summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--CHANGELOG.md10
-rw-r--r--CONTRIBUTING.md15
-rw-r--r--COPYRIGHT.txt5
-rw-r--r--SConstruct44
-rw-r--r--core/config/project_settings.cpp41
-rw-r--r--core/config/project_settings.h4
-rw-r--r--core/core_bind.cpp11
-rw-r--r--core/core_bind.h3
-rw-r--r--core/debugger/script_debugger.cpp4
-rw-r--r--core/debugger/script_debugger.h1
-rw-r--r--core/extension/extension_api_dump.cpp3
-rw-r--r--core/extension/gdextension_interface.cpp75
-rw-r--r--core/extension/gdextension_interface.h20
-rw-r--r--core/input/input_builders.py2
-rw-r--r--core/io/file_access.cpp12
-rw-r--r--core/io/file_access.h4
-rw-r--r--core/io/image_loader.cpp4
-rw-r--r--core/io/image_loader.h2
-rw-r--r--core/io/resource.cpp7
-rw-r--r--core/io/resource.h2
-rw-r--r--core/io/resource_format_binary.cpp4
-rw-r--r--core/io/resource_format_binary.h1
-rw-r--r--core/io/resource_loader.cpp7
-rw-r--r--core/io/resource_loader.h1
-rw-r--r--core/io/resource_saver.cpp7
-rw-r--r--core/io/resource_saver.h1
-rw-r--r--core/io/xml_parser.cpp10
-rw-r--r--core/io/xml_parser.h4
-rw-r--r--core/math/basis.cpp25
-rw-r--r--core/math/basis.h4
-rw-r--r--core/math/face3.cpp40
-rw-r--r--core/math/face3.h5
-rw-r--r--core/math/geometry_2d.cpp35
-rw-r--r--core/math/geometry_2d.h1
-rw-r--r--core/math/geometry_3d.cpp145
-rw-r--r--core/math/geometry_3d.h2
-rw-r--r--core/math/plane.h2
-rw-r--r--core/math/transform_2d.cpp6
-rw-r--r--core/math/transform_2d.h1
-rw-r--r--core/math/triangle_mesh.cpp196
-rw-r--r--core/math/triangle_mesh.h2
-rw-r--r--core/object/script_language.cpp51
-rw-r--r--core/object/script_language.h1
-rw-r--r--core/os/keyboard.cpp3
-rw-r--r--core/os/keyboard.h5
-rw-r--r--core/os/os.h3
-rw-r--r--core/variant/variant.h1
-rw-r--r--core/variant/variant_call.cpp2
-rw-r--r--core/variant/variant_setget.cpp21
-rw-r--r--doc/classes/@GlobalScope.xml4
-rw-r--r--doc/classes/AnimatedSprite2D.xml1
-rw-r--r--doc/classes/AnimationNode.xml7
-rw-r--r--doc/classes/AnimationNodeOneShot.xml6
-rw-r--r--doc/classes/AnimationNodeStateMachinePlayback.xml11
-rw-r--r--doc/classes/AnimationNodeStateMachineTransition.xml3
-rw-r--r--doc/classes/AnimationNodeTransition.xml8
-rw-r--r--doc/classes/AnimationPlayer.xml6
-rw-r--r--doc/classes/Array.xml2
-rw-r--r--doc/classes/ArrayMesh.xml14
-rw-r--r--doc/classes/BackBufferCopy.xml4
-rw-r--r--doc/classes/BaseButton.xml2
-rw-r--r--doc/classes/BoneAttachment3D.xml31
-rw-r--r--doc/classes/Callable.xml2
-rw-r--r--doc/classes/CanvasGroup.xml4
-rw-r--r--doc/classes/CanvasItem.xml33
-rw-r--r--doc/classes/CodeEdit.xml8
-rw-r--r--doc/classes/CollisionObject3D.xml6
-rw-r--r--doc/classes/Control.xml8
-rw-r--r--doc/classes/ConvexPolygonShape3D.xml2
-rw-r--r--doc/classes/DTLSServer.xml4
-rw-r--r--doc/classes/DisplayServer.xml5
-rw-r--r--doc/classes/EditorFileSystem.xml11
-rw-r--r--doc/classes/EditorPlugin.xml21
-rw-r--r--doc/classes/EditorResourceConversionPlugin.xml23
-rw-r--r--doc/classes/EditorSettings.xml6
-rw-r--r--doc/classes/EditorUndoRedoManager.xml2
-rw-r--r--doc/classes/GeometryInstance3D.xml5
-rw-r--r--doc/classes/Image.xml4
-rw-r--r--doc/classes/ImporterMesh.xml10
-rw-r--r--doc/classes/Input.xml1
-rw-r--r--doc/classes/JavaScriptBridge.xml2
-rw-r--r--doc/classes/Mesh.xml7
-rw-r--r--doc/classes/OS.xml12
-rw-r--r--doc/classes/Object.xml1
-rw-r--r--doc/classes/PhysicsServer3DManager.xml2
-rw-r--r--doc/classes/Plane.xml17
-rw-r--r--doc/classes/ProjectSettings.xml10
-rw-r--r--doc/classes/RenderingServer.xml9
-rw-r--r--doc/classes/ResourcePreloader.xml4
-rw-r--r--doc/classes/RichTextLabel.xml1
-rw-r--r--doc/classes/ShaderMaterial.xml3
-rw-r--r--doc/classes/Skeleton2D.xml2
-rw-r--r--doc/classes/Skeleton3D.xml96
-rw-r--r--doc/classes/SkeletonModification2D.xml2
-rw-r--r--doc/classes/SkeletonModification3D.xml66
-rw-r--r--doc/classes/SkeletonModification3DCCDIK.xml136
-rw-r--r--doc/classes/SkeletonModification3DFABRIK.xml161
-rw-r--r--doc/classes/SkeletonModification3DJiggle.xml199
-rw-r--r--doc/classes/SkeletonModification3DLookAt.xml64
-rw-r--r--doc/classes/SkeletonModification3DStackHolder.xml27
-rw-r--r--doc/classes/SkeletonModification3DTwoBoneIK.xml191
-rw-r--r--doc/classes/SkeletonModificationStack3D.xml88
-rw-r--r--doc/classes/SkeletonProfile.xml11
-rw-r--r--doc/classes/SkeletonProfileHumanoid.xml1
-rw-r--r--doc/classes/SpriteFrames.xml21
-rw-r--r--doc/classes/TextServer.xml11
-rw-r--r--doc/classes/TextServerExtension.xml2
-rw-r--r--doc/classes/TileMap.xml14
-rw-r--r--doc/classes/Transform3D.xml1
-rw-r--r--doc/classes/Tree.xml4
-rw-r--r--doc/classes/TreeItem.xml42
-rw-r--r--doc/classes/Tween.xml10
-rw-r--r--doc/classes/UndoRedo.xml2
-rw-r--r--doc/classes/Variant.xml4
-rw-r--r--doc/classes/VisualInstance3D.xml2
-rw-r--r--doc/classes/VisualShaderNode.xml7
-rw-r--r--doc/classes/VisualShaderNodeTexture.xml10
-rw-r--r--doc/classes/VisualShaderNodeTextureParameter.xml18
-rw-r--r--doc/classes/Window.xml38
-rw-r--r--doc/classes/bool.xml2
-rw-r--r--doc/translations/ar.po6
-rw-r--r--doc/translations/ca.po6
-rw-r--r--doc/translations/classes.pot10
-rw-r--r--doc/translations/cs.po6
-rw-r--r--doc/translations/de.po6
-rw-r--r--doc/translations/el.po6
-rw-r--r--doc/translations/es.po17
-rw-r--r--doc/translations/et.po6
-rw-r--r--doc/translations/fa.po6
-rw-r--r--doc/translations/fi.po6
-rw-r--r--doc/translations/fil.po6
-rw-r--r--doc/translations/fr.po16
-rw-r--r--doc/translations/gl.po6
-rw-r--r--doc/translations/hi.po6
-rw-r--r--doc/translations/hu.po6
-rw-r--r--doc/translations/id.po6
-rw-r--r--doc/translations/is.po6
-rw-r--r--doc/translations/it.po6
-rw-r--r--doc/translations/ja.po6
-rw-r--r--doc/translations/ko.po15
-rw-r--r--doc/translations/lt.po6
-rw-r--r--doc/translations/lv.po6
-rw-r--r--doc/translations/mr.po6
-rw-r--r--doc/translations/nb.po6
-rw-r--r--doc/translations/ne.po6
-rw-r--r--doc/translations/nl.po6
-rw-r--r--doc/translations/pl.po6
-rw-r--r--doc/translations/pt.po91
-rw-r--r--doc/translations/pt_BR.po80
-rw-r--r--doc/translations/ro.po6
-rw-r--r--doc/translations/ru.po267
-rw-r--r--doc/translations/sk.po6
-rw-r--r--doc/translations/sr_Cyrl.po6
-rw-r--r--doc/translations/sv.po6
-rw-r--r--doc/translations/th.po6
-rw-r--r--doc/translations/tl.po6
-rw-r--r--doc/translations/tr.po6
-rw-r--r--doc/translations/uk.po111
-rw-r--r--doc/translations/vi.po6
-rw-r--r--doc/translations/zh_CN.po611
-rw-r--r--doc/translations/zh_TW.po59
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp12
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.h3
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp9
-rw-r--r--drivers/gles3/shaders/canvas.glsl8
-rw-r--r--drivers/gles3/shaders/canvas_uniforms_inc.glsl3
-rw-r--r--drivers/gles3/shaders/scene.glsl4
-rw-r--r--drivers/gles3/storage/material_storage.cpp22
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.cpp3
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h2
-rw-r--r--drivers/gles3/storage/texture_storage.cpp27
-rw-r--r--drivers/gles3/storage/texture_storage.h7
-rw-r--r--drivers/unix/dir_access_unix.cpp4
-rw-r--r--drivers/unix/os_unix.cpp19
-rw-r--r--drivers/unix/os_unix.h4
-rw-r--r--drivers/windows/file_access_windows.cpp45
-rw-r--r--drivers/windows/file_access_windows.h6
-rw-r--r--editor/action_map_editor.cpp6
-rw-r--r--editor/animation_bezier_editor.cpp16
-rw-r--r--editor/animation_track_editor.cpp72
-rw-r--r--editor/animation_track_editor_plugins.cpp5
-rw-r--r--editor/array_property_edit.cpp301
-rw-r--r--editor/code_editor.cpp4
-rw-r--r--editor/connections_dialog.cpp7
-rw-r--r--editor/create_dialog.cpp8
-rw-r--r--editor/debugger/debug_adapter/debug_adapter_parser.cpp2
-rw-r--r--editor/debugger/editor_debugger_node.cpp2
-rw-r--r--editor/dictionary_property_edit.cpp177
-rw-r--r--editor/doc_tools.cpp63
-rw-r--r--editor/editor_audio_buses.cpp44
-rw-r--r--editor/editor_autoload_settings.cpp18
-rw-r--r--editor/editor_data.cpp69
-rw-r--r--editor/editor_data.h6
-rw-r--r--editor/editor_file_system.cpp141
-rw-r--r--editor/editor_file_system.h10
-rw-r--r--editor/editor_help.cpp2
-rw-r--r--editor/editor_inspector.cpp57
-rw-r--r--editor/editor_locale_dialog.cpp9
-rw-r--r--editor/editor_node.cpp84
-rw-r--r--editor/editor_node.h5
-rw-r--r--editor/editor_plugin.cpp18
-rw-r--r--editor/editor_plugin.h9
-rw-r--r--editor/editor_properties.cpp19
-rw-r--r--editor/editor_properties_array_dict.cpp4
-rw-r--r--editor/editor_resource_picker.cpp5
-rw-r--r--editor/editor_run_native.cpp103
-rw-r--r--editor/editor_run_native.h7
-rw-r--r--editor/editor_settings_dialog.cpp14
-rw-r--r--editor/editor_toaster.cpp49
-rw-r--r--editor/editor_toaster.h2
-rw-r--r--editor/editor_undo_redo_manager.cpp12
-rw-r--r--editor/editor_undo_redo_manager.h11
-rw-r--r--editor/export/editor_export.cpp4
-rw-r--r--editor/export/editor_export_platform.cpp1
-rw-r--r--editor/export/editor_export_preset.cpp9
-rw-r--r--editor/export/editor_export_preset.h9
-rw-r--r--editor/export/project_export.cpp30
-rw-r--r--editor/export/project_export.h2
-rw-r--r--editor/fbx_importer_manager.cpp8
-rw-r--r--editor/filesystem_dock.cpp28
-rw-r--r--editor/groups_editor.cpp14
-rw-r--r--editor/history_dock.cpp2
-rw-r--r--editor/history_dock.h2
-rw-r--r--editor/icons/PlayRemote.svg1
-rw-r--r--editor/icons/README.md2
-rw-r--r--editor/import/collada.cpp164
-rw-r--r--editor/import/resource_importer_obj.cpp27
-rw-r--r--editor/import/resource_importer_shader_file.cpp1
-rw-r--r--editor/import/scene_import_settings.cpp26
-rw-r--r--editor/inspector_dock.cpp4
-rw-r--r--editor/localization_editor.cpp19
-rw-r--r--editor/multi_node_edit.cpp2
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp10
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp14
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp19
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp24
-rw-r--r--editor/plugins/animation_library_editor.cpp28
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp54
-rw-r--r--editor/plugins/animation_player_editor_plugin.h2
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp22
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp29
-rw-r--r--editor/plugins/asset_library_editor_plugin.h1
-rw-r--r--editor/plugins/audio_stream_randomizer_editor_plugin.cpp4
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp22
-rw-r--r--editor/plugins/cast_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/collision_shape_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/control_editor_plugin.cpp6
-rw-r--r--editor/plugins/curve_editor_plugin.cpp14
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/gpu_particles_3d_editor_plugin.cpp4
-rw-r--r--editor/plugins/gradient_editor.cpp2
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/light_occluder_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/line_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/material_editor_plugin.cpp4
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/navigation_link_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/navigation_polygon_editor_plugin.cpp8
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp44
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp22
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp10
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp12
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp8
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp16
-rw-r--r--editor/plugins/script_editor_plugin.cpp32
-rw-r--r--editor/plugins/script_editor_plugin.h3
-rw-r--r--editor/plugins/script_text_editor.cpp10
-rw-r--r--editor/plugins/script_text_editor.h1
-rw-r--r--editor/plugins/shader_editor_plugin.cpp10
-rw-r--r--editor/plugins/shader_editor_plugin.h3
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp18
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp8
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp39
-rw-r--r--editor/plugins/text_editor.cpp2
-rw-r--r--editor/plugins/texture_region_editor_plugin.cpp4
-rw-r--r--editor/plugins/theme_editor_plugin.cpp48
-rw-r--r--editor/plugins/tiles/atlas_merging_dialog.cpp5
-rw-r--r--editor/plugins/tiles/tile_atlas_view.cpp30
-rw-r--r--editor/plugins/tiles/tile_atlas_view.h2
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp120
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp51
-rw-r--r--editor/plugins/tiles/tile_proxies_manager_dialog.cpp13
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp168
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.h2
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp56
-rw-r--r--editor/plugins/tiles/tile_set_editor.h1
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp10
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp142
-rw-r--r--editor/plugins/visual_shader_editor_plugin.h3
-rw-r--r--editor/project_converter_3_to_4.cpp282
-rw-r--r--editor/project_settings_editor.cpp16
-rw-r--r--editor/rename_dialog.cpp2
-rw-r--r--editor/scene_tree_dock.cpp44
-rw-r--r--editor/scene_tree_editor.cpp12
-rw-r--r--editor/shader_globals_editor.cpp6
-rw-r--r--editor/translations/af.po2
-rw-r--r--editor/translations/ar.po14
-rw-r--r--editor/translations/az.po2
-rw-r--r--editor/translations/bg.po2
-rw-r--r--editor/translations/bn.po17
-rw-r--r--editor/translations/br.po2
-rw-r--r--editor/translations/ca.po2
-rw-r--r--editor/translations/cs.po524
-rw-r--r--editor/translations/da.po2
-rw-r--r--editor/translations/de.po29
-rw-r--r--editor/translations/editor.pot6
-rw-r--r--editor/translations/el.po356
-rw-r--r--editor/translations/en_Shaw.po2
-rw-r--r--editor/translations/eo.po2
-rw-r--r--editor/translations/es.po65
-rw-r--r--editor/translations/es_AR.po22
-rw-r--r--editor/translations/et.po15
-rw-r--r--editor/translations/eu.po2
-rw-r--r--editor/translations/fa.po63
-rw-r--r--editor/translations/fi.po2
-rw-r--r--editor/translations/fil.po2
-rw-r--r--editor/translations/fr.po605
-rw-r--r--editor/translations/ga.po2
-rw-r--r--editor/translations/gl.po2
-rw-r--r--editor/translations/he.po249
-rw-r--r--editor/translations/hi.po2
-rw-r--r--editor/translations/hr.po11
-rw-r--r--editor/translations/hu.po2
-rw-r--r--editor/translations/id.po12
-rw-r--r--editor/translations/ig.po2
-rw-r--r--editor/translations/is.po2
-rw-r--r--editor/translations/it.po12
-rw-r--r--editor/translations/ja.po453
-rw-r--r--editor/translations/ka.po2
-rw-r--r--editor/translations/km.po2
-rw-r--r--editor/translations/ko.po64
-rw-r--r--editor/translations/lt.po2
-rw-r--r--editor/translations/lv.po2
-rw-r--r--editor/translations/mk.po2
-rw-r--r--editor/translations/ml.po2
-rw-r--r--editor/translations/mr.po2
-rw-r--r--editor/translations/ms.po2
-rw-r--r--editor/translations/nb.po112
-rw-r--r--editor/translations/nl.po2
-rw-r--r--editor/translations/pl.po1014
-rw-r--r--editor/translations/pr.po2
-rw-r--r--editor/translations/pt.po70
-rw-r--r--editor/translations/pt_BR.po97
-rw-r--r--editor/translations/ro.po435
-rw-r--r--editor/translations/ru.po2
-rw-r--r--editor/translations/si.po2
-rw-r--r--editor/translations/sk.po11
-rw-r--r--editor/translations/sl.po2
-rw-r--r--editor/translations/sq.po2
-rw-r--r--editor/translations/sr_Cyrl.po2
-rw-r--r--editor/translations/sr_Latn.po2
-rw-r--r--editor/translations/sv.po54
-rw-r--r--editor/translations/te.po2
-rw-r--r--editor/translations/th.po2
-rw-r--r--editor/translations/tl.po2
-rw-r--r--editor/translations/tr.po2
-rw-r--r--editor/translations/uk.po135
-rw-r--r--editor/translations/ur_PK.po2
-rw-r--r--editor/translations/vi.po2
-rw-r--r--editor/translations/zh_CN.po49
-rw-r--r--editor/translations/zh_HK.po2
-rw-r--r--editor/translations/zh_TW.po110
-rw-r--r--main/main.cpp26
-rw-r--r--main/performance.cpp1
-rw-r--r--misc/hooks/asmessage.applescript59
-rwxr-xr-xmisc/hooks/pre-commit-black19
-rwxr-xr-xmisc/hooks/pre-commit-clang-format19
-rw-r--r--modules/astcenc/SCsub55
-rw-r--r--modules/astcenc/config.py6
-rw-r--r--modules/astcenc/image_compress_astcenc.cpp251
-rw-r--r--modules/astcenc/image_compress_astcenc.h (renamed from editor/array_property_edit.h)44
-rw-r--r--modules/astcenc/register_types.cpp (renamed from editor/dictionary_property_edit.h)46
-rw-r--r--modules/astcenc/register_types.h (renamed from scene/resources/skeleton_modification_3d_stackholder.h)34
-rw-r--r--modules/bmp/image_loader_bmp.cpp20
-rw-r--r--modules/csg/editor/csg_gizmos.cpp8
-rw-r--r--modules/etcpak/image_compress_etcpak.cpp12
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml2
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml6
-rw-r--r--modules/gdscript/gdscript.cpp19
-rw-r--r--modules/gdscript/gdscript.h3
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp61
-rw-r--r--modules/gdscript/gdscript_compiler.cpp2
-rw-r--r--modules/gdscript/gdscript_editor.cpp10
-rw-r--r--modules/gdscript/gdscript_parser.cpp54
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp1
-rw-r--r--modules/gdscript/register_types.cpp5
-rw-r--r--modules/gdscript/tests/README.md2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd14
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd6
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out1
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/class_name.gd2
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd51
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out14
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml8
-rw-r--r--modules/gltf/gltf_document.cpp3
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp10
-rw-r--r--modules/mono/csharp_script.cpp5
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs2
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs6
-rw-r--r--modules/mono/editor/bindings_generator.cpp38
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs59
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs217
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs18
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs16
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs58
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs6
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs72
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs10
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs37
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs110
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs107
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs54
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs148
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs39
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs101
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs22
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs32
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp10
-rw-r--r--modules/multiplayer/multiplayer_spawner.cpp8
-rw-r--r--modules/multiplayer/multiplayer_spawner.h2
-rw-r--r--modules/multiplayer/scene_replication_interface.cpp48
-rw-r--r--modules/multiplayer/scene_replication_interface.h7
-rw-r--r--modules/ogg/ogg_packet_sequence.cpp2
-rw-r--r--modules/openxr/editor/openxr_action_editor.cpp3
-rw-r--r--modules/openxr/editor/openxr_action_editor.h2
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.cpp2
-rw-r--r--modules/openxr/editor/openxr_action_map_editor.h2
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.cpp3
-rw-r--r--modules/openxr/editor/openxr_action_set_editor.h2
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.cpp3
-rw-r--r--modules/openxr/editor/openxr_interaction_profile_editor.h2
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.cpp2
-rw-r--r--modules/openxr/openxr_api.cpp10
-rw-r--r--modules/openxr/openxr_api.h1
-rw-r--r--modules/openxr/register_types.cpp4
-rw-r--r--modules/raycast/SCsub2
-rw-r--r--modules/text_server_adv/text_server_adv.cpp80
-rw-r--r--modules/text_server_adv/text_server_adv.h5
-rw-r--r--modules/text_server_adv/thorvg_svg_in_ot.cpp33
-rw-r--r--modules/text_server_fb/text_server_fb.cpp57
-rw-r--r--modules/text_server_fb/text_server_fb.h4
-rw-r--r--modules/text_server_fb/thorvg_svg_in_ot.cpp33
-rw-r--r--modules/webxr/doc_classes/WebXRInterface.xml4
-rw-r--r--platform/android/README.md2
-rw-r--r--platform/android/display_server_android.cpp13
-rw-r--r--platform/android/export/export_plugin.cpp35
-rw-r--r--platform/android/export/export_plugin.h3
-rw-r--r--platform/android/os_android.cpp16
-rw-r--r--platform/ios/README.md2
-rw-r--r--platform/ios/display_server_ios.mm25
-rw-r--r--platform/ios/export/export_plugin.cpp6
-rw-r--r--platform/linuxbsd/README.md2
-rw-r--r--platform/linuxbsd/crash_handler_linuxbsd.cpp40
-rw-r--r--platform/linuxbsd/detect.py15
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp70
-rw-r--r--platform/linuxbsd/x11/display_server_x11.h4
-rw-r--r--platform/macos/README.md2
-rw-r--r--platform/macos/detect.py1
-rw-r--r--platform/macos/display_server_macos.h1
-rw-r--r--platform/macos/display_server_macos.mm34
-rw-r--r--platform/macos/gl_manager_macos_legacy.h5
-rw-r--r--platform/macos/gl_manager_macos_legacy.mm5
-rw-r--r--platform/macos/godot_content_view.h5
-rw-r--r--platform/macos/godot_menu_delegate.mm2
-rw-r--r--platform/macos/joypad_macos.cpp2
-rw-r--r--platform/uwp/README.md2
-rw-r--r--platform/web/README.md2
-rw-r--r--platform/web/api/web_tools_editor_plugin.cpp2
-rw-r--r--platform/web/api/web_tools_editor_plugin.h2
-rw-r--r--platform/web/display_server_web.cpp6
-rw-r--r--platform/web/os_web.cpp18
-rw-r--r--platform/windows/README.md2
-rw-r--r--platform/windows/display_server_windows.cpp57
-rw-r--r--platform/windows/display_server_windows.h1
-rw-r--r--platform/windows/os_windows.cpp17
-rw-r--r--platform/windows/os_windows.h3
-rw-r--r--scene/2d/area_2d.cpp5
-rw-r--r--scene/2d/collision_object_2d.cpp20
-rw-r--r--scene/2d/collision_object_2d.h7
-rw-r--r--scene/2d/path_2d.cpp25
-rw-r--r--scene/2d/path_2d.h5
-rw-r--r--scene/2d/physics_body_2d.cpp4
-rw-r--r--scene/2d/tile_map.cpp65
-rw-r--r--scene/2d/tile_map.h5
-rw-r--r--scene/3d/area_3d.cpp4
-rw-r--r--scene/3d/bone_attachment_3d.cpp52
-rw-r--r--scene/3d/bone_attachment_3d.h8
-rw-r--r--scene/3d/collision_object_3d.cpp20
-rw-r--r--scene/3d/collision_object_3d.h7
-rw-r--r--scene/3d/decal.cpp4
-rw-r--r--scene/3d/label_3d.cpp2
-rw-r--r--scene/3d/label_3d.h2
-rw-r--r--scene/3d/lightmap_gi.cpp10
-rw-r--r--scene/3d/physics_body_3d.cpp4
-rw-r--r--scene/3d/skeleton_3d.cpp263
-rw-r--r--scene/3d/skeleton_3d.h55
-rw-r--r--scene/3d/skeleton_ik_3d.cpp23
-rw-r--r--scene/3d/visual_instance_3d.cpp12
-rw-r--r--scene/3d/visual_instance_3d.h2
-rw-r--r--scene/animation/animation_blend_tree.cpp164
-rw-r--r--scene/animation/animation_blend_tree.h42
-rw-r--r--scene/animation/animation_node_state_machine.cpp134
-rw-r--r--scene/animation/animation_node_state_machine.h16
-rw-r--r--scene/animation/animation_player.cpp22
-rw-r--r--scene/animation/animation_player.h4
-rw-r--r--scene/animation/animation_tree.cpp23
-rw-r--r--scene/animation/animation_tree.h4
-rw-r--r--scene/animation/tween.cpp20
-rw-r--r--scene/animation/tween.h2
-rw-r--r--scene/gui/base_button.cpp76
-rw-r--r--scene/gui/base_button.h13
-rw-r--r--scene/gui/code_edit.cpp55
-rw-r--r--scene/gui/code_edit.h1
-rw-r--r--scene/gui/color_picker.cpp6
-rw-r--r--scene/gui/control.cpp25
-rw-r--r--scene/gui/control.h14
-rw-r--r--scene/gui/graph_edit.cpp1
-rw-r--r--scene/gui/item_list.cpp6
-rw-r--r--scene/gui/item_list.h1
-rw-r--r--scene/gui/label.cpp9
-rw-r--r--scene/gui/label.h2
-rw-r--r--scene/gui/rich_text_label.cpp4
-rw-r--r--scene/gui/tab_container.cpp5
-rw-r--r--scene/gui/text_edit.cpp10
-rw-r--r--scene/gui/texture_rect.cpp10
-rw-r--r--scene/gui/texture_rect.h3
-rw-r--r--scene/gui/tree.cpp100
-rw-r--r--scene/gui/tree.h22
-rw-r--r--scene/main/canvas_item.cpp66
-rw-r--r--scene/main/canvas_item.h18
-rw-r--r--scene/main/node.cpp10
-rw-r--r--scene/main/scene_tree.cpp1
-rw-r--r--scene/main/viewport.cpp42
-rw-r--r--scene/main/viewport.h3
-rw-r--r--scene/main/window.cpp20
-rw-r--r--scene/main/window.h5
-rw-r--r--scene/register_scene_types.cpp17
-rw-r--r--scene/resources/convex_polygon_shape_2d.cpp2
-rw-r--r--scene/resources/environment.cpp12
-rw-r--r--scene/resources/immediate_mesh.cpp17
-rw-r--r--scene/resources/material.cpp12
-rw-r--r--scene/resources/mesh.cpp5
-rw-r--r--scene/resources/primitive_meshes.cpp2
-rw-r--r--scene/resources/primitive_meshes.h2
-rw-r--r--scene/resources/resource_format_text.cpp7
-rw-r--r--scene/resources/resource_format_text.h1
-rw-r--r--scene/resources/skeleton_modification_3d.cpp151
-rw-r--r--scene/resources/skeleton_modification_3d.h79
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.cpp474
-rw-r--r--scene/resources/skeleton_modification_3d_ccdik.h114
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.cpp628
-rw-r--r--scene/resources/skeleton_modification_3d_fabrik.h124
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.cpp582
-rw-r--r--scene/resources/skeleton_modification_3d_jiggle.h138
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.cpp267
-rw-r--r--scene/resources/skeleton_modification_3d_lookat.h89
-rw-r--r--scene/resources/skeleton_modification_3d_stackholder.cpp104
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.cpp617
-rw-r--r--scene/resources/skeleton_modification_3d_twoboneik.h118
-rw-r--r--scene/resources/skeleton_modification_stack_3d.cpp224
-rw-r--r--scene/resources/skeleton_modification_stack_3d.h91
-rw-r--r--scene/resources/tile_set.cpp1
-rw-r--r--scene/resources/visual_shader.cpp5
-rw-r--r--scene/resources/visual_shader_nodes.cpp473
-rw-r--r--scene/resources/visual_shader_nodes.h17
-rw-r--r--servers/display_server.cpp1
-rw-r--r--servers/display_server.h2
-rw-r--r--servers/physics_3d/gjk_epa.cpp6
-rw-r--r--servers/physics_3d/godot_body_pair_3d.cpp14
-rw-r--r--servers/physics_3d/godot_body_pair_3d.h8
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.cpp18
-rw-r--r--servers/physics_3d/godot_collision_solver_3d.h4
-rw-r--r--servers/physics_3d/godot_collision_solver_3d_sat.cpp59
-rw-r--r--servers/physics_3d/godot_physics_server_3d.cpp2
-rw-r--r--servers/physics_3d/godot_physics_server_3d.h2
-rw-r--r--servers/physics_3d/godot_space_3d.cpp6
-rw-r--r--servers/rendering/dummy/storage/texture_storage.h1
-rw-r--r--servers/rendering/renderer_canvas_cull.cpp296
-rw-r--r--servers/rendering/renderer_canvas_cull.h8
-rw-r--r--servers/rendering/renderer_rd/environment/sky.cpp2
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp2
-rw-r--r--servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp18
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp18
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp15
-rw-r--r--servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h1
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp17
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.h3
-rw-r--r--servers/rendering/renderer_rd/renderer_scene_render_rd.cpp7
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl5
-rw-r--r--servers/rendering/renderer_rd/storage_rd/light_storage.cpp9
-rw-r--r--servers/rendering/renderer_rd/storage_rd/material_storage.cpp8
-rw-r--r--servers/rendering/renderer_rd/storage_rd/particles_storage.cpp13
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp10
-rw-r--r--servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h4
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.cpp26
-rw-r--r--servers/rendering/renderer_rd/storage_rd/texture_storage.h4
-rw-r--r--servers/rendering/renderer_scene_cull.cpp12
-rw-r--r--servers/rendering/renderer_scene_render.cpp2
-rw-r--r--servers/rendering/renderer_viewport.cpp69
-rw-r--r--servers/rendering/rendering_device_binds.cpp2
-rw-r--r--servers/rendering/rendering_server_default.h2
-rw-r--r--servers/rendering/shader_compiler.cpp41
-rw-r--r--servers/rendering/shader_compiler.h3
-rw-r--r--servers/rendering/shader_language.cpp9
-rw-r--r--servers/rendering/shader_preprocessor.cpp14
-rw-r--r--servers/rendering/shader_preprocessor.h3
-rw-r--r--servers/rendering/shader_types.cpp4
-rw-r--r--servers/rendering/storage/render_scene_buffers.cpp4
-rw-r--r--servers/rendering/storage/render_scene_buffers.h4
-rw-r--r--servers/rendering/storage/texture_storage.h1
-rw-r--r--servers/rendering_server.cpp14
-rw-r--r--servers/rendering_server.h11
-rw-r--r--servers/text/text_server_extension.cpp4
-rw-r--r--servers/text/text_server_extension.h4
-rw-r--r--servers/text_server.cpp116
-rw-r--r--servers/text_server.h7
-rw-r--r--tests/core/io/test_xml_parser.h2
-rw-r--r--tests/core/math/test_plane.h4
-rw-r--r--tests/scene/test_arraymesh.h21
-rw-r--r--tests/scene/test_code_edit.h50
-rw-r--r--tests/scene/test_curve_2d.h228
-rw-r--r--tests/scene/test_node.h106
-rw-r--r--tests/scene/test_primitives.h2
-rw-r--r--tests/test_main.cpp1
-rw-r--r--thirdparty/README.md12
-rw-r--r--thirdparty/astcenc/LICENSE.txt175
-rw-r--r--thirdparty/astcenc/astcenc.h815
-rw-r--r--thirdparty/astcenc/astcenc_averages_and_directions.cpp995
-rw-r--r--thirdparty/astcenc/astcenc_block_sizes.cpp1184
-rw-r--r--thirdparty/astcenc/astcenc_color_quantize.cpp2071
-rw-r--r--thirdparty/astcenc/astcenc_color_unquantize.cpp941
-rw-r--r--thirdparty/astcenc/astcenc_compress_symbolic.cpp1455
-rw-r--r--thirdparty/astcenc/astcenc_compute_variance.cpp472
-rw-r--r--thirdparty/astcenc/astcenc_decompress_symbolic.cpp623
-rw-r--r--thirdparty/astcenc/astcenc_diagnostic_trace.cpp230
-rw-r--r--thirdparty/astcenc/astcenc_diagnostic_trace.h219
-rw-r--r--thirdparty/astcenc/astcenc_entry.cpp1427
-rw-r--r--thirdparty/astcenc/astcenc_find_best_partitioning.cpp780
-rw-r--r--thirdparty/astcenc/astcenc_ideal_endpoints_and_weights.cpp1663
-rw-r--r--thirdparty/astcenc/astcenc_image.cpp558
-rw-r--r--thirdparty/astcenc/astcenc_integer_sequence.cpp739
-rw-r--r--thirdparty/astcenc/astcenc_internal.h2196
-rw-r--r--thirdparty/astcenc/astcenc_internal_entry.h273
-rw-r--r--thirdparty/astcenc/astcenc_mathlib.cpp48
-rw-r--r--thirdparty/astcenc/astcenc_mathlib.h476
-rw-r--r--thirdparty/astcenc/astcenc_mathlib_softfloat.cpp411
-rw-r--r--thirdparty/astcenc/astcenc_partition_tables.cpp481
-rw-r--r--thirdparty/astcenc/astcenc_percentile_tables.cpp1251
-rw-r--r--thirdparty/astcenc/astcenc_pick_best_endpoint_format.cpp1350
-rw-r--r--thirdparty/astcenc/astcenc_platform_isa_detection.cpp166
-rw-r--r--thirdparty/astcenc/astcenc_quantization.cpp904
-rw-r--r--thirdparty/astcenc/astcenc_symbolic_physical.cpp534
-rw-r--r--thirdparty/astcenc/astcenc_vecmathlib.h570
-rw-r--r--thirdparty/astcenc/astcenc_vecmathlib_avx2_8.h1204
-rw-r--r--thirdparty/astcenc/astcenc_vecmathlib_common_4.h423
-rw-r--r--thirdparty/astcenc/astcenc_vecmathlib_neon_4.h1072
-rw-r--r--thirdparty/astcenc/astcenc_vecmathlib_none_4.h1169
-rw-r--r--thirdparty/astcenc/astcenc_vecmathlib_sse_4.h1283
-rw-r--r--thirdparty/astcenc/astcenc_weight_align.cpp479
-rw-r--r--thirdparty/astcenc/astcenc_weight_quant_xfer_tables.cpp147
-rw-r--r--thirdparty/astcenc/patches/fix-build-no-ssse3.patch81
687 files changed, 37703 insertions, 13331 deletions
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f59c0e645d..820a85c3fc 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -37,11 +37,8 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- [New and improved IK in Skeleton2D](https://github.com/godotengine/godot/pull/40347).
- New classes: SkeletonModifier2D, SkeletonModifierStack2D, SkeletonModification2DLookAt, SkeletonModification2DCCDIK, SkeletonModification2DFABRIK, SkeletonModification2DJiggle, SkeletonModification2DTwoBoneIK, PhysicalBone2D, SkeletonModification2DPhysicalBones, SkeletonModification2DStackHolder.
- New `Transform2D.looking_at()` function.
-- [New and improved IK in Skeleton3D](https://github.com/godotengine/godot/pull/39353).
- - New classes: SkeletonModifier3D, SkeletonModifierStack3D, SkeletonModifier3DLookAt, SkeletonModification3DCCDIK, SkeletonModification3DFABRIK, SkeletonModification3DJiggle, SkeletonModification3DTwoBoneIK, SkeletonModification3DStackHolder.
- - The Bone struct now includes a local_pose_override.
+- [Improvements to Skeleton3D](https://github.com/godotengine/godot/pull/39353).
- The Bone struct now keeps track of its children bones, if it has any.
- - Added functions to Skeleton3D for getting the forward vector using the information stored in the rest pose for the bones.
- New `Basis.rotate_to_align()` function.
- Refactored the BoneAttachment3D node.
- Removed the `process_list` functions.
@@ -230,6 +227,7 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- More information in the [progress report](https://godotengine.org/article/improvements-shaders-visual-shaders-godot-4).
- [Add Billboard mode to visual shaders.](https://github.com/godotengine/godot/pull/49157)
- [The constants `PI`, `TAU` and `E` are now available in the shader language.](https://github.com/godotengine/godot/pull/48837)
+- Uniform hints to control textures (`repeat_enabled`, `repeat_disabled`, `filter_linear`, `filter_nearest`, `hint_screen_texture`, etc.).
#### Miscellaneous
@@ -404,6 +402,10 @@ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/).
- [Removed support for 16× MSAA due to driver bugs and low performance.](https://github.com/godotengine/godot/pull/49063)
- For high-quality offline rendering, using supersampling together with 8× MSAA is a better option anyway.
+#### Shaders
+
+- Removed `SCREEN_TEXTURE` and `DEPTH_TEXTURE` in favour of uniform hints `hint_screen_texture` and `hint_depth_texture`.
+
### Fixed
#### Core
diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index 21d6e110ce..aea1c8c5ff 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -122,11 +122,12 @@ recommend that you have a look at it to know what's important to take into
account for a PR to be considered for merging.
In addition to the following tips, also take a look at the
-[Engine development guide](https://docs.godotengine.org/en/latest/development/cpp/)
+[Engine development guide](https://docs.godotengine.org/en/latest/contributing/development/index.html)
for an introduction to developing on Godot.
-The [Contributing docs](https://docs.godotengine.org/en/latest/community/contributing/index.html)
-also have important information on the PR workflow and the code style we use.
+The [Contributing docs](https://docs.godotengine.org/en/latest/contributing/ways_to_contribute.html)
+also have important information on the [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
+and the [code style](https://docs.godotengine.org/en/latest/contributing/development/code_style_guidelines.html) we use.
### Document your changes
@@ -135,10 +136,10 @@ scripting APIs, you **must** update the class reference to document those.
This is to ensure the documentation coverage doesn't decrease as contributions
are merged.
-[Update the documentation template](https://docs.godotengine.org/en/latest/community/contributing/updating_the_class_reference.html#updating-the-documentation-template)
+[Update documentation XML files](https://docs.godotengine.org/en/latest/contributing/documentation/updating_the_class_reference.html#updating-class-reference-when-working-on-the-engine)
using your compiled binary, then fill in the descriptions.
Follow the style guide described in the
-[Docs writing guidelines](https://docs.godotengine.org/en/latest/community/contributing/docs_writing_guidelines.html).
+[Writing guidelines](https://docs.godotengine.org/en/latest/contributing/documentation/docs_writing_guidelines.html).
If your pull request modifies parts of the code in a non-obvious way, make sure
to add comments in the code as well. This helps other people understand the
@@ -164,7 +165,7 @@ applicable.
Feel free to contribute standalone pull requests to add new tests or improve
existing tests as well.
-See [Unit testing](https://docs.godotengine.org/en/latest/development/cpp/unit_testing.html)
+See [Unit testing](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html)
for information on writing tests in Godot's C++ codebase.
### Be nice to the Git history
@@ -186,7 +187,7 @@ Internet).
This [Git style guide](https://github.com/agis-/git-style-guide) has some
good practices to have in mind.
-See our [PR workflow](https://docs.godotengine.org/en/latest/community/contributing/pr_workflow.html)
+See our [PR workflow](https://docs.godotengine.org/en/latest/contributing/workflow/pr_workflow.html)
documentation for tips on using Git, amending commits and rebasing branches.
### Format your commit messages with readability in mind
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 7fe45657bc..8a966dcb05 100644
--- a/COPYRIGHT.txt
+++ b/COPYRIGHT.txt
@@ -141,6 +141,11 @@ Comment: AMD FidelityFX Super Resolution
Copyright: 2021, Advanced Micro Devices, Inc.
License: Expat
+Files: ./thirdparty/astcenc/
+Comment: Arm ASTC Encoder
+Copyright: 2011-2023, Arm Limited
+License: Apache-2.0
+
Files: ./thirdparty/basis_universal/
Comment: Basis Universal
Copyright: 2022, Binomial LLC.
diff --git a/SConstruct b/SConstruct
index 1eb6c0adc8..1acbd83e63 100644
--- a/SConstruct
+++ b/SConstruct
@@ -202,7 +202,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("build_feature_profile", "Path to a file containing a feature build profile", "")
+opts.Add("build_profile", "Path to a file containing a feature build profile", "")
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", True))
opts.Add("system_certs_path", "Use this path as SSL certificates default for editor (for package maintainers)", "")
@@ -492,6 +492,25 @@ if selected_platform in platform_list:
env["LINKFLAGS"] = ""
env.Append(LINKFLAGS=str(LINKFLAGS).split())
+ # Feature build profile
+ disabled_classes = []
+ if env["build_profile"] != "":
+ print("Using feature build profile: " + env["build_profile"])
+ import json
+
+ try:
+ ft = json.load(open(env["build_profile"]))
+ if "disabled_classes" in ft:
+ disabled_classes = ft["disabled_classes"]
+ if "disabled_build_options" in ft:
+ dbo = ft["disabled_build_options"]
+ for c in dbo:
+ env[c] = dbo[c]
+ except:
+ print("Error opening feature build profile: " + env["build_profile"])
+ Exit(255)
+ methods.write_disabled_classes(disabled_classes)
+
# Platform specific flags.
# These can sometimes override default options.
flag_list = platform_flags[selected_platform]
@@ -540,6 +559,9 @@ if selected_platform in platform_list:
env.Append(CCFLAGS=["/Od"])
else:
if env["debug_symbols"]:
+ # Adding dwarf-4 explicitly makes stacktraces work with clang builds,
+ # otherwise addr2line doesn't understand them
+ env.Append(CCFLAGS=["-gdwarf-4"])
if env.dev_build:
env.Append(CCFLAGS=["-g3"])
else:
@@ -815,26 +837,6 @@ if selected_platform in platform_list:
env["LIBSUFFIX"] = suffix + env["LIBSUFFIX"]
env["SHLIBSUFFIX"] = suffix + env["SHLIBSUFFIX"]
- disabled_classes = []
-
- if env["build_feature_profile"] != "":
- print("Using build feature profile: " + env["build_feature_profile"])
- import json
-
- try:
- ft = json.load(open(env["build_feature_profile"]))
- if "disabled_classes" in ft:
- disabled_classes = ft["disabled_classes"]
- if "disabled_build_options" in ft:
- dbo = ft["disabled_build_options"]
- for c in dbo:
- env[c] = dbo[c]
- except:
- print("Error opening feature build profile: " + env["build_feature_profile"])
- Exit(255)
-
- methods.write_disabled_classes(disabled_classes)
-
if env["disable_3d"]:
if env.editor_build:
print("Build option 'disable_3d=yes' cannot be used for editor builds, but only for export templates.")
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 73d7d7420f..ed89bc15d3 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -33,6 +33,7 @@
#include "core/core_bind.h" // For Compression enum.
#include "core/core_string_names.h"
#include "core/input/input_map.h"
+#include "core/io/config_file.h"
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
#include "core/io/file_access_network.h"
@@ -1068,23 +1069,6 @@ Variant _GLOBAL_DEF(const PropertyInfo &p_info, const Variant &p_default, bool p
return ret;
}
-Vector<String> ProjectSettings::get_optimizer_presets() const {
- List<PropertyInfo> pi;
- ProjectSettings::get_singleton()->get_property_list(&pi);
- Vector<String> names;
-
- for (const PropertyInfo &E : pi) {
- if (!E.name.begins_with("optimizer_presets/")) {
- continue;
- }
- names.push_back(E.name.get_slicec('/', 1));
- }
-
- names.sort();
-
- return names;
-}
-
void ProjectSettings::_add_property_info_bind(const Dictionary &p_info) {
ERR_FAIL_COND(!p_info.has("name"));
ERR_FAIL_COND(!p_info.has("type"));
@@ -1148,6 +1132,29 @@ Variant ProjectSettings::get_setting(const String &p_setting, const Variant &p_d
}
}
+Array ProjectSettings::get_global_class_list() {
+ Array script_classes;
+
+ Ref<ConfigFile> cf;
+ cf.instantiate();
+ if (cf->load(get_project_data_path().path_join("global_script_class_cache.cfg")) == OK) {
+ script_classes = cf->get_value("", "list");
+ } else {
+#ifndef TOOLS_ENABLED
+ // Script classes can't be recreated in exported project, so print an error.
+ ERR_PRINT("Could not load global script cache.");
+#endif
+ }
+ return script_classes;
+}
+
+void ProjectSettings::store_global_class_list(const Array &p_classes) {
+ Ref<ConfigFile> cf;
+ cf.instantiate();
+ cf->set_value("", "list", p_classes);
+ cf->save(get_project_data_path().path_join("global_script_class_cache.cfg"));
+}
+
bool ProjectSettings::has_custom_feature(const String &p_feature) const {
return custom_features.has(p_feature);
}
diff --git a/core/config/project_settings.h b/core/config/project_settings.h
index 353e298919..d1704a7c31 100644
--- a/core/config/project_settings.h
+++ b/core/config/project_settings.h
@@ -141,6 +141,8 @@ public:
void set_setting(const String &p_setting, const Variant &p_value);
Variant get_setting(const String &p_setting, const Variant &p_default_value = Variant()) const;
+ Array get_global_class_list();
+ void store_global_class_list(const Array &p_classes);
bool has_setting(String p_var) const;
String localize_path(const String &p_path) const;
@@ -176,8 +178,6 @@ public:
const HashMap<StringName, PropertyInfo> &get_custom_property_info() const;
uint64_t get_last_saved_time() { return last_save_time; }
- Vector<String> get_optimizer_presets() const;
-
List<String> get_input_presets() const { return input_presets; }
Variant get_setting_with_override(const StringName &p_name) const;
diff --git a/core/core_bind.cpp b/core/core_bind.cpp
index ab433bd8f1..96e1da9dde 100644
--- a/core/core_bind.cpp
+++ b/core/core_bind.cpp
@@ -322,8 +322,12 @@ String OS::get_environment(const String &p_var) const {
return ::OS::get_singleton()->get_environment(p_var);
}
-bool OS::set_environment(const String &p_var, const String &p_value) const {
- return ::OS::get_singleton()->set_environment(p_var, p_value);
+void OS::set_environment(const String &p_var, const String &p_value) const {
+ ::OS::get_singleton()->set_environment(p_var, p_value);
+}
+
+void OS::unset_environment(const String &p_var) const {
+ ::OS::get_singleton()->unset_environment(p_var);
}
String OS::get_name() const {
@@ -548,9 +552,10 @@ void OS::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_process_running", "pid"), &OS::is_process_running);
ClassDB::bind_method(D_METHOD("get_process_id"), &OS::get_process_id);
+ ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
ClassDB::bind_method(D_METHOD("get_environment", "variable"), &OS::get_environment);
ClassDB::bind_method(D_METHOD("set_environment", "variable", "value"), &OS::set_environment);
- ClassDB::bind_method(D_METHOD("has_environment", "variable"), &OS::has_environment);
+ ClassDB::bind_method(D_METHOD("unset_environment", "variable"), &OS::unset_environment);
ClassDB::bind_method(D_METHOD("get_name"), &OS::get_name);
ClassDB::bind_method(D_METHOD("get_distribution_name"), &OS::get_distribution_name);
diff --git a/core/core_bind.h b/core/core_bind.h
index 7ef346d1c4..c0c87fd009 100644
--- a/core/core_bind.h
+++ b/core/core_bind.h
@@ -162,7 +162,8 @@ public:
bool has_environment(const String &p_var) const;
String get_environment(const String &p_var) const;
- bool set_environment(const String &p_var, const String &p_value) const;
+ void set_environment(const String &p_var, const String &p_value) const;
+ void unset_environment(const String &p_var) const;
String get_name() const;
String get_distribution_name() const;
diff --git a/core/debugger/script_debugger.cpp b/core/debugger/script_debugger.cpp
index 8af1573bff..32725b76c1 100644
--- a/core/debugger/script_debugger.cpp
+++ b/core/debugger/script_debugger.cpp
@@ -73,10 +73,6 @@ bool ScriptDebugger::is_breakpoint(int p_line, const StringName &p_source) const
return breakpoints[p_line].has(p_source);
}
-bool ScriptDebugger::is_breakpoint_line(int p_line) const {
- return breakpoints.has(p_line);
-}
-
String ScriptDebugger::breakpoint_find_source(const String &p_source) const {
return p_source;
}
diff --git a/core/debugger/script_debugger.h b/core/debugger/script_debugger.h
index c7aa90027b..edce089179 100644
--- a/core/debugger/script_debugger.h
+++ b/core/debugger/script_debugger.h
@@ -64,7 +64,6 @@ public:
void insert_breakpoint(int p_line, const StringName &p_source);
void remove_breakpoint(int p_line, const StringName &p_source);
bool is_breakpoint(int p_line, const StringName &p_source) const;
- bool is_breakpoint_line(int p_line) const;
void clear_breakpoints();
const HashMap<int, HashSet<StringName>> &get_breakpoints() const { return breakpoints; }
diff --git a/core/extension/extension_api_dump.cpp b/core/extension/extension_api_dump.cpp
index 312064a36c..7be14b741d 100644
--- a/core/extension/extension_api_dump.cpp
+++ b/core/extension/extension_api_dump.cpp
@@ -458,6 +458,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
// Global enums and constants.
Array constants;
HashMap<String, List<Pair<String, int64_t>>> enum_list;
+ HashMap<String, bool> enum_is_bitfield;
for (int i = 0; i < CoreConstants::get_global_constant_count(); i++) {
int64_t value = CoreConstants::get_global_constant_value(i);
@@ -466,6 +467,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
bool bitfield = CoreConstants::is_global_constant_bitfield(i);
if (!enum_name.is_empty()) {
enum_list[enum_name].push_back(Pair<String, int64_t>(name, value));
+ enum_is_bitfield[enum_name] = bitfield;
} else {
Dictionary d;
d["name"] = name;
@@ -481,6 +483,7 @@ Dictionary GDExtensionAPIDump::generate_extension_api() {
for (const KeyValue<String, List<Pair<String, int64_t>>> &E : enum_list) {
Dictionary d1;
d1["name"] = E.key;
+ d1["is_bitfield"] = enum_is_bitfield[E.key];
Array values;
for (const Pair<String, int64_t> &F : E.value) {
Dictionary d2;
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index bd4fa61bd5..a9063c8b27 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -31,8 +31,11 @@
#include "gdextension_interface.h"
#include "core/config/engine.h"
+#include "core/io/file_access.h"
+#include "core/io/xml_parser.h"
#include "core/object/class_db.h"
#include "core/object/script_language_extension.h"
+#include "core/object/worker_thread_pool.h"
#include "core/os/memory.h"
#include "core/variant/variant.h"
#include "core/version.h"
@@ -678,6 +681,59 @@ static const char32_t *gdextension_string_operator_index_const(GDExtensionConstS
return &self->ptr()[p_index];
}
+static void gdextension_string_operator_plus_eq_string(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b) {
+ String *self = (String *)p_self;
+ const String *b = (const String *)p_b;
+ *self += *b;
+}
+
+static void gdextension_string_operator_plus_eq_char(GDExtensionStringPtr p_self, char32_t p_b) {
+ String *self = (String *)p_self;
+ *self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_cstr(GDExtensionStringPtr p_self, const char *p_b) {
+ String *self = (String *)p_self;
+ *self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_wcstr(GDExtensionStringPtr p_self, const wchar_t *p_b) {
+ String *self = (String *)p_self;
+ *self += p_b;
+}
+
+static void gdextension_string_operator_plus_eq_c32str(GDExtensionStringPtr p_self, const char32_t *p_b) {
+ String *self = (String *)p_self;
+ *self += p_b;
+}
+
+static GDExtensionInt gdextension_xml_parser_open_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size) {
+ XMLParser *xml = (XMLParser *)p_instance;
+ return (GDExtensionInt)xml->_open_buffer(p_buffer, p_size);
+}
+
+static void gdextension_file_access_store_buffer(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length) {
+ FileAccess *fa = (FileAccess *)p_instance;
+ fa->store_buffer(p_src, p_length);
+}
+
+static uint64_t gdextension_file_access_get_buffer(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length) {
+ const FileAccess *fa = (FileAccess *)p_instance;
+ return fa->get_buffer(p_dst, p_length);
+}
+
+static int64_t gdextension_worker_thread_pool_add_native_group_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description) {
+ WorkerThreadPool *p = (WorkerThreadPool *)p_instance;
+ const String *description = (const String *)p_description;
+ return (int64_t)p->add_native_group_task(p_func, p_userdata, p_elements, p_tasks, static_cast<bool>(p_high_priority), *description);
+}
+
+static int64_t gdextension_worker_thread_pool_add_native_task(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description) {
+ WorkerThreadPool *p = (WorkerThreadPool *)p_instance;
+ const String *description = (const String *)p_description;
+ return (int64_t)p->add_native_task(p_func, p_userdata, static_cast<bool>(p_high_priority), *description);
+}
+
/* Packed array functions */
static uint8_t *gdextension_packed_byte_array_operator_index(GDExtensionTypePtr p_self, GDExtensionInt p_index) {
@@ -1025,6 +1081,25 @@ void gdextension_setup_interface(GDExtensionInterface *p_interface) {
gde_interface.string_to_wide_chars = gdextension_string_to_wide_chars;
gde_interface.string_operator_index = gdextension_string_operator_index;
gde_interface.string_operator_index_const = gdextension_string_operator_index_const;
+ gde_interface.string_operator_plus_eq_string = gdextension_string_operator_plus_eq_string;
+ gde_interface.string_operator_plus_eq_char = gdextension_string_operator_plus_eq_char;
+ gde_interface.string_operator_plus_eq_cstr = gdextension_string_operator_plus_eq_cstr;
+ gde_interface.string_operator_plus_eq_wcstr = gdextension_string_operator_plus_eq_wcstr;
+ gde_interface.string_operator_plus_eq_c32str = gdextension_string_operator_plus_eq_c32str;
+
+ /* XMLParser extra utilities */
+
+ gde_interface.xml_parser_open_buffer = gdextension_xml_parser_open_buffer;
+
+ /* FileAccess extra utilities */
+
+ gde_interface.file_access_store_buffer = gdextension_file_access_store_buffer;
+ gde_interface.file_access_get_buffer = gdextension_file_access_get_buffer;
+
+ /* WorkerThreadPool extra utilities */
+
+ gde_interface.worker_thread_pool_add_native_group_task = gdextension_worker_thread_pool_add_native_group_task;
+ gde_interface.worker_thread_pool_add_native_task = gdextension_worker_thread_pool_add_native_task;
/* Packed array functions */
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 190298ee8a..6e5dee8265 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -503,6 +503,26 @@ typedef struct {
char32_t *(*string_operator_index)(GDExtensionStringPtr p_self, GDExtensionInt p_index);
const char32_t *(*string_operator_index_const)(GDExtensionConstStringPtr p_self, GDExtensionInt p_index);
+ void (*string_operator_plus_eq_string)(GDExtensionStringPtr p_self, GDExtensionConstStringPtr p_b);
+ void (*string_operator_plus_eq_char)(GDExtensionStringPtr p_self, char32_t p_b);
+ void (*string_operator_plus_eq_cstr)(GDExtensionStringPtr p_self, const char *p_b);
+ void (*string_operator_plus_eq_wcstr)(GDExtensionStringPtr p_self, const wchar_t *p_b);
+ void (*string_operator_plus_eq_c32str)(GDExtensionStringPtr p_self, const char32_t *p_b);
+
+ /* XMLParser extra utilities */
+
+ GDExtensionInt (*xml_parser_open_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_buffer, size_t p_size);
+
+ /* FileAccess extra utilities */
+
+ void (*file_access_store_buffer)(GDExtensionObjectPtr p_instance, const uint8_t *p_src, uint64_t p_length);
+ uint64_t (*file_access_get_buffer)(GDExtensionConstObjectPtr p_instance, uint8_t *p_dst, uint64_t p_length);
+
+ /* WorkerThreadPool extra utilities */
+
+ int64_t (*worker_thread_pool_add_native_group_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *, uint32_t), void *p_userdata, int p_elements, int p_tasks, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description);
+ int64_t (*worker_thread_pool_add_native_task)(GDExtensionObjectPtr p_instance, void (*p_func)(void *), void *p_userdata, GDExtensionBool p_high_priority, GDExtensionConstStringPtr p_description);
+
/* Packed array functions */
uint8_t *(*packed_byte_array_operator_index)(GDExtensionTypePtr p_self, GDExtensionInt p_index); // p_self should be a PackedByteArray
diff --git a/core/input/input_builders.py b/core/input/input_builders.py
index a7729c9af2..76e199e0ff 100644
--- a/core/input/input_builders.py
+++ b/core/input/input_builders.py
@@ -45,7 +45,7 @@ def make_default_controller_mappings(target, source, env):
platform_mappings[current_platform][guid] = line
platform_variables = {
- "Linux": "#if X11_ENABLED",
+ "Linux": "#if LINUXBSD_ENABLED",
"Windows": "#ifdef WINDOWS_ENABLED",
"Mac OS X": "#ifdef MACOS_ENABLED",
"Android": "#if defined(__ANDROID__)",
diff --git a/core/io/file_access.cpp b/core/io/file_access.cpp
index 77d1bdcc5c..cacbcb28a4 100644
--- a/core/io/file_access.cpp
+++ b/core/io/file_access.cpp
@@ -292,7 +292,7 @@ real_t FileAccess::get_real() const {
Variant FileAccess::get_var(bool p_allow_objects) const {
uint32_t len = get_32();
- Vector<uint8_t> buff = _get_buffer(len);
+ Vector<uint8_t> buff = get_buffer(len);
ERR_FAIL_COND_V((uint32_t)buff.size() != len, Variant());
const uint8_t *r = buff.ptr();
@@ -469,7 +469,7 @@ uint64_t FileAccess::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
return i;
}
-Vector<uint8_t> FileAccess::_get_buffer(int64_t p_length) const {
+Vector<uint8_t> FileAccess::get_buffer(int64_t p_length) const {
Vector<uint8_t> data;
ERR_FAIL_COND_V_MSG(p_length < 0, data, "Length of buffer cannot be smaller than 0.");
@@ -663,7 +663,7 @@ void FileAccess::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
}
-void FileAccess::_store_buffer(const Vector<uint8_t> &p_buffer) {
+void FileAccess::store_buffer(const Vector<uint8_t> &p_buffer) {
uint64_t len = p_buffer.size();
if (len == 0) {
return;
@@ -687,7 +687,7 @@ void FileAccess::store_var(const Variant &p_var, bool p_full_objects) {
ERR_FAIL_COND_MSG(err != OK, "Error when trying to encode Variant.");
store_32(len);
- _store_buffer(buff);
+ store_buffer(buff);
}
Vector<uint8_t> FileAccess::get_file_as_bytes(const String &p_path, Error *r_error) {
@@ -829,7 +829,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_float"), &FileAccess::get_float);
ClassDB::bind_method(D_METHOD("get_double"), &FileAccess::get_double);
ClassDB::bind_method(D_METHOD("get_real"), &FileAccess::get_real);
- ClassDB::bind_method(D_METHOD("get_buffer", "length"), &FileAccess::_get_buffer);
+ ClassDB::bind_method(D_METHOD("get_buffer", "length"), (Vector<uint8_t>(FileAccess::*)(int64_t) const) & FileAccess::get_buffer);
ClassDB::bind_method(D_METHOD("get_line"), &FileAccess::get_line);
ClassDB::bind_method(D_METHOD("get_csv_line", "delim"), &FileAccess::get_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("get_as_text", "skip_cr"), &FileAccess::get_as_text, DEFVAL(false));
@@ -847,7 +847,7 @@ void FileAccess::_bind_methods() {
ClassDB::bind_method(D_METHOD("store_float", "value"), &FileAccess::store_float);
ClassDB::bind_method(D_METHOD("store_double", "value"), &FileAccess::store_double);
ClassDB::bind_method(D_METHOD("store_real", "value"), &FileAccess::store_real);
- ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), &FileAccess::_store_buffer);
+ ClassDB::bind_method(D_METHOD("store_buffer", "buffer"), (void(FileAccess::*)(const Vector<uint8_t> &)) & FileAccess::store_buffer);
ClassDB::bind_method(D_METHOD("store_line", "line"), &FileAccess::store_line);
ClassDB::bind_method(D_METHOD("store_csv_line", "values", "delim"), &FileAccess::store_csv_line, DEFVAL(","));
ClassDB::bind_method(D_METHOD("store_string", "string"), &FileAccess::store_string);
diff --git a/core/io/file_access.h b/core/io/file_access.h
index 3116ed521f..3e51ba11ed 100644
--- a/core/io/file_access.h
+++ b/core/io/file_access.h
@@ -127,7 +127,7 @@ public:
Variant get_var(bool p_allow_objects = false) const;
virtual uint64_t get_buffer(uint8_t *p_dst, uint64_t p_length) const; ///< get an array of bytes
- Vector<uint8_t> _get_buffer(int64_t p_length) const;
+ Vector<uint8_t> get_buffer(int64_t p_length) const;
virtual String get_line() const;
virtual String get_token() const;
virtual Vector<String> get_csv_line(const String &p_delim = ",") const;
@@ -162,7 +162,7 @@ public:
virtual String get_pascal_string();
virtual void store_buffer(const uint8_t *p_src, uint64_t p_length); ///< store an array of bytes
- void _store_buffer(const Vector<uint8_t> &p_buffer);
+ void store_buffer(const Vector<uint8_t> &p_buffer);
void store_var(const Variant &p_var, bool p_full_objects = false);
diff --git a/core/io/image_loader.cpp b/core/io/image_loader.cpp
index 17fb199811..c6452f1033 100644
--- a/core/io/image_loader.cpp
+++ b/core/io/image_loader.cpp
@@ -135,10 +135,6 @@ void ImageLoader::remove_image_format_loader(Ref<ImageFormatLoader> p_loader) {
loader.erase(p_loader);
}
-const Vector<Ref<ImageFormatLoader>> &ImageLoader::get_image_format_loaders() {
- return loader;
-}
-
void ImageLoader::cleanup() {
while (loader.size()) {
remove_image_format_loader(loader[0]);
diff --git a/core/io/image_loader.h b/core/io/image_loader.h
index 1473f24186..ac51f13376 100644
--- a/core/io/image_loader.h
+++ b/core/io/image_loader.h
@@ -98,8 +98,6 @@ public:
static void add_image_format_loader(Ref<ImageFormatLoader> p_loader);
static void remove_image_format_loader(Ref<ImageFormatLoader> p_loader);
- static const Vector<Ref<ImageFormatLoader>> &get_image_format_loaders();
-
static void cleanup();
};
diff --git a/core/io/resource.cpp b/core/io/resource.cpp
index 2d6f09725f..6d3575b9fa 100644
--- a/core/io/resource.cpp
+++ b/core/io/resource.cpp
@@ -385,10 +385,6 @@ void Resource::set_as_translation_remapped(bool p_remapped) {
ResourceCache::lock.unlock();
}
-bool Resource::is_translation_remapped() const {
- return remapped_list.in_list();
-}
-
#ifdef TOOLS_ENABLED
//helps keep IDs same number when loading/saving scenes. -1 clears ID and it Returns -1 when no id stored
void Resource::set_id_for_path(const String &p_path, const String &p_id) {
@@ -481,9 +477,6 @@ void ResourceCache::clear() {
resources.clear();
}
-void ResourceCache::reload_externals() {
-}
-
bool ResourceCache::has(const String &p_path) {
lock.lock();
diff --git a/core/io/resource.h b/core/io/resource.h
index 22ce5cef43..5135664f36 100644
--- a/core/io/resource.h
+++ b/core/io/resource.h
@@ -136,7 +136,6 @@ public:
#endif
void set_as_translation_remapped(bool p_remapped);
- bool is_translation_remapped() const;
virtual RID get_rid() const; // some resources may offer conversion to RID
@@ -164,7 +163,6 @@ class ResourceCache {
friend void register_core_types();
public:
- static void reload_externals();
static bool has(const String &p_path);
static Ref<Resource> get_ref(const String &p_path);
static void get_cached_resources(List<Ref<Resource>> *p_resources);
diff --git a/core/io/resource_format_binary.cpp b/core/io/resource_format_binary.cpp
index 45e1301930..03beb25b03 100644
--- a/core/io/resource_format_binary.cpp
+++ b/core/io/resource_format_binary.cpp
@@ -661,10 +661,6 @@ Error ResourceLoaderBinary::parse_variant(Variant &r_v) {
return OK; //never reach anyway
}
-void ResourceLoaderBinary::set_local_path(const String &p_local_path) {
- res_path = p_local_path;
-}
-
Ref<Resource> ResourceLoaderBinary::get_resource() {
return resource;
}
diff --git a/core/io/resource_format_binary.h b/core/io/resource_format_binary.h
index 2e8988005f..9dd208e3cd 100644
--- a/core/io/resource_format_binary.h
+++ b/core/io/resource_format_binary.h
@@ -92,7 +92,6 @@ class ResourceLoaderBinary {
HashMap<String, Ref<Resource>> dependency_cache;
public:
- void set_local_path(const String &p_local_path);
Ref<Resource> get_resource();
Error load();
void set_translation_remapped(bool p_remapped);
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index 946c31cf0d..68b9f8b6f7 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -1011,13 +1011,6 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) {
return true;
}
-void ResourceLoader::remove_custom_resource_format_loader(String script_path) {
- Ref<ResourceFormatLoader> custom_loader = _find_custom_resource_format_loader(script_path);
- if (custom_loader.is_valid()) {
- remove_resource_format_loader(custom_loader);
- }
-}
-
void ResourceLoader::set_create_missing_resources_if_class_unavailable(bool p_enable) {
create_missing_resources_if_class_unavailable = p_enable;
}
diff --git a/core/io/resource_loader.h b/core/io/resource_loader.h
index 41ba0dc6e6..e427a2f5fc 100644
--- a/core/io/resource_loader.h
+++ b/core/io/resource_loader.h
@@ -225,7 +225,6 @@ public:
static ResourceLoaderImport import;
static bool add_custom_resource_format_loader(String script_path);
- static void remove_custom_resource_format_loader(String script_path);
static void add_custom_loaders();
static void remove_custom_loaders();
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 9809b9a48f..b8201cc6b9 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -250,13 +250,6 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
return true;
}
-void ResourceSaver::remove_custom_resource_format_saver(String script_path) {
- Ref<ResourceFormatSaver> custom_saver = _find_custom_resource_format_saver(script_path);
- if (custom_saver.is_valid()) {
- remove_resource_format_saver(custom_saver);
- }
-}
-
void ResourceSaver::add_custom_savers() {
// Custom resource savers exploits global class names
diff --git a/core/io/resource_saver.h b/core/io/resource_saver.h
index 2043947963..9e88b2086b 100644
--- a/core/io/resource_saver.h
+++ b/core/io/resource_saver.h
@@ -101,7 +101,6 @@ public:
static void set_get_resource_id_for_path(ResourceSaverGetResourceIDForPath p_callback);
static bool add_custom_resource_format_saver(String script_path);
- static void remove_custom_resource_format_saver(String script_path);
static void add_custom_savers();
static void remove_custom_savers();
};
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 09836419be..5c0a017bfc 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -354,10 +354,10 @@ void XMLParser::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_node_offset"), &XMLParser::get_node_offset);
ClassDB::bind_method(D_METHOD("get_attribute_count"), &XMLParser::get_attribute_count);
ClassDB::bind_method(D_METHOD("get_attribute_name", "idx"), &XMLParser::get_attribute_name);
- ClassDB::bind_method(D_METHOD("get_attribute_value", "idx"), (String(XMLParser::*)(int) const) & XMLParser::get_attribute_value);
+ ClassDB::bind_method(D_METHOD("get_attribute_value", "idx"), &XMLParser::get_attribute_value);
ClassDB::bind_method(D_METHOD("has_attribute", "name"), &XMLParser::has_attribute);
- ClassDB::bind_method(D_METHOD("get_named_attribute_value", "name"), (String(XMLParser::*)(const String &) const) & XMLParser::get_attribute_value);
- ClassDB::bind_method(D_METHOD("get_named_attribute_value_safe", "name"), &XMLParser::get_attribute_value_safe);
+ ClassDB::bind_method(D_METHOD("get_named_attribute_value", "name"), &XMLParser::get_named_attribute_value);
+ ClassDB::bind_method(D_METHOD("get_named_attribute_value_safe", "name"), &XMLParser::get_named_attribute_value_safe);
ClassDB::bind_method(D_METHOD("is_empty"), &XMLParser::is_empty);
ClassDB::bind_method(D_METHOD("get_current_line"), &XMLParser::get_current_line);
ClassDB::bind_method(D_METHOD("skip_section"), &XMLParser::skip_section);
@@ -422,7 +422,7 @@ bool XMLParser::has_attribute(const String &p_name) const {
return false;
}
-String XMLParser::get_attribute_value(const String &p_name) const {
+String XMLParser::get_named_attribute_value(const String &p_name) const {
int idx = -1;
for (int i = 0; i < attributes.size(); i++) {
if (attributes[i].name == p_name) {
@@ -436,7 +436,7 @@ String XMLParser::get_attribute_value(const String &p_name) const {
return attributes[idx].value;
}
-String XMLParser::get_attribute_value_safe(const String &p_name) const {
+String XMLParser::get_named_attribute_value_safe(const String &p_name) const {
int idx = -1;
for (int i = 0; i < attributes.size(); i++) {
if (attributes[i].name == p_name) {
diff --git a/core/io/xml_parser.h b/core/io/xml_parser.h
index b4ae5c93b6..b96478c7a5 100644
--- a/core/io/xml_parser.h
+++ b/core/io/xml_parser.h
@@ -109,8 +109,8 @@ public:
String get_attribute_name(int p_idx) const;
String get_attribute_value(int p_idx) const;
bool has_attribute(const String &p_name) const;
- String get_attribute_value(const String &p_name) const;
- String get_attribute_value_safe(const String &p_name) const; // do not print error if doesn't exist
+ String get_named_attribute_value(const String &p_name) const;
+ String get_named_attribute_value_safe(const String &p_name) const; // do not print error if doesn't exist
bool is_empty() const;
int get_current_line() const;
diff --git a/core/math/basis.cpp b/core/math/basis.cpp
index 39e383fb49..234a4ddb79 100644
--- a/core/math/basis.cpp
+++ b/core/math/basis.cpp
@@ -36,23 +36,6 @@
#define cofac(row1, col1, row2, col2) \
(rows[row1][col1] * rows[row2][col2] - rows[row1][col2] * rows[row2][col1])
-void Basis::from_z(const Vector3 &p_z) {
- if (Math::abs(p_z.z) > (real_t)Math_SQRT12) {
- // choose p in y-z plane
- real_t a = p_z[1] * p_z[1] + p_z[2] * p_z[2];
- real_t k = 1.0f / Math::sqrt(a);
- rows[0] = Vector3(0, -p_z[2] * k, p_z[1] * k);
- rows[1] = Vector3(a * k, -p_z[0] * rows[0][2], p_z[0] * rows[0][1]);
- } else {
- // choose p in x-y plane
- real_t a = p_z.x * p_z.x + p_z.y * p_z.y;
- real_t k = 1.0f / Math::sqrt(a);
- rows[0] = Vector3(-p_z.y * k, p_z.x * k, 0);
- rows[1] = Vector3(-p_z.z * rows[0].y, p_z.z * rows[0].x, a * k);
- }
- rows[2] = p_z;
-}
-
void Basis::invert() {
real_t co[3] = {
cofac(1, 1, 2, 2), cofac(1, 2, 2, 0), cofac(1, 0, 2, 1)
@@ -271,14 +254,6 @@ float Basis::get_uniform_scale() const {
return (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f;
}
-void Basis::make_scale_uniform() {
- float l = (rows[0].length() + rows[1].length() + rows[2].length()) / 3.0f;
- for (int i = 0; i < 3; i++) {
- rows[i].normalize();
- rows[i] *= l;
- }
-}
-
Basis Basis::scaled_local(const Vector3 &p_scale) const {
return (*this) * Basis::from_scale(p_scale);
}
diff --git a/core/math/basis.h b/core/math/basis.h
index b3197dbc84..bbc1d40469 100644
--- a/core/math/basis.h
+++ b/core/math/basis.h
@@ -56,8 +56,6 @@ struct _NO_DISCARD_ Basis {
_FORCE_INLINE_ real_t determinant() const;
- void from_z(const Vector3 &p_z);
-
void rotate(const Vector3 &p_axis, real_t p_angle);
Basis rotated(const Vector3 &p_axis, real_t p_angle) const;
@@ -101,8 +99,6 @@ struct _NO_DISCARD_ Basis {
void scale_orthogonal(const Vector3 &p_scale);
Basis scaled_orthogonal(const Vector3 &p_scale) const;
-
- void make_scale_uniform();
float get_uniform_scale() const;
Vector3 get_scale() const;
diff --git a/core/math/face3.cpp b/core/math/face3.cpp
index e53bbf872b..1dff0ee4a6 100644
--- a/core/math/face3.cpp
+++ b/core/math/face3.cpp
@@ -120,36 +120,6 @@ bool Face3::is_degenerate() const {
return (normal.length_squared() < (real_t)CMP_EPSILON2);
}
-Face3::Side Face3::get_side_of(const Face3 &p_face, ClockDirection p_clock_dir) const {
- int over = 0, under = 0;
-
- Plane plane = get_plane(p_clock_dir);
-
- for (int i = 0; i < 3; i++) {
- const Vector3 &v = p_face.vertex[i];
-
- if (plane.has_point(v)) { //coplanar, don't bother
- continue;
- }
-
- if (plane.is_point_over(v)) {
- over++;
- } else {
- under++;
- }
- }
-
- if (over > 0 && under == 0) {
- return SIDE_OVER;
- } else if (under > 0 && over == 0) {
- return SIDE_UNDER;
- } else if (under == 0 && over == 0) {
- return SIDE_COPLANAR;
- } else {
- return SIDE_SPANNING;
- }
-}
-
Vector3 Face3::get_random_point_inside() const {
real_t a = Math::random(0.0, 1.0);
real_t b = Math::random(0.0, 1.0);
@@ -164,20 +134,10 @@ Plane Face3::get_plane(ClockDirection p_dir) const {
return Plane(vertex[0], vertex[1], vertex[2], p_dir);
}
-Vector3 Face3::get_median_point() const {
- return (vertex[0] + vertex[1] + vertex[2]) / 3.0f;
-}
-
real_t Face3::get_area() const {
return vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]).length() * 0.5f;
}
-ClockDirection Face3::get_clock_dir() const {
- Vector3 normal = vec3_cross(vertex[0] - vertex[1], vertex[0] - vertex[2]);
- //printf("normal is %g,%g,%g x %g,%g,%g- wtfu is %g\n",tofloat(normal.x),tofloat(normal.y),tofloat(normal.z),tofloat(vertex[0].x),tofloat(vertex[0].y),tofloat(vertex[0].z),tofloat( normal.dot( vertex[0] ) ) );
- return (normal.dot(vertex[0]) >= 0) ? CLOCKWISE : COUNTERCLOCKWISE;
-}
-
bool Face3::intersects_aabb(const AABB &p_aabb) const {
/** TEST PLANE **/
if (!p_aabb.intersects_plane(get_plane())) {
diff --git a/core/math/face3.h b/core/math/face3.h
index 3d87de03dc..3dd47d0226 100644
--- a/core/math/face3.h
+++ b/core/math/face3.h
@@ -57,19 +57,14 @@ struct _NO_DISCARD_ Face3 {
Plane get_plane(ClockDirection p_dir = CLOCKWISE) const;
Vector3 get_random_point_inside() const;
- Side get_side_of(const Face3 &p_face, ClockDirection p_clock_dir = CLOCKWISE) const;
-
bool is_degenerate() const;
real_t get_area() const;
- Vector3 get_median_point() const;
Vector3 get_closest_point_to(const Vector3 &p_point) const;
bool intersects_ray(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection = nullptr) const;
bool intersects_segment(const Vector3 &p_from, const Vector3 &p_dir, Vector3 *p_intersection = nullptr) const;
- ClockDirection get_clock_dir() const; ///< todo, test if this is returning the proper clockwisity
-
void get_support(const Vector3 &p_normal, const Transform3D &p_transform, Vector3 *p_vertices, int *p_count, int p_max) const;
void project_range(const Vector3 &p_normal, const Transform3D &p_transform, real_t &r_min, real_t &r_max) const;
diff --git a/core/math/geometry_2d.cpp b/core/math/geometry_2d.cpp
index a0b76d31cb..74cb92539a 100644
--- a/core/math/geometry_2d.cpp
+++ b/core/math/geometry_2d.cpp
@@ -320,41 +320,6 @@ Vector<Vector<Point2>> Geometry2D::_polypath_offset(const Vector<Point2> &p_poly
return polypaths;
}
-Vector<Point2i> Geometry2D::pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size) {
- Vector<stbrp_node> nodes;
- nodes.resize(p_atlas_size.width);
-
- stbrp_context context;
- stbrp_init_target(&context, p_atlas_size.width, p_atlas_size.height, nodes.ptrw(), p_atlas_size.width);
-
- Vector<stbrp_rect> rects;
- rects.resize(p_sizes.size());
-
- for (int i = 0; i < p_sizes.size(); i++) {
- rects.write[i].id = 0;
- rects.write[i].w = p_sizes[i].width;
- rects.write[i].h = p_sizes[i].height;
- rects.write[i].x = 0;
- rects.write[i].y = 0;
- rects.write[i].was_packed = 0;
- }
-
- int res = stbrp_pack_rects(&context, rects.ptrw(), rects.size());
- if (res == 0) { //pack failed
- return Vector<Point2i>();
- }
-
- Vector<Point2i> ret;
- ret.resize(p_sizes.size());
-
- for (int i = 0; i < p_sizes.size(); i++) {
- Point2i r(rects[i].x, rects[i].y);
- ret.write[i] = r;
- }
-
- return ret;
-}
-
Vector<Vector3i> Geometry2D::partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size) {
Vector<stbrp_node> nodes;
nodes.resize(p_atlas_size.width);
diff --git a/core/math/geometry_2d.h b/core/math/geometry_2d.h
index b55aecf85e..0e5702e0af 100644
--- a/core/math/geometry_2d.h
+++ b/core/math/geometry_2d.h
@@ -464,7 +464,6 @@ public:
static Vector<Vector<Vector2>> decompose_polygon_in_convex(Vector<Point2> polygon);
static void make_atlas(const Vector<Size2i> &p_rects, Vector<Point2i> &r_result, Size2i &r_size);
- static Vector<Point2i> pack_rects(const Vector<Size2i> &p_sizes, const Size2i &p_atlas_size);
static Vector<Vector3i> partial_pack_rects(const Vector<Vector2i> &p_sizes, const Size2i &p_atlas_size);
private:
diff --git a/core/math/geometry_3d.cpp b/core/math/geometry_3d.cpp
index 3ac78e0709..51523ea296 100644
--- a/core/math/geometry_3d.cpp
+++ b/core/math/geometry_3d.cpp
@@ -198,149 +198,6 @@ struct _FaceClassify {
_FaceClassify() {}
};
-static bool _connect_faces(_FaceClassify *p_faces, int len, int p_group) {
- // Connect faces, error will occur if an edge is shared between more than 2 faces.
- // Clear connections.
-
- bool error = false;
-
- for (int i = 0; i < len; i++) {
- for (int j = 0; j < 3; j++) {
- p_faces[i].links[j].clear();
- }
- }
-
- for (int i = 0; i < len; i++) {
- if (p_faces[i].group != p_group) {
- continue;
- }
- for (int j = i + 1; j < len; j++) {
- if (p_faces[j].group != p_group) {
- continue;
- }
-
- for (int k = 0; k < 3; k++) {
- Vector3 vi1 = p_faces[i].face.vertex[k];
- Vector3 vi2 = p_faces[i].face.vertex[(k + 1) % 3];
-
- for (int l = 0; l < 3; l++) {
- Vector3 vj2 = p_faces[j].face.vertex[l];
- Vector3 vj1 = p_faces[j].face.vertex[(l + 1) % 3];
-
- if (vi1.distance_to(vj1) < 0.00001f &&
- vi2.distance_to(vj2) < 0.00001f) {
- if (p_faces[i].links[k].face != -1) {
- ERR_PRINT("already linked\n");
- error = true;
- break;
- }
- if (p_faces[j].links[l].face != -1) {
- ERR_PRINT("already linked\n");
- error = true;
- break;
- }
-
- p_faces[i].links[k].face = j;
- p_faces[i].links[k].edge = l;
- p_faces[j].links[l].face = i;
- p_faces[j].links[l].edge = k;
- }
- }
- if (error) {
- break;
- }
- }
- if (error) {
- break;
- }
- }
- if (error) {
- break;
- }
- }
-
- for (int i = 0; i < len; i++) {
- p_faces[i].valid = true;
- for (int j = 0; j < 3; j++) {
- if (p_faces[i].links[j].face == -1) {
- p_faces[i].valid = false;
- }
- }
- }
- return error;
-}
-
-static bool _group_face(_FaceClassify *p_faces, int len, int p_index, int p_group) {
- if (p_faces[p_index].group >= 0) {
- return false;
- }
-
- p_faces[p_index].group = p_group;
-
- for (int i = 0; i < 3; i++) {
- ERR_FAIL_INDEX_V(p_faces[p_index].links[i].face, len, true);
- _group_face(p_faces, len, p_faces[p_index].links[i].face, p_group);
- }
-
- return true;
-}
-
-Vector<Vector<Face3>> Geometry3D::separate_objects(Vector<Face3> p_array) {
- Vector<Vector<Face3>> objects;
-
- int len = p_array.size();
-
- const Face3 *arrayptr = p_array.ptr();
-
- Vector<_FaceClassify> fc;
-
- fc.resize(len);
-
- _FaceClassify *_fcptr = fc.ptrw();
-
- for (int i = 0; i < len; i++) {
- _fcptr[i].face = arrayptr[i];
- }
-
- bool error = _connect_faces(_fcptr, len, -1);
-
- ERR_FAIL_COND_V_MSG(error, Vector<Vector<Face3>>(), "Invalid geometry.");
-
- // Group connected faces in separate objects.
-
- int group = 0;
- for (int i = 0; i < len; i++) {
- if (!_fcptr[i].valid) {
- continue;
- }
- if (_group_face(_fcptr, len, i, group)) {
- group++;
- }
- }
-
- // Group connected faces in separate objects.
-
- for (int i = 0; i < len; i++) {
- _fcptr[i].face = arrayptr[i];
- }
-
- if (group >= 0) {
- objects.resize(group);
- Vector<Face3> *group_faces = objects.ptrw();
-
- for (int i = 0; i < len; i++) {
- if (!_fcptr[i].valid) {
- continue;
- }
- if (_fcptr[i].group >= 0 && _fcptr[i].group < group) {
- group_faces[_fcptr[i].group].push_back(_fcptr[i].face);
- }
- }
- }
-
- return objects;
-}
-
/*** GEOMETRY WRAPPER ***/
enum _CellFlags {
@@ -748,7 +605,7 @@ Geometry3D::MeshData Geometry3D::build_convex_mesh(const Vector<Plane> &p_planes
Vector3 right = p.normal.cross(ref).normalized();
Vector3 up = p.normal.cross(right).normalized();
- Vector3 center = p.center();
+ Vector3 center = p.get_center();
// make a quad clockwise
LocalVector<Vector3> vertices = {
diff --git a/core/math/geometry_3d.h b/core/math/geometry_3d.h
index 6759db5766..99c554fe05 100644
--- a/core/math/geometry_3d.h
+++ b/core/math/geometry_3d.h
@@ -532,8 +532,6 @@ public:
return clipped;
}
- static Vector<Vector<Face3>> separate_objects(Vector<Face3> p_array);
-
// Create a "wrap" that encloses the given geometry.
static Vector<Face3> wrap_geometry(Vector<Face3> p_array, real_t *p_error = nullptr);
diff --git a/core/math/plane.h b/core/math/plane.h
index 3bc7c54b9d..8159f25342 100644
--- a/core/math/plane.h
+++ b/core/math/plane.h
@@ -47,7 +47,7 @@ struct _NO_DISCARD_ Plane {
/* Plane-Point operations */
- _FORCE_INLINE_ Vector3 center() const { return normal * d; }
+ _FORCE_INLINE_ Vector3 get_center() const { return normal * d; }
Vector3 get_any_perpendicular_normal() const;
_FORCE_INLINE_ bool is_point_over(const Vector3 &p_point) const; ///< Point is over plane
diff --git a/core/math/transform_2d.cpp b/core/math/transform_2d.cpp
index 6a7ee32230..910995d717 100644
--- a/core/math/transform_2d.cpp
+++ b/core/math/transform_2d.cpp
@@ -221,12 +221,6 @@ Transform2D Transform2D::operator*(const Transform2D &p_transform) const {
return t;
}
-Transform2D Transform2D::basis_scaled(const Size2 &p_scale) const {
- Transform2D copy = *this;
- copy.scale_basis(p_scale);
- return copy;
-}
-
Transform2D Transform2D::scaled(const Size2 &p_scale) const {
// Equivalent to left multiplication
Transform2D copy = *this;
diff --git a/core/math/transform_2d.h b/core/math/transform_2d.h
index 2a0917c63f..4a17a9db37 100644
--- a/core/math/transform_2d.h
+++ b/core/math/transform_2d.h
@@ -85,7 +85,6 @@ struct _NO_DISCARD_ Transform2D {
_FORCE_INLINE_ const Vector2 &get_origin() const { return columns[2]; }
_FORCE_INLINE_ void set_origin(const Vector2 &p_origin) { columns[2] = p_origin; }
- Transform2D basis_scaled(const Size2 &p_scale) const;
Transform2D scaled(const Size2 &p_scale) const;
Transform2D scaled_local(const Size2 &p_scale) const;
Transform2D translated(const Vector2 &p_offset) const;
diff --git a/core/math/triangle_mesh.cpp b/core/math/triangle_mesh.cpp
index 4b6921d38b..0da1b8c7ad 100644
--- a/core/math/triangle_mesh.cpp
+++ b/core/math/triangle_mesh.cpp
@@ -182,90 +182,6 @@ void TriangleMesh::create(const Vector<Vector3> &p_faces, const Vector<int32_t>
valid = true;
}
-Vector3 TriangleMesh::get_area_normal(const AABB &p_aabb) const {
- uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
-
- enum {
- TEST_AABB_BIT = 0,
- VISIT_LEFT_BIT = 1,
- VISIT_RIGHT_BIT = 2,
- VISIT_DONE_BIT = 3,
- VISITED_BIT_SHIFT = 29,
- NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1,
- VISITED_BIT_MASK = ~NODE_IDX_MASK,
-
- };
-
- int n_count = 0;
- Vector3 n;
-
- int level = 0;
-
- const Triangle *triangleptr = triangles.ptr();
- // const Vector3 *verticesr = vertices.ptr();
- const BVH *bvhptr = bvh.ptr();
-
- int pos = bvh.size() - 1;
-
- stack[0] = pos;
- while (true) {
- uint32_t node = stack[level] & NODE_IDX_MASK;
- const BVH &b = bvhptr[node];
- bool done = false;
-
- switch (stack[level] >> VISITED_BIT_SHIFT) {
- case TEST_AABB_BIT: {
- if (!b.aabb.intersects(p_aabb)) {
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- } else {
- if (b.face_index >= 0) {
- const Triangle &s = triangleptr[b.face_index];
- n += s.normal;
- n_count++;
-
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
- } else {
- stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node;
- }
- }
- continue;
- }
- case VISIT_LEFT_BIT: {
- stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- level++;
- stack[level] = b.left | TEST_AABB_BIT;
- continue;
- }
- case VISIT_RIGHT_BIT: {
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- level++;
- stack[level] = b.right | TEST_AABB_BIT;
- continue;
- }
- case VISIT_DONE_BIT: {
- if (level == 0) {
- done = true;
- break;
- } else {
- level--;
- }
- continue;
- }
- }
-
- if (done) {
- break;
- }
- }
-
- if (n_count > 0) {
- n /= n_count;
- }
-
- return n;
-}
-
bool TriangleMesh::intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index) const {
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
@@ -468,118 +384,6 @@ bool TriangleMesh::intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, V
return inters;
}
-bool TriangleMesh::intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const {
- uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
-
- //p_fully_inside = true;
-
- enum {
- TEST_AABB_BIT = 0,
- VISIT_LEFT_BIT = 1,
- VISIT_RIGHT_BIT = 2,
- VISIT_DONE_BIT = 3,
- VISITED_BIT_SHIFT = 29,
- NODE_IDX_MASK = (1 << VISITED_BIT_SHIFT) - 1,
- VISITED_BIT_MASK = ~NODE_IDX_MASK,
-
- };
-
- int level = 0;
-
- const Triangle *triangleptr = triangles.ptr();
- const Vector3 *vertexptr = vertices.ptr();
- const BVH *bvhptr = bvh.ptr();
-
- int pos = bvh.size() - 1;
-
- stack[0] = pos;
- while (true) {
- uint32_t node = stack[level] & NODE_IDX_MASK;
- const BVH &b = bvhptr[node];
- bool done = false;
-
- switch (stack[level] >> VISITED_BIT_SHIFT) {
- case TEST_AABB_BIT: {
- if (!b.aabb.intersects_convex_shape(p_planes, p_plane_count, p_points, p_point_count)) {
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- } else {
- if (b.face_index >= 0) {
- const Triangle &s = triangleptr[b.face_index];
-
- for (int j = 0; j < 3; ++j) {
- const Vector3 &point = vertexptr[s.indices[j]];
- const Vector3 &next_point = vertexptr[s.indices[(j + 1) % 3]];
- Vector3 res;
- bool over = true;
- for (int i = 0; i < p_plane_count; i++) {
- const Plane &p = p_planes[i];
-
- if (p.intersects_segment(point, next_point, &res)) {
- bool inisde = true;
- for (int k = 0; k < p_plane_count; k++) {
- if (k == i) {
- continue;
- }
- const Plane &pp = p_planes[k];
- if (pp.is_point_over(res)) {
- inisde = false;
- break;
- }
- }
- if (inisde) {
- return true;
- }
- }
-
- if (p.is_point_over(point)) {
- over = false;
- break;
- }
- }
- if (over) {
- return true;
- }
- }
-
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
-
- } else {
- stack[level] = (VISIT_LEFT_BIT << VISITED_BIT_SHIFT) | node;
- }
- }
- continue;
- }
- case VISIT_LEFT_BIT: {
- stack[level] = (VISIT_RIGHT_BIT << VISITED_BIT_SHIFT) | node;
- level++;
- stack[level] = b.left | TEST_AABB_BIT;
- continue;
- }
- case VISIT_RIGHT_BIT: {
- stack[level] = (VISIT_DONE_BIT << VISITED_BIT_SHIFT) | node;
- level++;
- stack[level] = b.right | TEST_AABB_BIT;
- continue;
- }
- case VISIT_DONE_BIT: {
- if (level == 0) {
- done = true;
- break;
- } else {
- level--;
- }
- continue;
- }
- }
-
- if (done) {
- break;
- }
- }
-
- return false;
-}
-
bool TriangleMesh::inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale) const {
uint32_t *stack = (uint32_t *)alloca(sizeof(int) * max_depth);
diff --git a/core/math/triangle_mesh.h b/core/math/triangle_mesh.h
index 728fd600d5..24fc12dda9 100644
--- a/core/math/triangle_mesh.h
+++ b/core/math/triangle_mesh.h
@@ -84,9 +84,7 @@ public:
bool is_valid() const;
bool intersect_segment(const Vector3 &p_begin, const Vector3 &p_end, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const;
bool intersect_ray(const Vector3 &p_begin, const Vector3 &p_dir, Vector3 &r_point, Vector3 &r_normal, int32_t *r_surf_index = nullptr) const;
- bool intersect_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count) const;
bool inside_convex_shape(const Plane *p_planes, int p_plane_count, const Vector3 *p_points, int p_point_count, Vector3 p_scale = Vector3(1, 1, 1)) const;
- Vector3 get_area_normal(const AABB &p_aabb) const;
Vector<Face3> get_faces() const;
const Vector<Triangle> &get_triangles() const { return triangles; }
diff --git a/core/object/script_language.cpp b/core/object/script_language.cpp
index 7be3a6c688..66ef418e42 100644
--- a/core/object/script_language.cpp
+++ b/core/object/script_language.cpp
@@ -186,6 +186,7 @@ void ScriptServer::unregister_language(const ScriptLanguage *p_language) {
void ScriptServer::init_languages() {
{ // Load global classes.
global_classes_clear();
+#ifndef DISABLE_DEPRECATED
if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
Array script_classes = GLOBAL_GET("_global_script_classes");
@@ -196,6 +197,17 @@ void ScriptServer::init_languages() {
}
add_global_class(c["class"], c["base"], c["language"], c["path"]);
}
+ ProjectSettings::get_singleton()->clear("_global_script_classes");
+ }
+#endif
+
+ Array script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary c = script_classes[i];
+ if (!c.has("class") || !c.has("language") || !c.has("path") || !c.has("base")) {
+ continue;
+ }
+ add_global_class(c["class"], c["base"], c["language"], c["path"]);
}
}
@@ -251,6 +263,15 @@ void ScriptServer::remove_global_class(const StringName &p_class) {
global_classes.erase(p_class);
}
+void ScriptServer::remove_global_class_by_path(const String &p_path) {
+ for (const KeyValue<StringName, GlobalScriptClass> &kv : global_classes) {
+ if (kv.value.path == p_path) {
+ global_classes.erase(kv.key);
+ return;
+ }
+ }
+}
+
bool ScriptServer::is_global_class(const StringName &p_class) {
return global_classes.has(p_class);
}
@@ -291,6 +312,17 @@ void ScriptServer::get_global_class_list(List<StringName> *r_global_classes) {
}
void ScriptServer::save_global_classes() {
+ Dictionary class_icons;
+
+ Array script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary d = script_classes[i];
+ if (!d.has("name") || !d.has("icon")) {
+ continue;
+ }
+ class_icons[d["name"]] = d["icon"];
+ }
+
List<StringName> gc;
get_global_class_list(&gc);
Array gcarr;
@@ -300,25 +332,10 @@ void ScriptServer::save_global_classes() {
d["language"] = global_classes[E].language;
d["path"] = global_classes[E].path;
d["base"] = global_classes[E].base;
+ d["icon"] = class_icons.get(E, "");
gcarr.push_back(d);
}
-
- Array old;
- if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- old = GLOBAL_GET("_global_script_classes");
- }
- if ((!old.is_empty() || gcarr.is_empty()) && gcarr.hash() == old.hash()) {
- return;
- }
-
- if (gcarr.is_empty()) {
- if (ProjectSettings::get_singleton()->has_setting("_global_script_classes")) {
- ProjectSettings::get_singleton()->clear("_global_script_classes");
- }
- } else {
- ProjectSettings::get_singleton()->set("_global_script_classes", gcarr);
- }
- ProjectSettings::get_singleton()->save();
+ ProjectSettings::get_singleton()->store_global_class_list(gcarr);
}
////////////////////
diff --git a/core/object/script_language.h b/core/object/script_language.h
index ff678bcd25..02d1880dc2 100644
--- a/core/object/script_language.h
+++ b/core/object/script_language.h
@@ -80,6 +80,7 @@ public:
static void global_classes_clear();
static void add_global_class(const StringName &p_class, const StringName &p_base, const StringName &p_language, const String &p_path);
static void remove_global_class(const StringName &p_class);
+ static void remove_global_class_by_path(const String &p_path);
static bool is_global_class(const StringName &p_class);
static StringName get_global_class_language(const StringName &p_class);
static String get_global_class_path(const String &p_class);
diff --git a/core/os/keyboard.cpp b/core/os/keyboard.cpp
index e0231b818f..5183b77cb1 100644
--- a/core/os/keyboard.cpp
+++ b/core/os/keyboard.cpp
@@ -63,12 +63,15 @@ static const _KeyCodeText _keycodes[] = {
{Key::CTRL ,"Ctrl"},
#if defined(MACOS_ENABLED)
{Key::META ,"Command"},
+ {Key::CMD_OR_CTRL ,"Command"},
{Key::ALT ,"Option"},
#elif defined(WINDOWS_ENABLED)
{Key::META ,"Windows"},
+ {Key::CMD_OR_CTRL ,"Ctrl"},
{Key::ALT ,"Alt"},
#else
{Key::META ,"Meta"},
+ {Key::CMD_OR_CTRL ,"Ctrl"},
{Key::ALT ,"Alt"},
#endif
{Key::CAPSLOCK ,"CapsLock"},
diff --git a/core/os/keyboard.h b/core/os/keyboard.h
index 389baee915..c78fa2a631 100644
--- a/core/os/keyboard.h
+++ b/core/os/keyboard.h
@@ -65,6 +65,11 @@ enum class Key {
SHIFT = SPECIAL | 0x15,
CTRL = SPECIAL | 0x16,
META = SPECIAL | 0x17,
+#if defined(MACOS_ENABLED)
+ CMD_OR_CTRL = META,
+#else
+ CMD_OR_CTRL = CTRL,
+#endif
ALT = SPECIAL | 0x18,
CAPSLOCK = SPECIAL | 0x19,
NUMLOCK = SPECIAL | 0x1A,
diff --git a/core/os/os.h b/core/os/os.h
index b80efa47b7..4818e9281a 100644
--- a/core/os/os.h
+++ b/core/os/os.h
@@ -167,7 +167,8 @@ public:
virtual bool has_environment(const String &p_var) const = 0;
virtual String get_environment(const String &p_var) const = 0;
- virtual bool set_environment(const String &p_var, const String &p_value) const = 0;
+ virtual void set_environment(const String &p_var, const String &p_value) const = 0;
+ virtual void unset_environment(const String &p_var) const = 0;
virtual String get_name() const = 0;
virtual String get_distribution_name() const = 0;
diff --git a/core/variant/variant.h b/core/variant/variant.h
index fff59c43a6..b9294de77d 100644
--- a/core/variant/variant.h
+++ b/core/variant/variant.h
@@ -655,6 +655,7 @@ public:
static bool has_indexing(Variant::Type p_type);
static Variant::Type get_indexed_element_type(Variant::Type p_type);
+ static uint32_t get_indexed_element_usage(Variant::Type p_type);
typedef void (*ValidatedIndexedSetter)(Variant *base, int64_t index, const Variant *value, bool *oob);
typedef void (*ValidatedIndexedGetter)(const Variant *base, int64_t index, Variant *value, bool *oob);
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 05fb62ff12..2cc0b3a8d7 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1923,7 +1923,7 @@ static void _register_variant_builtin_methods() {
/* Plane */
bind_method(Plane, normalized, sarray(), varray());
- bind_method(Plane, center, sarray(), varray());
+ bind_method(Plane, get_center, sarray(), varray());
bind_method(Plane, is_equal_approx, sarray("to_plane"), varray());
bind_method(Plane, is_finite, sarray(), varray());
bind_method(Plane, is_point_over, sarray("point"), varray());
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index b8d4495702..ba37e15f31 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -389,6 +389,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v.write[index] = PtrToArg<m_elem_type>::convert(member); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
};
@@ -460,6 +461,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v.write[index] = PtrToArg<m_elem_type>::convert(member); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
};
@@ -515,6 +517,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v[index] = PtrToArg<m_elem_type>::convert(member); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
};
@@ -564,6 +567,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v m_accessor[index] = PtrToArg<m_elem_type>::convert(member); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
};
@@ -613,6 +617,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
v.m_set(index, PtrToArg<m_elem_type>::convert(member)); \
} \
static Variant::Type get_index_type() { return GetTypeInfo<m_elem_type>::VARIANT_TYPE; } \
+ static uint32_t get_index_usage() { return GetTypeInfo<m_elem_type>::get_class_info().usage; } \
static uint64_t get_indexed_size(const Variant *base) { return m_max; } \
};
@@ -683,6 +688,7 @@ struct VariantIndexedSetGet_Array {
v.set(index, PtrToArg<Variant>::convert(member));
}
static Variant::Type get_index_type() { return Variant::NIL; }
+ static uint32_t get_index_usage() { return PROPERTY_USAGE_NIL_IS_VARIANT; }
static uint64_t get_indexed_size(const Variant *base) { return 0; }
};
@@ -768,6 +774,7 @@ struct VariantIndexedSetGet_String {
}
}
static Variant::Type get_index_type() { return Variant::STRING; }
+ static uint32_t get_index_usage() { return PROPERTY_USAGE_DEFAULT; }
static uint64_t get_indexed_size(const Variant *base) { return VariantInternal::get_string(base)->length(); }
};
@@ -812,6 +819,7 @@ struct VariantIndexedSetGet_String {
v[index] = PtrToArg<Variant>::convert(member); \
} \
static Variant::Type get_index_type() { return Variant::NIL; } \
+ static uint32_t get_index_usage() { return PROPERTY_USAGE_DEFAULT; } \
static uint64_t get_indexed_size(const Variant *base) { return VariantGetInternalPtr<m_base_type>::get_ptr(base)->size(); } \
};
@@ -852,7 +860,8 @@ struct VariantIndexedSetterGetterInfo {
uint64_t (*get_indexed_size)(const Variant *base) = nullptr;
- Variant::Type index_type;
+ Variant::Type index_type = Variant::NIL;
+ uint32_t index_usage = PROPERTY_USAGE_DEFAULT;
bool valid = false;
};
@@ -872,6 +881,7 @@ static void register_indexed_member(Variant::Type p_type) {
sgi.ptr_getter = T::ptr_get;
sgi.index_type = T::get_index_type();
+ sgi.index_usage = T::get_index_usage();
sgi.get_indexed_size = T::get_indexed_size;
sgi.valid = true;
@@ -920,6 +930,11 @@ Variant::Type Variant::get_indexed_element_type(Variant::Type p_type) {
return variant_indexed_setters_getters[p_type].index_type;
}
+uint32_t Variant::get_indexed_element_usage(Variant::Type p_type) {
+ ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, PROPERTY_USAGE_DEFAULT);
+ return variant_indexed_setters_getters[p_type].index_usage;
+}
+
Variant::ValidatedIndexedSetter Variant::get_member_validated_indexed_setter(Variant::Type p_type) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
return variant_indexed_setters_getters[p_type].validated_setter;
@@ -1253,7 +1268,7 @@ bool Variant::iter_init(Variant &r_iter, bool &valid) const {
return _data._int > 0;
} break;
case FLOAT: {
- r_iter = 0;
+ r_iter = 0.0;
return _data._float > 0.0;
} break;
case VECTOR2: {
@@ -1457,7 +1472,7 @@ bool Variant::iter_next(Variant &r_iter, bool &valid) const {
return true;
} break;
case FLOAT: {
- int64_t idx = r_iter;
+ double idx = r_iter;
idx++;
if (idx >= _data._float) {
return false;
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index 41836650cd..7e7cb07cef 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -494,7 +494,7 @@
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns whether [code]x[/code] is a finite value, i.e. it is not [constant @GDScript.NAN], positive infinity, or negative infinity.
+ Returns whether [param x] is a finite value, i.e. it is not [constant @GDScript.NAN], positive infinity, or negative infinity.
</description>
</method>
<method name="is_inf">
@@ -529,7 +529,7 @@
<return type="bool" />
<param index="0" name="x" type="float" />
<description>
- Returns [code]true[/code] if [param x] is zero or almost zero.
+ Returns [code]true[/code] if [param x] is zero or almost zero. The comparison is done using a tolerance calculation with a small internal epsilon.
This function is faster than using [method is_equal_approx] with one value as zero.
</description>
</method>
diff --git a/doc/classes/AnimatedSprite2D.xml b/doc/classes/AnimatedSprite2D.xml
index e20fb71c7e..cd9c0cee98 100644
--- a/doc/classes/AnimatedSprite2D.xml
+++ b/doc/classes/AnimatedSprite2D.xml
@@ -7,7 +7,6 @@
[AnimatedSprite2D] is similar to the [Sprite2D] node, except it carries multiple textures as animation frames. Animations are created using a [SpriteFrames] resource, which allows you to import image files (or a folder containing said files) to provide the animation frames for the sprite. The [SpriteFrames] resource can be configured in the editor via the SpriteFrames bottom panel.
After setting up [member frames], [method play] may be called. It's also possible to select an [member animation] and toggle [member playing], even within the editor.
To pause the current animation, set [member playing] to [code]false[/code]. Alternatively, setting [member speed_scale] to [code]0[/code] also preserves the current frame's elapsed time.
- [b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
<link title="2D Sprite animation">$DOCS_URL/tutorials/2d/2d_sprite_animation.html</link>
diff --git a/doc/classes/AnimationNode.xml b/doc/classes/AnimationNode.xml
index a33ec2f6dc..6e3345b675 100644
--- a/doc/classes/AnimationNode.xml
+++ b/doc/classes/AnimationNode.xml
@@ -49,6 +49,13 @@
When inheriting from [AnimationRootNode], implement this virtual method to return whether the blend tree editor should display filter editing on this node.
</description>
</method>
+ <method name="_is_parameter_read_only" qualifiers="virtual const">
+ <return type="bool" />
+ <param index="0" name="parameter" type="StringName" />
+ <description>
+ When inheriting from [AnimationRootNode], implement this virtual method to return whether the [param parameter] is read-only. Parameters are custom local memory used for your nodes, given a resource can be reused in multiple trees.
+ </description>
+ </method>
<method name="_process" qualifiers="virtual const">
<return type="float" />
<param index="0" name="time" type="float" />
diff --git a/doc/classes/AnimationNodeOneShot.xml b/doc/classes/AnimationNodeOneShot.xml
index 14abc34992..9e8193868c 100644
--- a/doc/classes/AnimationNodeOneShot.xml
+++ b/doc/classes/AnimationNodeOneShot.xml
@@ -28,6 +28,12 @@
</member>
</members>
<constants>
+ <constant name="ONE_SHOT_REQUEST_NONE" value="0" enum="OneShotRequest">
+ </constant>
+ <constant name="ONE_SHOT_REQUEST_FIRE" value="1" enum="OneShotRequest">
+ </constant>
+ <constant name="ONE_SHOT_REQUEST_ABORT" value="2" enum="OneShotRequest">
+ </constant>
<constant name="MIX_MODE_BLEND" value="0" enum="MixMode">
</constant>
<constant name="MIX_MODE_ADD" value="1" enum="MixMode">
diff --git a/doc/classes/AnimationNodeStateMachinePlayback.xml b/doc/classes/AnimationNodeStateMachinePlayback.xml
index 8f53ef0dcf..7e01be12c4 100644
--- a/doc/classes/AnimationNodeStateMachinePlayback.xml
+++ b/doc/classes/AnimationNodeStateMachinePlayback.xml
@@ -50,11 +50,19 @@
Returns [code]true[/code] if an animation is playing.
</description>
</method>
+ <method name="next">
+ <return type="void" />
+ <description>
+ If there is a next path by travel or auto advance, immediately transitions from the current state to the next state.
+ </description>
+ </method>
<method name="start">
<return type="void" />
<param index="0" name="node" type="StringName" />
+ <param index="1" name="reset" type="bool" default="true" />
<description>
Starts playing the given animation.
+ If [param reset] is [code]true[/code], the animation is played from the beginning.
</description>
</method>
<method name="stop">
@@ -66,8 +74,11 @@
<method name="travel">
<return type="void" />
<param index="0" name="to_node" type="StringName" />
+ <param index="1" name="reset_on_teleport" type="bool" default="true" />
<description>
Transitions from the current state to another one, following the shortest path.
+ If the path does not connect from the current state, the animation will play after the state teleports.
+ If [param reset_on_teleport] is [code]true[/code], the animation is played from the beginning when the travel cause a teleportation.
</description>
</method>
</methods>
diff --git a/doc/classes/AnimationNodeStateMachineTransition.xml b/doc/classes/AnimationNodeStateMachineTransition.xml
index 814b2d0052..eee25fad7c 100644
--- a/doc/classes/AnimationNodeStateMachineTransition.xml
+++ b/doc/classes/AnimationNodeStateMachineTransition.xml
@@ -28,6 +28,9 @@
<member name="priority" type="int" setter="set_priority" getter="get_priority" default="1">
Lower priority transitions are preferred when travelling through the tree via [method AnimationNodeStateMachinePlayback.travel] or [member advance_mode] is set to [constant ADVANCE_MODE_AUTO].
</member>
+ <member name="reset" type="bool" setter="set_reset" getter="is_reset" default="true">
+ If [code]true[/code], the destination animation is played back from the beginning when switched.
+ </member>
<member name="switch_mode" type="int" setter="set_switch_mode" getter="get_switch_mode" enum="AnimationNodeStateMachineTransition.SwitchMode" default="0">
The transition type.
</member>
diff --git a/doc/classes/AnimationNodeTransition.xml b/doc/classes/AnimationNodeTransition.xml
index f6e2fc5eb2..bca94a568a 100644
--- a/doc/classes/AnimationNodeTransition.xml
+++ b/doc/classes/AnimationNodeTransition.xml
@@ -12,6 +12,12 @@
<link title="Third Person Shooter Demo">https://godotengine.org/asset-library/asset/678</link>
</tutorials>
<methods>
+ <method name="find_input_caption" qualifiers="const">
+ <return type="int" />
+ <param index="0" name="caption" type="String" />
+ <description>
+ </description>
+ </method>
<method name="get_input_caption" qualifiers="const">
<return type="String" />
<param index="0" name="input" type="int" />
@@ -43,7 +49,7 @@
<member name="enabled_inputs" type="int" setter="set_enabled_inputs" getter="get_enabled_inputs" default="0">
The number of enabled input ports for this node.
</member>
- <member name="from_start" type="bool" setter="set_from_start" getter="is_from_start" default="true">
+ <member name="reset" type="bool" setter="set_reset" getter="is_reset" default="true">
If [code]true[/code], the destination animation is played back from the beginning when switched.
</member>
<member name="xfade_curve" type="Curve" setter="set_xfade_curve" getter="get_xfade_curve">
diff --git a/doc/classes/AnimationPlayer.xml b/doc/classes/AnimationPlayer.xml
index ca0cbf0ca1..304caeef43 100644
--- a/doc/classes/AnimationPlayer.xml
+++ b/doc/classes/AnimationPlayer.xml
@@ -208,9 +208,11 @@
</method>
<method name="stop">
<return type="void" />
+ <param index="0" name="keep_state" type="bool" default="false" />
<description>
- Stops the currently playing animation. The animation position is reset to [code]0[/code] and the playback speed is reset to [code]1.0[/code].
- See also [method pause].
+ Stops the currently playing animation. The animation position is reset to [code]0[/code] and the playback speed is reset to [code]1.0[/code]. See also [method pause].
+ If [param keep_state] is [code]true[/code], the animation state is not updated visually.
+ [b]Note:[/b] The method / audio / animation playback tracks will not be processed by this method.
</description>
</method>
</methods>
diff --git a/doc/classes/Array.xml b/doc/classes/Array.xml
index 21ccf79fe2..ce4d7693d8 100644
--- a/doc/classes/Array.xml
+++ b/doc/classes/Array.xml
@@ -679,7 +679,7 @@
</description>
</operator>
<operator name="operator []">
- <return type="void" />
+ <return type="Variant" />
<param index="0" name="index" type="int" />
<description>
Returns a reference to the element of type [Variant] at the specified location. Arrays start at index 0. [param index] can be a zero or positive value to start from the beginning, or a negative value to start from the end. Out-of-bounds array access causes a run-time error, which will result in an error being printed and the project execution pausing if run from the editor.
diff --git a/doc/classes/ArrayMesh.xml b/doc/classes/ArrayMesh.xml
index f7764d5e32..7b86afcc4c 100644
--- a/doc/classes/ArrayMesh.xml
+++ b/doc/classes/ArrayMesh.xml
@@ -65,11 +65,15 @@
<param index="1" name="arrays" type="Array" />
<param index="2" name="blend_shapes" type="Array[]" default="[]" />
<param index="3" name="lods" type="Dictionary" default="{}" />
- <param index="4" name="compress_flags" type="int" enum="Mesh.ArrayFormat" default="0" />
- <description>
- Creates a new surface.
- Surfaces are created to be rendered using a [param primitive], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
- The [param arrays] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ <param index="4" name="flags" type="int" enum="Mesh.ArrayFormat" default="0" />
+ <description>
+ Creates a new surface. [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
+ Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType].
+ The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code].
+ The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents a LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of a LOD also increases the distance that the objects has to be from the camera before the LOD is used.
+ The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY].
+ [b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles.
</description>
</method>
<method name="clear_blend_shapes">
diff --git a/doc/classes/BackBufferCopy.xml b/doc/classes/BackBufferCopy.xml
index b2c5a1756f..be4a649b50 100644
--- a/doc/classes/BackBufferCopy.xml
+++ b/doc/classes/BackBufferCopy.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="BackBufferCopy" inherits="Node2D" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- 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.
+ Copies a region of the screen (or the whole screen) to a buffer so it can be accessed in your shader scripts using the screen texture (i.e. a uniform sampler with ``hint_screen_texture``).
</brief_description>
<description>
- 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.
+ 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 screen texture 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 aedb8f4420..68f62d1c00 100644
--- a/doc/classes/BaseButton.xml
+++ b/doc/classes/BaseButton.xml
@@ -70,7 +70,7 @@
[Shortcut] associated to the button.
</member>
<member name="shortcut_feedback" type="bool" setter="set_shortcut_feedback" getter="is_shortcut_feedback" default="true">
- If [code]true[/code], the button will appear pressed when its shortcut is activated. If [code]false[/code] and [member toggle_mode] is [code]false[/code], the shortcut will activate the button without appearing to press the button.
+ If [code]true[/code], the button will highlight for a short amount of time when its shortcut is activated. If [code]false[/code] and [member toggle_mode] is [code]false[/code], the shortcut will activate without any visual feedback.
</member>
<member name="shortcut_in_tooltip" type="bool" setter="set_shortcut_in_tooltip" getter="is_shortcut_in_tooltip_enabled" default="true">
If [code]true[/code], the button will add information about its shortcut in the tooltip.
diff --git a/doc/classes/BoneAttachment3D.xml b/doc/classes/BoneAttachment3D.xml
index f29525038e..dd01de3607 100644
--- a/doc/classes/BoneAttachment3D.xml
+++ b/doc/classes/BoneAttachment3D.xml
@@ -16,19 +16,6 @@
Returns the [NodePath] to the external [Skeleton3D] node, if one has been set.
</description>
</method>
- <method name="get_override_mode" qualifiers="const" is_deprecated="true">
- <return type="int" />
- <description>
- Deprecated. Local pose overrides will be removed.
- Returns the override mode for the BoneAttachment3D node (0=global / 1=local).
- </description>
- </method>
- <method name="get_override_pose" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the BoneAttachment3D node is overriding the bone pose of the bone it's attached to.
- </description>
- </method>
<method name="get_use_external_skeleton" qualifiers="const">
<return type="bool" />
<description>
@@ -49,21 +36,6 @@
Sets the [NodePath] to the external skeleton that the BoneAttachment3D node should use. The external [Skeleton3D] node is only used when [code]use_external_skeleton[/code] is set to [code]true[/code].
</description>
</method>
- <method name="set_override_mode" is_deprecated="true">
- <return type="void" />
- <param index="0" name="override_mode" type="int" />
- <description>
- Deprecated. Local pose overrides will be removed.
- Sets the override mode for the BoneAttachment3D node (0=global / 1=local). The override mode defines which of the bone poses the BoneAttachment3D node will override.
- </description>
- </method>
- <method name="set_override_pose">
- <return type="void" />
- <param index="0" name="override_pose" type="bool" />
- <description>
- Sets whether the BoneAttachment3D node will override the bone pose of the bone it is attached to. When set to [code]true[/code], the BoneAttachment3D node can change the pose of the bone.
- </description>
- </method>
<method name="set_use_external_skeleton">
<return type="void" />
<param index="0" name="use_external_skeleton" type="bool" />
@@ -79,5 +51,8 @@
<member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default="&quot;&quot;">
The name of the attached bone.
</member>
+ <member name="override_pose" type="bool" setter="set_override_pose" getter="get_override_pose" default="false">
+ Whether the BoneAttachment3D node will override the bone pose of the bone it is attached to. When set to [code]true[/code], the BoneAttachment3D node can change the pose of the bone. When set to [code]false[/code], the BoneAttachment3D will always be set to the bone's transform.
+ </member>
</members>
</class>
diff --git a/doc/classes/Callable.xml b/doc/classes/Callable.xml
index d1fdaef29c..79e65f3472 100644
--- a/doc/classes/Callable.xml
+++ b/doc/classes/Callable.xml
@@ -14,7 +14,7 @@
func test():
var callable = Callable(self, "print_args")
callable.call("hello", "world") # Prints "hello world ".
- callable.call(Vector2.UP, 42, callable) # Prints "(0, -1) 42 Node(Node.gd)::print_args".
+ callable.call(Vector2.UP, 42, callable) # Prints "(0, -1) 42 Node(node.gd)::print_args".
callable.call("invalid") # Invalid call, should have at least 2 arguments.
[/gdscript]
[csharp]
diff --git a/doc/classes/CanvasGroup.xml b/doc/classes/CanvasGroup.xml
index 37827defec..6eeff8fef3 100644
--- a/doc/classes/CanvasGroup.xml
+++ b/doc/classes/CanvasGroup.xml
@@ -9,8 +9,10 @@
[codeblock]
shader_type canvas_item;
+ uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a &gt; 0.0001) {
c.rgb /= c.a;
diff --git a/doc/classes/CanvasItem.xml b/doc/classes/CanvasItem.xml
index fbab1d76a0..c3c768c12d 100644
--- a/doc/classes/CanvasItem.xml
+++ b/doc/classes/CanvasItem.xml
@@ -42,10 +42,12 @@
<param index="3" name="end_angle" type="float" />
<param index="4" name="point_count" type="int" />
<param index="5" name="color" type="Color" />
- <param index="6" name="width" type="float" default="1.0" />
+ <param index="6" name="width" type="float" default="-1.0" />
<param index="7" name="antialiased" type="bool" default="false" />
<description>
- Draws a unfilled arc between the given angles. The larger the value of [param point_count], the smoother the curve. See also [method draw_circle].
+ Draws an unfilled arc between the given angles with a uniform [param color] and [param width] and optional antialiasing (supported only for positive [param width]). The larger the value of [param point_count], the smoother the curve. See also [method draw_circle].
+ If [param width] is negative, then the arc is drawn using [constant RenderingServer.PRIMITIVE_LINE_STRIP]. This means that when the CanvasItem is scaled, the arc will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
+ The arc is drawn from [param start_angle] towards the value of [param end_angle] so in clockwise direction if [code]start_angle &lt; end_angle[/code] and counter-clockwise otherwise. Passing the same angles but in reversed order will produce the same arc. If absolute difference of [param start_angle] and [param end_angle] is greater than [constant @GDScript.TAU] radians, then a full circle arc is drawn (i.e. arc will not overlap itself).
</description>
</method>
<method name="draw_char" qualifiers="const">
@@ -95,11 +97,12 @@
<param index="0" name="from" type="Vector2" />
<param index="1" name="to" type="Vector2" />
<param index="2" name="color" type="Color" />
- <param index="3" name="width" type="float" default="1.0" />
+ <param index="3" name="width" type="float" default="-1.0" />
<param index="4" name="dash" type="float" default="2.0" />
<param index="5" name="aligned" type="bool" default="true" />
<description>
Draws a dashed line from a 2D point to another, with a given color and width. See also [method draw_multiline] and [method draw_polyline].
+ If [param width] is negative, then a two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the line parts will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_end_animation">
@@ -130,10 +133,11 @@
<param index="0" name="from" type="Vector2" />
<param index="1" name="to" type="Vector2" />
<param index="2" name="color" type="Color" />
- <param index="3" name="width" type="float" default="1.0" />
+ <param index="3" name="width" type="float" default="-1.0" />
<param index="4" name="antialiased" type="bool" default="false" />
<description>
Draws a line from a 2D point to another, with a given color and width. It can be optionally antialiased. See also [method draw_multiline] and [method draw_polyline].
+ If [param width] is negative, then a two-point primitive will be drawn instead of a four-point one. This means that when the CanvasItem is scaled, the line will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_mesh">
@@ -165,18 +169,20 @@
<return type="void" />
<param index="0" name="points" type="PackedVector2Array" />
<param index="1" name="color" type="Color" />
- <param index="2" name="width" type="float" default="1.0" />
+ <param index="2" name="width" type="float" default="-1.0" />
<description>
Draws multiple disconnected lines with a uniform [param color]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline] instead.
+ If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_multiline_colors">
<return type="void" />
<param index="0" name="points" type="PackedVector2Array" />
<param index="1" name="colors" type="PackedColorArray" />
- <param index="2" name="width" type="float" default="1.0" />
+ <param index="2" name="width" type="float" default="-1.0" />
<description>
Draws multiple disconnected lines with a uniform [param width] and segment-by-segment coloring. Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw interconnected lines, use [method draw_polyline_colors] instead.
+ If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_multiline_string" qualifiers="const">
@@ -238,20 +244,22 @@
<return type="void" />
<param index="0" name="points" type="PackedVector2Array" />
<param index="1" name="color" type="Color" />
- <param index="2" name="width" type="float" default="1.0" />
+ <param index="2" name="width" type="float" default="-1.0" />
<param index="3" name="antialiased" type="bool" default="false" />
<description>
- Draws interconnected line segments with a uniform [param color] and [param width] and optional antialiasing. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon].
+ Draws interconnected line segments with a uniform [param color] and [param width] and optional antialiasing (supported only for positive [param width]). When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline] instead. See also [method draw_polygon].
+ If [param width] is negative, the polyline is drawn using [constant RenderingServer.PRIMITIVE_LINE_STRIP]. This means that when the CanvasItem is scaled, the polyline will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_polyline_colors">
<return type="void" />
<param index="0" name="points" type="PackedVector2Array" />
<param index="1" name="colors" type="PackedColorArray" />
- <param index="2" name="width" type="float" default="1.0" />
+ <param index="2" name="width" type="float" default="-1.0" />
<param index="3" name="antialiased" type="bool" default="false" />
<description>
- Draws interconnected line segments with a uniform [param width] and segment-by-segment coloring, and optional antialiasing. Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon].
+ Draws interconnected line segments with a uniform [param width] and segment-by-segment coloring, and optional antialiasing (supported only for positive [param width]). Colors assigned to line segments match by index between [param points] and [param colors]. When drawing large amounts of lines, this is faster than using individual [method draw_line] calls. To draw disconnected lines, use [method draw_multiline_colors] instead. See also [method draw_polygon].
+ If [param width] is negative, then the polyline is drawn using [constant RenderingServer.PRIMITIVE_LINE_STRIP]. This means that when the CanvasItem is scaled, the polyline will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
</description>
</method>
<method name="draw_primitive">
@@ -260,7 +268,6 @@
<param index="1" name="colors" type="PackedColorArray" />
<param index="2" name="uvs" type="PackedVector2Array" />
<param index="3" name="texture" type="Texture2D" default="null" />
- <param index="4" name="width" type="float" default="1.0" />
<description>
Draws a custom primitive. 1 point for a point, 2 points for a line, 3 points for a triangle, and 4 points for a quad. If 0 points or more than 4 points are specified, nothing will be drawn and an error message will be printed. See also [method draw_line], [method draw_polyline], [method draw_polygon], and [method draw_rect].
</description>
@@ -270,10 +277,12 @@
<param index="0" name="rect" type="Rect2" />
<param index="1" name="color" type="Color" />
<param index="2" name="filled" type="bool" default="true" />
- <param index="3" name="width" type="float" default="1.0" />
+ <param index="3" name="width" type="float" default="-1.0" />
<description>
Draws a rectangle. If [param filled] is [code]true[/code], the rectangle will be filled with the [param color] specified. If [param filled] is [code]false[/code], the rectangle will be drawn as a stroke with the [param color] and [param width] specified.
+ If [param width] is negative, then two-point primitives will be drawn instead of a four-point ones. This means that when the CanvasItem is scaled, the lines will remain thin. If this behavior is not desired, then pass a positive [param width] like [code]1.0[/code].
[b]Note:[/b] [param width] is only effective if [param filled] is [code]false[/code].
+ [b]Note:[/b] Unfilled rectangles drawn with a negative [param width] may not display perfectly. For example, corners may be missing or brighter due to overlapping lines (for a translucent [param color]).
</description>
</method>
<method name="draw_set_transform">
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index 3ceb8967a0..df40d2a4cf 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -132,12 +132,6 @@
Perform an indent as if the user activated the "ui_text_indent" action.
</description>
</method>
- <method name="do_unindent">
- <return type="void" />
- <description>
- Perform an unindent as if the user activated the "ui_text_unindent" action.
- </description>
- </method>
<method name="fold_all_lines">
<return type="void" />
<description>
@@ -423,7 +417,7 @@
<method name="unindent_lines">
<return type="void" />
<description>
- Unindents selected lines, or in the case of no selection the caret line by one.
+ Unindents selected lines, or in the case of no selection the caret line by one. Same as performing "ui_text_unindent" action.
</description>
</method>
<method name="update_code_completion_options">
diff --git a/doc/classes/CollisionObject3D.xml b/doc/classes/CollisionObject3D.xml
index c302963b92..31b5842930 100644
--- a/doc/classes/CollisionObject3D.xml
+++ b/doc/classes/CollisionObject3D.xml
@@ -216,13 +216,13 @@
<signal name="mouse_entered">
<description>
Emitted when the mouse pointer enters any of this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
- [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject2D]'s area is small. This signal may also not be emitted if another [CollisionObject2D] is overlapping the [CollisionObject2D] in question.
+ [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject3D]'s area is small. This signal may also not be emitted if another [CollisionObject3D] is overlapping the [CollisionObject3D] in question.
</description>
</signal>
<signal name="mouse_exited">
<description>
Emitted when the mouse pointer exits all this object's shapes. Requires [member input_ray_pickable] to be [code]true[/code] and at least one [member collision_layer] bit to be set.
- [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject2D]'s area is small. This signal may also not be emitted if another [CollisionObject2D] is overlapping the [CollisionObject2D] in question.
+ [b]Note:[/b] Due to the lack of continuous collision detection, this signal may not be emitted in the expected order if the mouse moves fast enough and the [CollisionObject3D]'s area is small. This signal may also not be emitted if another [CollisionObject3D] is overlapping the [CollisionObject3D] in question.
</description>
</signal>
</signals>
@@ -232,7 +232,7 @@
Automatically re-added to the physics simulation when the [Node] is processed again.
</constant>
<constant name="DISABLE_MODE_MAKE_STATIC" value="1" enum="DisableMode">
- When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area2D]. [PhysicsBody3D] can't be affected by forces or other bodies while static.
+ When [member Node.process_mode] is set to [constant Node.PROCESS_MODE_DISABLED], make the body static. Doesn't affect [Area3D]. [PhysicsBody3D] can't be affected by forces or other bodies while static.
Automatically set [PhysicsBody3D] back to its original mode when the [Node] is processed again.
</constant>
<constant name="DISABLE_MODE_KEEP_ACTIVE" value="2" enum="DisableMode">
diff --git a/doc/classes/Control.xml b/doc/classes/Control.xml
index 08964cf21d..7082eff97d 100644
--- a/doc/classes/Control.xml
+++ b/doc/classes/Control.xml
@@ -180,14 +180,14 @@
[codeblocks]
[gdscript]
func _make_custom_tooltip(for_text):
- var tooltip = preload("res://SomeTooltipScene.tscn").instantiate()
+ var tooltip = preload("res://some_tooltip_scene.tscn").instantiate()
tooltip.get_node("Label").text = for_text
return tooltip
[/gdscript]
[csharp]
public override Godot.Control _MakeCustomTooltip(String forText)
{
- Node tooltip = ResourceLoader.Load&lt;PackedScene&gt;("res://SomeTooltipScene.tscn").Instantiate();
+ Node tooltip = ResourceLoader.Load&lt;PackedScene&gt;("res://some_tooltip_scene.tscn").Instantiate();
tooltip.GetNode&lt;Label&gt;("Label").Text = forText;
return tooltip;
}
@@ -196,12 +196,12 @@
</description>
</method>
<method name="_structured_text_parser" qualifiers="virtual const">
- <return type="Vector2i[]" />
+ <return type="Vector3i[]" />
<param index="0" name="args" type="Array" />
<param index="1" name="text" type="String" />
<description>
User defined BiDi algorithm override function.
- Returns an [Array] of [Vector2i] text ranges, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately.
+ Returns an [Array] of [Vector3i] text ranges and text base directions, in the left-to-right order. Ranges should cover full source [param text] without overlaps. BiDi algorithm will be used on each range separately.
</description>
</method>
<method name="accept_event">
diff --git a/doc/classes/ConvexPolygonShape3D.xml b/doc/classes/ConvexPolygonShape3D.xml
index 32dc8f673b..66d2280280 100644
--- a/doc/classes/ConvexPolygonShape3D.xml
+++ b/doc/classes/ConvexPolygonShape3D.xml
@@ -4,7 +4,7 @@
Convex polygon shape resource for 3D physics.
</brief_description>
<description>
- 3D convex polygon shape resource to be added as a [i]direct[/i] child of a [PhysicsBody3D] or [Area3D] using a [CollisionShape3D] node. Unlike [ConcavePolygonShape3D], [ConvexPolygonShape3D] cannot store concave polygon shapes. [ConvexPolygonShape2D]s can be manually drawn in the editor using the [CollisionPolygon3D] node.
+ 3D convex polygon shape resource to be added as a [i]direct[/i] child of a [PhysicsBody3D] or [Area3D] using a [CollisionShape3D] node. Unlike [ConcavePolygonShape3D], [ConvexPolygonShape3D] cannot store concave polygon shapes. [ConvexPolygonShape3D]s can be manually drawn in the editor using the [CollisionPolygon3D] node.
[b]Convex decomposition:[/b] Concave objects' collisions can be represented accurately using [i]several[/i] [ConvexPolygonShape3D]s. This allows dynamic physics bodies to have complex concave collisions (at a performance cost). This is available in the editor by selecting the [MeshInstance3D], going to the [b]Mesh[/b] menu and choosing [b]Create Multiple Convex Collision Siblings[/b]. Alternatively, [method MeshInstance3D.create_multiple_convex_collisions] can be called in a script to perform this decomposition at run-time.
[b]Performance:[/b] [ConvexPolygonShape3D] is faster to check collisions against compared to [ConcavePolygonShape3D], but it is slower than primitive collision shapes such as [SphereShape3D] or [BoxShape3D]. Its use should generally be limited to medium-sized objects that cannot have their collision accurately represented by a primitive shape.
</description>
diff --git a/doc/classes/DTLSServer.xml b/doc/classes/DTLSServer.xml
index 9af8be99ef..457513b8aa 100644
--- a/doc/classes/DTLSServer.xml
+++ b/doc/classes/DTLSServer.xml
@@ -8,7 +8,7 @@
Below a small example of how to use it:
[codeblocks]
[gdscript]
- # ServerNode.gd
+ # server_node.gd
extends Node
var dtls := DTLSServer.new()
@@ -86,7 +86,7 @@
[/codeblocks]
[codeblocks]
[gdscript]
- # ClientNode.gd
+ # client_node.gd
extends Node
var dtls := PacketPeerDTLS.new()
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 5da6cf8102..832adb6e98 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1694,7 +1694,10 @@
Use [method window_get_safe_title_margins] to determine area under the title bar that is not covered by decorations.
[b]Note:[/b] This flag is implemented on macOS.
</constant>
- <constant name="WINDOW_FLAG_MAX" value="7" enum="WindowFlags">
+ <constant name="WINDOW_FLAG_MOUSE_PASSTHROUGH" value="7" enum="WindowFlags">
+ All mouse events are passed to the underlying window of the same application.
+ </constant>
+ <constant name="WINDOW_FLAG_MAX" value="8" enum="WindowFlags">
Max value of the [enum WindowFlags].
</constant>
<constant name="WINDOW_EVENT_MOUSE_ENTER" value="0" enum="WindowEvent">
diff --git a/doc/classes/EditorFileSystem.xml b/doc/classes/EditorFileSystem.xml
index e8df6ae7fe..5f33c68a7d 100644
--- a/doc/classes/EditorFileSystem.xml
+++ b/doc/classes/EditorFileSystem.xml
@@ -71,12 +71,6 @@
This will not import the file. To reimport, call [method reimport_files] or [method scan] methods.
</description>
</method>
- <method name="update_script_classes">
- <return type="void" />
- <description>
- Scans the script files and updates the list of custom class names.
- </description>
- </method>
</methods>
<signals>
<signal name="filesystem_changed">
@@ -96,6 +90,11 @@
Emitted if at least one resource is reloaded when the filesystem is scanned.
</description>
</signal>
+ <signal name="script_classes_updated">
+ <description>
+ Emitted when the list of global script classes gets updated.
+ </description>
+ </signal>
<signal name="sources_changed">
<param index="0" name="exist" type="bool" />
<description>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index b44c1d7ffa..370be8e9f3 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -143,7 +143,7 @@
[gdscript]
func _forward_canvas_draw_over_viewport(overlay):
# Draw a circle at cursor position.
- overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.white)
+ overlay.draw_circle(overlay.get_local_mouse_position(), 64, Color.WHITE)
func _forward_canvas_gui_input(event):
if event is InputEventMouseMotion:
@@ -347,7 +347,7 @@
[codeblock]
func _set_state(data):
zoom = data.get("zoom", 1.0)
- preferred_color = data.get("my_color", Color.white)
+ preferred_color = data.get("my_color", Color.WHITE)
[/codeblock]
</description>
</method>
@@ -359,7 +359,7 @@
[codeblock]
func _set_window_layout(configuration):
$Window.position = configuration.get_value("MyPlugin", "window_position", Vector2())
- $Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.white)
+ $Icon.modulate = configuration.get_value("MyPlugin", "icon_color", Color.WHITE)
[/codeblock]
</description>
</method>
@@ -467,6 +467,14 @@
See [method add_inspector_plugin] for an example of how to register a plugin.
</description>
</method>
+ <method name="add_resource_conversion_plugin">
+ <return type="void" />
+ <param index="0" name="plugin" type="EditorResourceConversionPlugin" />
+ <description>
+ Registers a new [EditorResourceConversionPlugin]. Resource conversion plugins are used to add custom resource converters to the editor inspector.
+ See [EditorResourceConversionPlugin] for an example of how to create a resource conversion plugin.
+ </description>
+ </method>
<method name="add_scene_format_importer_plugin">
<return type="void" />
<param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
@@ -632,6 +640,13 @@
Removes a gizmo plugin registered by [method add_node_3d_gizmo_plugin].
</description>
</method>
+ <method name="remove_resource_conversion_plugin">
+ <return type="void" />
+ <param index="0" name="plugin" type="EditorResourceConversionPlugin" />
+ <description>
+ Removes a resource conversion plugin registered by [method add_resource_conversion_plugin].
+ </description>
+ </method>
<method name="remove_scene_format_importer_plugin">
<return type="void" />
<param index="0" name="scene_format_importer" type="EditorSceneFormatImporter" />
diff --git a/doc/classes/EditorResourceConversionPlugin.xml b/doc/classes/EditorResourceConversionPlugin.xml
index c40bb1d91e..6bdfbbe40c 100644
--- a/doc/classes/EditorResourceConversionPlugin.xml
+++ b/doc/classes/EditorResourceConversionPlugin.xml
@@ -1,8 +1,28 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="EditorResourceConversionPlugin" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ Plugin for adding custom converters from one resource format to another in the editor resource picker context menu; for example, converting a [StandardMaterial3D] to a [ShaderMaterial].
</brief_description>
<description>
+ [EditorResourceConversionPlugin] is invoked when the context menu is brought up for a resource in the editor inspector. Relevant conversion plugins will appear as menu options to convert the given resource to a target type.
+ Below shows an example of a basic plugin that will convert an [ImageTexture] to a [PortableCompressedTexture2D].
+ [codeblocks]
+ [gdscript]
+ extends EditorResourceConversionPlugin
+
+ func _handles(resource : Resource):
+ return resource is ImageTexture
+
+ func _converts_to():
+ return "PortableCompressedTexture2D"
+
+ func _convert(itex : Resource):
+ var ptex = PortableCompressedTexture2D.new()
+ ptex.create_from_image(itex.get_image(), PortableCompressedTexture2D.COMPRESSION_MODE_LOSSLESS)
+ return ptex
+ [/gdscript]
+ [/codeblocks]
+ To use an [EditorResourceConversionPlugin], register it using the [method EditorPlugin.add_resource_conversion_plugin] method first.
</description>
<tutorials>
</tutorials>
@@ -11,17 +31,20 @@
<return type="Resource" />
<param index="0" name="resource" type="Resource" />
<description>
+ Takes an input [Resource] and converts it to the type given in [method _converts_to]. The returned [Resource] is the result of the conversion, and the input [Resource] remains unchanged.
</description>
</method>
<method name="_converts_to" qualifiers="virtual const">
<return type="String" />
<description>
+ Returns the class name of the target type of [Resource] that this plugin converts source resources to.
</description>
</method>
<method name="_handles" qualifiers="virtual const">
<return type="bool" />
<param index="0" name="resource" type="Resource" />
<description>
+ Called to determine whether a particular [Resource] can be converted to the target resource type by this plugin.
</description>
</method>
</methods>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index 98f4789163..fca87f6a56 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -499,7 +499,7 @@
</member>
<member name="interface/editor/editor_language" type="String" setter="" getter="">
The language to use for the editor interface.
- Translations are provided by the community. If you spot a mistake, [url=https://docs.godotengine.org/en/latest/community/contributing/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url]
+ Translations are provided by the community. If you spot a mistake, [url=$DOCS_URL/contributing/documentation/editor_and_docs_localization.html]contribute to editor translations on Weblate![/url]
</member>
<member name="interface/editor/expand_to_title" type="bool" setter="" getter="">
Expanding main editor window content to the title, if supported by [DisplayServer]. See [constant DisplayServer.WINDOW_FLAG_EXTEND_TO_TITLE].
@@ -741,7 +741,7 @@
</member>
<member name="text_editor/behavior/indent/type" type="int" setter="" getter="">
The indentation style to use (tabs or spaces).
- [b]Note:[/b] The [url=https://docs.godotengine.org/en/latest/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation.
+ [b]Note:[/b] The [url=$DOCS_URL/getting_started/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url] recommends using tabs for indentation. It is advised to change this setting only if you need to work on a project that currently uses spaces for indentation.
</member>
<member name="text_editor/behavior/navigation/drag_and_drop_selection" type="bool" setter="" getter="">
If [code]true[/code], allows drag-and-dropping text in the script editor to move text. Disable this if you find yourself accidentally drag-and-dropping text in the script editor.
@@ -782,7 +782,7 @@
If [code]true[/code], the code completion tooltip will appear below the current line unless there is no space on screen below the current line. If [code]false[/code], the code completion tooltip will appear above the current line.
</member>
<member name="text_editor/completion/use_single_quotes" type="bool" setter="" getter="">
- If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]).
+ If [code]true[/code], performs string autocompletion with single quotes. If [code]false[/code], performs string autocompletion with double quotes (which matches the [url=$DOCS_URL/tutorials/scripting/gdscript/gdscript_styleguide.html]GDScript style guide[/url]).
</member>
<member name="text_editor/help/class_reference_examples" type="int" setter="" getter="">
Controls which multi-line code blocks should be displayed in the editor help. This setting does not affect single-line code literals in the editor help.
diff --git a/doc/classes/EditorUndoRedoManager.xml b/doc/classes/EditorUndoRedoManager.xml
index cd96e740e8..4d6938e6aa 100644
--- a/doc/classes/EditorUndoRedoManager.xml
+++ b/doc/classes/EditorUndoRedoManager.xml
@@ -1,5 +1,5 @@
<?xml version="1.0" encoding="UTF-8" ?>
-<class name="EditorUndoRedoManager" inherits="RefCounted" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
+<class name="EditorUndoRedoManager" inherits="Object" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
Manages undo history of scenes opened in the editor.
</brief_description>
diff --git a/doc/classes/GeometryInstance3D.xml b/doc/classes/GeometryInstance3D.xml
index 1ae4718536..127c5daf95 100644
--- a/doc/classes/GeometryInstance3D.xml
+++ b/doc/classes/GeometryInstance3D.xml
@@ -21,7 +21,10 @@
<param index="0" name="name" type="StringName" />
<param index="1" name="value" type="Variant" />
<description>
- Set the value of a shader parameter for this instance only.
+ Set the value of a shader uniform for this instance only ([url=$DOCS_URL/tutorials/shaders/shader_reference/shading_language.html#per-instance-uniforms]per-instance uniform[/url]). See also [method ShaderMaterial.set_shader_parameter] to assign a uniform on all instances using the same [ShaderMaterial].
+ [b]Note:[/b] For a shader uniform to be assignable on a per-instance basis, it [i]must[/i] be defined with [code]instance uniform ...[/code] rather than [code]uniform ...[/code] in the shader code.
+ [b]Note:[/b] [param name] is case-sensitive and must match the name of the uniform in the code exactly (not the capitalized name in the inspector).
+ [b]Note:[/b] Per-instance shader uniforms are currently only available in 3D, so there is no 2D equivalent of this method.
</description>
</method>
</methods>
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index ed1b40488e..051e087611 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -489,7 +489,7 @@
var img = Image.new()
img.create(img_width, img_height, false, Image.FORMAT_RGBA8)
- img.set_pixel(1, 2, Color.red) # Sets the color at (1, 2) to red.
+ img.set_pixel(1, 2, Color.RED) # Sets the color at (1, 2) to red.
[/gdscript]
[csharp]
int imgWidth = 10;
@@ -517,7 +517,7 @@
var img = Image.new()
img.create(img_width, img_height, false, Image.FORMAT_RGBA8)
- img.set_pixelv(Vector2i(1, 2), Color.red) # Sets the color at (1, 2) to red.
+ img.set_pixelv(Vector2i(1, 2), Color.RED) # Sets the color at (1, 2) to red.
[/gdscript]
[csharp]
int imgWidth = 10;
diff --git a/doc/classes/ImporterMesh.xml b/doc/classes/ImporterMesh.xml
index b80857a7bf..10479dfcfe 100644
--- a/doc/classes/ImporterMesh.xml
+++ b/doc/classes/ImporterMesh.xml
@@ -27,9 +27,13 @@
<param index="5" name="name" type="String" default="&quot;&quot;" />
<param index="6" name="flags" type="int" default="0" />
<description>
- Creates a new surface, analogous to [method ArrayMesh.add_surface_from_arrays].
- Surfaces are created to be rendered using a [param primitive], which may be any of the types defined in [enum Mesh.PrimitiveType]. (As a note, when using indices, it is recommended to only use points, lines, or triangles.) [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
- The [param arrays] argument is an array of arrays. See [enum Mesh.ArrayType] for the values used in this array. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this function into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ Creates a new surface. [method Mesh.get_surface_count] will become the [code]surf_idx[/code] for this new surface.
+ Surfaces are created to be rendered using a [param primitive], which may be any of the values defined in [enum Mesh.PrimitiveType].
+ The [param arrays] argument is an array of arrays. Each of the [constant Mesh.ARRAY_MAX] elements contains an array with some of the mesh data for this surface as described by the corresponding member of [enum Mesh.ArrayType] or [code]null[/code] if it is not used by the surface. For example, [code]arrays[0][/code] is the array of vertices. That first vertex sub-array is always required; the others are optional. Adding an index array puts this surface into "index mode" where the vertex and other arrays become the sources of data and the index array defines the vertex order. All sub-arrays must have the same length as the vertex array (or be an exact multiple of the vertex array's length, when multiple elements of a sub-array correspond to a single vertex) or be empty, except for [constant Mesh.ARRAY_INDEX] if it is used.
+ The [param blend_shapes] argument is an array of vertex data for each blend shape. Each element is an array of the same structure as [param arrays], but [constant Mesh.ARRAY_VERTEX], [constant Mesh.ARRAY_NORMAL], and [constant Mesh.ARRAY_TANGENT] are set if and only if they are set in [param arrays] and all other entries are [code]null[/code].
+ The [param lods] argument is a dictionary with [float] keys and [PackedInt32Array] values. Each entry in the dictionary represents a LOD level of the surface, where the value is the [constant Mesh.ARRAY_INDEX] array to use for the LOD level and the key is roughly proportional to the distance at which the LOD stats being used. I.e., increasing the key of a LOD also increases the distance that the objects has to be from the camera before the LOD is used.
+ The [param flags] argument is the bitwise or of, as required: One value of [enum Mesh.ArrayCustomFormat] left shifted by [code]ARRAY_FORMAT_CUSTOMn_SHIFT[/code] for each custom channel in use, [constant Mesh.ARRAY_FLAG_USE_DYNAMIC_UPDATE], [constant Mesh.ARRAY_FLAG_USE_8_BONE_WEIGHTS], or [constant Mesh.ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY].
+ [b]Note:[/b] When using indices, it is recommended to only use points, lines, or triangles.
</description>
</method>
<method name="clear">
diff --git a/doc/classes/Input.xml b/doc/classes/Input.xml
index a0d2d93a7d..6ecf903fde 100644
--- a/doc/classes/Input.xml
+++ b/doc/classes/Input.xml
@@ -297,6 +297,7 @@
[param hotspot] must be within [param image]'s size.
[b]Note:[/b] [AnimatedTexture]s aren't supported as custom mouse cursors. If using an [AnimatedTexture], only the first frame will be displayed.
[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or [b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] compression mode can't be used for custom cursors.
+ [b]Note:[/b] On the web platform, the maximum allowed cursor image size is 128×128. Cursor images larger than 32×32 will also only be displayed if the mouse cursor image is entirely located within the page for [url=https://chromestatus.com/feature/5825971391299584]security reasons[/url].
</description>
</method>
<method name="set_default_cursor_shape">
diff --git a/doc/classes/JavaScriptBridge.xml b/doc/classes/JavaScriptBridge.xml
index 340c296eef..f79c11b334 100644
--- a/doc/classes/JavaScriptBridge.xml
+++ b/doc/classes/JavaScriptBridge.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
The JavaScriptBridge singleton is implemented only in the Web export. It's used to access the browser's JavaScript context. This allows interaction with embedding pages or calling third-party JavaScript APIs.
- [b]Note:[/b] This singleton can be disabled at build-time to improve security. By default, the JavaScriptBridge singleton is enabled. Official export templates also have the JavaScriptBridge singleton enabled. See [url=$DOCS_URL/development/compiling/compiling_for_web.html]Compiling for the Web[/url] in the documentation for more information.
+ [b]Note:[/b] This singleton can be disabled at build-time to improve security. By default, the JavaScriptBridge singleton is enabled. Official export templates also have the JavaScriptBridge singleton enabled. See [url=$DOCS_URL/contributing/development/compiling/compiling_for_web.html]Compiling for the Web[/url] in the documentation for more information.
</description>
<tutorials>
<link title="Exporting for the Web: Calling JavaScript from script">$DOCS_URL/tutorials/export/exporting_for_web.html#calling-javascript-from-script</link>
diff --git a/doc/classes/Mesh.xml b/doc/classes/Mesh.xml
index 94e80ffb2b..1c1f48588f 100644
--- a/doc/classes/Mesh.xml
+++ b/doc/classes/Mesh.xml
@@ -227,10 +227,10 @@
Contains custom color channel 3. [PackedByteArray] if [code](format &gt;&gt; [constant ARRAY_FORMAT_CUSTOM3_SHIFT]) &amp; [constant ARRAY_FORMAT_CUSTOM_MASK])[/code] is [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RGBA8_UNORM], [constant ARRAY_CUSTOM_RG_HALF] or [constant ARRAY_CUSTOM_RGBA_HALF]. [PackedFloat32Array] otherwise.
</constant>
<constant name="ARRAY_BONES" value="10" enum="ArrayType">
- [PackedFloat32Array] or [PackedInt32Array] of bone indices. Each element is a group of 4 numbers.
+ [PackedFloat32Array] or [PackedInt32Array] of bone indices. Contains either 4 or 8 numbers per vertex depending on the presence of the [constant ARRAY_FLAG_USE_8_BONE_WEIGHTS] flag.
</constant>
<constant name="ARRAY_WEIGHTS" value="11" enum="ArrayType">
- [PackedFloat32Array] of bone weights. Each element in groups of 4 floats.
+ [PackedFloat32Array] or [PackedFloat64Array] of bone weights in the range [code]0.0[/code] to [code]1.0[/code] (inclusive). Contains either 4 or 8 numbers per vertex depending on the presence of the [constant ARRAY_FLAG_USE_8_BONE_WEIGHTS] flag.
</constant>
<constant name="ARRAY_INDEX" value="12" enum="ArrayType">
[PackedInt32Array] of integers used as indices referencing vertices, colors, normals, tangents, and textures. All of those arrays must have the same number of elements as the vertex array. No index can be beyond the vertex array size. When this index array is present, it puts the function into "index mode," where the index selects the *i*'th vertex, normal, tangent, color, UV, etc. This means if you want to have different normals or colors along an edge, you have to duplicate the vertices.
@@ -341,6 +341,9 @@
<constant name="ARRAY_FLAG_USE_8_BONE_WEIGHTS" value="134217728" enum="ArrayFormat" is_bitfield="true">
Flag used to mark that the mesh contains up to 8 bone influences per vertex. This flag indicates that [constant ARRAY_BONES] and [constant ARRAY_WEIGHTS] elements will have double length.
</constant>
+ <constant name="ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY" value="268435456" enum="ArrayFormat" is_bitfield="true">
+ Flag used to mark that the mesh intentionally contains no vertex array.
+ </constant>
<constant name="BLEND_SHAPE_MODE_NORMALIZED" value="0" enum="BlendShapeMode">
Blend shapes are normalized.
</constant>
diff --git a/doc/classes/OS.xml b/doc/classes/OS.xml
index 6dab7b4ebe..1bc81ffb42 100644
--- a/doc/classes/OS.xml
+++ b/doc/classes/OS.xml
@@ -592,12 +592,12 @@
</description>
</method>
<method name="set_environment" qualifiers="const">
- <return type="bool" />
+ <return type="void" />
<param index="0" name="variable" type="String" />
<param index="1" name="value" type="String" />
<description>
Sets the value of the environment variable [param variable] to [param value]. The environment variable will be set for the Godot process and any process executed with [method execute] after running [method set_environment]. The environment variable will [i]not[/i] persist to processes run after the Godot process was terminated.
- [b]Note:[/b] Double-check the casing of [param variable]. Environment variable names are case-sensitive on all platforms except Windows.
+ [b]Note:[/b] Environment variable names are case-sensitive on all platforms except Windows. The [param variable] name cannot be empty or include the [code]=[/code] character. On Windows, there is a 32767 characters limit for the combined length of [param variable], [param value], and the [code]=[/code] and null terminator characters that will be registered in the environment block.
</description>
</method>
<method name="set_restart_on_exit">
@@ -637,6 +637,14 @@
[b]Note:[/b] This method is implemented on Android, iOS, Web, Linux, macOS and Windows.
</description>
</method>
+ <method name="unset_environment" qualifiers="const">
+ <return type="void" />
+ <param index="0" name="variable" type="String" />
+ <description>
+ Removes the environment [param variable] from the current environment, if it exists. The environment variable will be removed for the Godot process and any process executed with [method execute] after running [method unset_environment]. The removal of the environment variable will [i]not[/i] persist to processes run after the Godot process was terminated.
+ [b]Note:[/b] Environment variable names are case-sensitive on all platforms except Windows. The [param variable] name cannot be empty or include the [code]=[/code] character.
+ </description>
+ </method>
</methods>
<members>
<member name="low_processor_usage_mode" type="bool" setter="set_low_processor_usage_mode" getter="is_in_low_processor_usage_mode" default="false">
diff --git a/doc/classes/Object.xml b/doc/classes/Object.xml
index e015bec134..a9e17f4666 100644
--- a/doc/classes/Object.xml
+++ b/doc/classes/Object.xml
@@ -24,6 +24,7 @@
[b]Note:[/b] The [code]script[/code] is not exposed like most properties. To set or get an object's [Script] in code, use [method set_script] and [method get_script], respectively.
</description>
<tutorials>
+ <link title="Object class introduction">$DOCS_URL/contributing/development/core_and_modules/object_class.html</link>
<link title="When and how to avoid using nodes for everything">$DOCS_URL/tutorials/best_practices/node_alternatives.html</link>
<link title="Object notifications">$DOCS_URL/tutorials/best_practices/godot_notifications.html</link>
</tutorials>
diff --git a/doc/classes/PhysicsServer3DManager.xml b/doc/classes/PhysicsServer3DManager.xml
index 3ec03fede4..4d789ceb3f 100644
--- a/doc/classes/PhysicsServer3DManager.xml
+++ b/doc/classes/PhysicsServer3DManager.xml
@@ -15,7 +15,7 @@
<param index="0" name="name" type="String" />
<param index="1" name="create_callback" type="Callable" />
<description>
- Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer2D] object.
+ Register a [PhysicsServer3D] implementation by passing a [param name] and a [Callable] that returns a [PhysicsServer3D] object.
</description>
</method>
<method name="set_default_server">
diff --git a/doc/classes/Plane.xml b/doc/classes/Plane.xml
index fbe8afa8d1..aa09081e3e 100644
--- a/doc/classes/Plane.xml
+++ b/doc/classes/Plane.xml
@@ -38,6 +38,7 @@
<param index="0" name="normal" type="Vector3" />
<description>
Creates a plane from the normal vector. The plane will intersect the origin.
+ The [param normal] of the plane must be a unit vector.
</description>
</constructor>
<constructor name="Plane">
@@ -46,6 +47,7 @@
<param index="1" name="d" type="float" />
<description>
Creates a plane from the normal vector and the plane's distance from the origin.
+ The [param normal] of the plane must be a unit vector.
</description>
</constructor>
<constructor name="Plane">
@@ -54,6 +56,7 @@
<param index="1" name="point" type="Vector3" />
<description>
Creates a plane from the normal vector and a point on the plane.
+ The [param normal] of the plane must be a unit vector.
</description>
</constructor>
<constructor name="Plane">
@@ -67,12 +70,6 @@
</constructor>
</constructors>
<methods>
- <method name="center" qualifiers="const">
- <return type="Vector3" />
- <description>
- Returns the center of the plane.
- </description>
- </method>
<method name="distance_to" qualifiers="const">
<return type="float" />
<param index="0" name="point" type="Vector3" />
@@ -80,6 +77,12 @@
Returns the shortest distance from the plane to the position [param point]. If the point is above the plane, the distance will be positive. If below, the distance will be negative.
</description>
</method>
+ <method name="get_center" qualifiers="const">
+ <return type="Vector3" />
+ <description>
+ Returns the center of the plane.
+ </description>
+ </method>
<method name="has_point" qualifiers="const">
<return type="bool" />
<param index="0" name="point" type="Vector3" />
@@ -152,7 +155,7 @@
In the scalar equation of the plane [code]ax + by + cz = d[/code], this is [code]d[/code], while the [code](a, b, c)[/code] coordinates are represented by the [member normal] property.
</member>
<member name="normal" type="Vector3" setter="" getter="" default="Vector3(0, 0, 0)">
- The normal of the plane, which must be normalized.
+ The normal of the plane, which must be a unit vector.
In the scalar equation of the plane [code]ax + by + cz = d[/code], this is the vector [code](a, b, c)[/code], where [code]d[/code] is the [member d] property.
</member>
<member name="x" type="float" setter="" getter="" default="0.0">
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index f954e8bca8..de41edc305 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -652,6 +652,13 @@
See [enum DisplayServer.VSyncMode] for possible values and how they affect the behavior of your application.
Depending on the platform and used renderer, the engine will fall back to [code]Enabled[/code], if the desired mode is not supported.
</member>
+ <member name="dotnet/project/assembly_name" type="String" setter="" getter="" default="&quot;&quot;">
+ Name of the .NET assembly. This name is used as the name of the [code].csproj[/code] and [code].sln[/code] files. By default, it's set to the name of the project ([member application/config/name]) allowing to change it in the future without affecting the .NET assembly.
+ </member>
+ <member name="dotnet/project/solution_directory" type="String" setter="" getter="" default="&quot;&quot;">
+ Directory that contains the [code].sln[/code] file. By default, the [code].sln[/code] files is in the root of the project directory, next to the [code]project.godot[/code] and [code].csproj[/code] files.
+ Changing this value allows setting up a multi-project scenario where there are multiple [code].csproj[/code]. Keep in mind that the Godot project is considered one of the C# projects in the workspace and it's root directory should contain the [code]project.godot[/code] and [code].csproj[/code] next to each other.
+ </member>
<member name="editor/movie_writer/disable_vsync" type="bool" setter="" getter="" default="false">
If [code]true[/code], requests V-Sync to be disabled when writing a movie (similar to setting [member display/window/vsync/vsync_mode] to [b]Disabled[/b]). This can speed up video writing if the hardware is fast enough to render, encode and save the video at a framerate higher than the monitor's refresh rate.
[b]Note:[/b] [member editor/movie_writer/disable_vsync] has no effect if the operating system or graphics driver forces V-Sync with no way for applications to disable it.
@@ -760,6 +767,9 @@
<member name="gui/theme/lcd_subpixel_layout" type="int" setter="" getter="" default="1">
LCD subpixel layout used for font anti-aliasing. See [enum TextServer.FontLCDSubpixelLayout].
</member>
+ <member name="gui/timers/button_shortcut_feedback_highlight_time" type="float" setter="" getter="" default="0.2">
+ When [member BaseButton.shortcut_feedback] is enabled, this is the time the [BaseButton] will remain highlighted after a shortcut.
+ </member>
<member name="gui/timers/incremental_search_max_interval_msec" type="int" setter="" getter="" default="2000">
Timer setting for incremental search in [Tree], [ItemList], etc. controls (in milliseconds).
</member>
diff --git a/doc/classes/RenderingServer.xml b/doc/classes/RenderingServer.xml
index 7675a37cbd..fc08a16619 100644
--- a/doc/classes/RenderingServer.xml
+++ b/doc/classes/RenderingServer.xml
@@ -217,7 +217,7 @@
<param index="1" name="from" type="Vector2" />
<param index="2" name="to" type="Vector2" />
<param index="3" name="color" type="Color" />
- <param index="4" name="width" type="float" default="1.0" />
+ <param index="4" name="width" type="float" default="-1.0" />
<param index="5" name="antialiased" type="bool" default="false" />
<description>
</description>
@@ -291,7 +291,7 @@
<param index="0" name="item" type="RID" />
<param index="1" name="points" type="PackedVector2Array" />
<param index="2" name="colors" type="PackedColorArray" />
- <param index="3" name="width" type="float" default="1.0" />
+ <param index="3" name="width" type="float" default="-1.0" />
<param index="4" name="antialiased" type="bool" default="false" />
<description>
</description>
@@ -303,7 +303,6 @@
<param index="2" name="colors" type="PackedColorArray" />
<param index="3" name="uvs" type="PackedVector2Array" />
<param index="4" name="texture" type="RID" />
- <param index="5" name="width" type="float" default="1.0" />
<description>
</description>
</method>
@@ -3337,7 +3336,7 @@
<param index="0" name="viewport" type="RID" />
<param index="1" name="enabled" type="bool" />
<description>
- If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the [code]SCREEN_TEXTURE[/code]. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size.
+ If [code]true[/code], render the contents of the viewport directly to screen. This allows a low-level optimization where you can skip drawing a viewport to the root viewport. While this optimization can result in a significant increase in speed (especially on older devices), it comes at a cost of usability. When this is enabled, you cannot read from the viewport or from the screen_texture. You also lose the benefit of certain window settings, such as the various stretch modes. Another consequence to be aware of is that in 2D the rendering happens in window coordinates, so if you have a viewport that is double the size of the window, and you set this, then only the portion that fits within the window will be drawn, no automatic scaling is possible, even if your game scene is significantly larger than the window size.
</description>
</method>
<method name="viewport_set_scaling_3d_mode">
@@ -3811,6 +3810,8 @@
</constant>
<constant name="ARRAY_FLAG_USE_8_BONE_WEIGHTS" value="134217728" enum="ArrayFormat" is_bitfield="true">
</constant>
+ <constant name="ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY" value="268435456" enum="ArrayFormat" is_bitfield="true">
+ </constant>
<constant name="PRIMITIVE_POINTS" value="0" enum="PrimitiveType">
Primitive to draw consists of points.
</constant>
diff --git a/doc/classes/ResourcePreloader.xml b/doc/classes/ResourcePreloader.xml
index 17904697e6..5c0079f408 100644
--- a/doc/classes/ResourcePreloader.xml
+++ b/doc/classes/ResourcePreloader.xml
@@ -1,10 +1,10 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="ResourcePreloader" inherits="Node" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
- Resource Preloader Node.
+ Preloads a list of resources inside a scene.
</brief_description>
<description>
- This node is used to preload sub-resources inside a scene, so when the scene is loaded, all the resources are ready to use and can be retrieved from the preloader.
+ This node is used to preload sub-resources inside a scene, so when the scene is loaded, all the resources are ready to use and can be retrieved from the preloader. You can add the resources using the ResourcePreloader tab when the node is selected.
GDScript has a simplified [method @GDScript.preload] built-in method which can be used in most situations, leaving the use of [ResourcePreloader] for more advanced scenarios.
</description>
<tutorials>
diff --git a/doc/classes/RichTextLabel.xml b/doc/classes/RichTextLabel.xml
index dd291a425d..5550bf0955 100644
--- a/doc/classes/RichTextLabel.xml
+++ b/doc/classes/RichTextLabel.xml
@@ -283,6 +283,7 @@
<return type="void" />
<param index="0" name="font_size" type="int" />
<description>
+ Adds a [code][font_size][/code] tag to the tag stack. Overrides default font size for its duration.
</description>
</method>
<method name="push_hint">
diff --git a/doc/classes/ShaderMaterial.xml b/doc/classes/ShaderMaterial.xml
index 1af7ac4fc5..a2346822e5 100644
--- a/doc/classes/ShaderMaterial.xml
+++ b/doc/classes/ShaderMaterial.xml
@@ -23,7 +23,8 @@
<param index="1" name="value" type="Variant" />
<description>
Changes the value set for this material of a uniform in the shader.
- [b]Note:[/b] [param param] must match the name of the uniform in the code exactly.
+ [b]Note:[/b] [param param] is case-sensitive and must match the name of the uniform in the code exactly (not the capitalized name in the inspector).
+ [b]Note:[/b] Changes to the shader uniform will be effective on all instances using this [ShaderMaterial]. To prevent this, use per-instance uniforms with [method GeometryInstance3D.set_instance_shader_parameter] or duplicate the [ShaderMaterial] resource using [method Resource.duplicate]. Per-instance uniforms allow for better shader reuse and are therefore faster, so they should be preferred over duplicating the [ShaderMaterial] when possible.
</description>
</method>
</methods>
diff --git a/doc/classes/Skeleton2D.xml b/doc/classes/Skeleton2D.xml
index 808f93b491..39bdc5c796 100644
--- a/doc/classes/Skeleton2D.xml
+++ b/doc/classes/Skeleton2D.xml
@@ -16,7 +16,7 @@
<param index="0" name="delta" type="float" />
<param index="1" name="execution_mode" type="int" />
<description>
- Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton3D has one assigned.
+ Executes all the modifications on the [SkeletonModificationStack2D], if the Skeleton2D has one assigned.
</description>
</method>
<method name="get_bone">
diff --git a/doc/classes/Skeleton3D.xml b/doc/classes/Skeleton3D.xml
index 3bd0e04b92..70986ba06a 100644
--- a/doc/classes/Skeleton3D.xml
+++ b/doc/classes/Skeleton3D.xml
@@ -7,6 +7,7 @@
Skeleton3D provides a hierarchical interface for managing bones, including pose, rest and animation (see [Animation]). It can also use ragdoll physics.
The overall transform of a bone with respect to the skeleton is determined by the following hierarchical order: rest pose, custom pose and pose.
Note that "global pose" below refers to the overall transform of the bone with respect to skeleton, so it not the actual global/world transform of the bone.
+ To setup different types of inverse kinematics, consider using [SkeletonIK3D], or add a custom IK implementation in [method Node._process] as a child node.
</description>
<tutorials>
<link title="3D Inverse Kinematics Demo">https://godotengine.org/asset-library/asset/523</link>
@@ -32,26 +33,11 @@
Removes the global pose override on all bones in the skeleton.
</description>
</method>
- <method name="clear_bones_local_pose_override" is_deprecated="true">
- <return type="void" />
- <description>
- Deprecated. Local pose overrides will be removed.
- Removes the local pose override on all bones in the skeleton.
- </description>
- </method>
<method name="create_skin_from_rest_transforms">
<return type="Skin" />
<description>
</description>
</method>
- <method name="execute_modifications" is_deprecated="true">
- <return type="void" />
- <param index="0" name="delta" type="float" />
- <param index="1" name="execution_mode" type="int" />
- <description>
- Executes all the modifications on the [SkeletonModificationStack3D], if the Skeleton3D has one assigned.
- </description>
- </method>
<method name="find_bone" qualifiers="const">
<return type="int" />
<param index="0" name="name" type="String" />
@@ -113,13 +99,6 @@
Returns the global rest transform for [param bone_idx].
</description>
</method>
- <method name="get_bone_local_pose_override" qualifiers="const">
- <return type="Transform3D" />
- <param index="0" name="bone_idx" type="int" />
- <description>
- Returns the local pose override transform for [param bone_idx].
- </description>
- </method>
<method name="get_bone_name" qualifiers="const">
<return type="String" />
<param index="0" name="bone_idx" type="int" />
@@ -167,43 +146,18 @@
Returns the rest transform for a bone [param bone_idx].
</description>
</method>
- <method name="get_modification_stack" is_deprecated="true">
- <return type="SkeletonModificationStack3D" />
- <description>
- Returns the modification stack attached to this skeleton, if one exists.
- </description>
- </method>
<method name="get_parentless_bones" qualifiers="const">
<return type="PackedInt32Array" />
<description>
Returns an array with all of the bones that are parentless. Another way to look at this is that it returns the indexes of all the bones that are not dependent or modified by other bones in the Skeleton.
</description>
</method>
- <method name="global_pose_to_local_pose" is_deprecated="true">
- <return type="Transform3D" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="global_pose" type="Transform3D" />
- <description>
- Takes the passed-in global pose and converts it to local pose transform.
- This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform in [method set_bone_local_pose_override].
- </description>
- </method>
- <method name="global_pose_to_world_transform" is_deprecated="true">
- <return type="Transform3D" />
- <param index="0" name="global_pose" type="Transform3D" />
- <description>
- Deprecated. Use [Node3D] apis instead.
- Takes the passed-in global pose and converts it to a world transform.
- This can be used to easily convert a global pose from [method get_bone_global_pose] to a global transform usable with a node's transform, like [member Node3D.global_transform] for example.
- </description>
- </method>
- <method name="global_pose_z_forward_to_bone_forward" is_deprecated="true">
- <return type="Basis" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="basis" type="Basis" />
+ <method name="get_version" qualifiers="const">
+ <return type="int" />
<description>
- Rotates the given [Basis] so that the forward axis of the Basis is facing in the forward direction of the bone at [param bone_idx].
- This is helper function to make using [method Transform3D.looking_at] easier with bone poses.
+ Returns the number of times the bone hierarchy has changed within this skeleton, including renames.
+ The Skeleton version is not serialized: only use within a single instance of Skeleton3D.
+ Use for invalidating caches in IK solvers and other nodes which process bones.
</description>
</method>
<method name="is_bone_enabled" qualifiers="const">
@@ -213,15 +167,6 @@
Returns whether the bone pose for the bone at [param bone_idx] is enabled.
</description>
</method>
- <method name="local_pose_to_global_pose" is_deprecated="true">
- <return type="Transform3D" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="local_pose" type="Transform3D" />
- <description>
- Converts the passed-in local pose to a global pose relative to the inputted bone, [param bone_idx].
- This could be used to convert [method get_bone_pose] for use with the [method set_bone_global_pose_override] function.
- </description>
- </method>
<method name="localize_rests">
<return type="void" />
<description>
@@ -298,19 +243,6 @@
[b]Note:[/b] The pose transform needs to be a global pose! To convert a world transform from a [Node3D] to a global bone pose, multiply the [method Transform3D.affine_inverse] of the node's [member Node3D.global_transform] by the desired world transform
</description>
</method>
- <method name="set_bone_local_pose_override" is_deprecated="true">
- <return type="void" />
- <param index="0" name="bone_idx" type="int" />
- <param index="1" name="pose" type="Transform3D" />
- <param index="2" name="amount" type="float" />
- <param index="3" name="persistent" type="bool" default="false" />
- <description>
- Deprecated. Local pose overrides will be removed.
- Sets the local pose transform, [param pose], for the bone at [param bone_idx].
- [param amount] is the interpolation strength that will be used when applying the pose, and [param persistent] determines if the applied pose will remain.
- [b]Note:[/b] The pose transform needs to be a local pose! Use [method global_pose_to_local_pose] to convert a global pose to a local pose.
- </description>
- </method>
<method name="set_bone_name">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
@@ -356,13 +288,6 @@
Sets the rest transform for bone [param bone_idx].
</description>
</method>
- <method name="set_modification_stack" is_deprecated="true">
- <return type="void" />
- <param index="0" name="modification_stack" type="SkeletonModificationStack3D" />
- <description>
- Sets the modification stack for this skeleton to the passed-in modification stack, [param modification_stack].
- </description>
- </method>
<method name="unparent_bone_and_rest">
<return type="void" />
<param index="0" name="bone_idx" type="int" />
@@ -370,15 +295,6 @@
Unparents the bone at [param bone_idx] and sets its rest position to that of its parent prior to being reset.
</description>
</method>
- <method name="world_transform_to_global_pose" is_deprecated="true">
- <return type="Transform3D" />
- <param index="0" name="world_transform" type="Transform3D" />
- <description>
- Deprecated. Use [Node3D] apis instead.
- Takes the passed-in global transform and converts it to a global pose.
- This can be used to easily convert a global transform from [member Node3D.global_transform] to a global pose usable with [method set_bone_global_pose_override], for example.
- </description>
- </method>
</methods>
<members>
<member name="animate_physical_bones" type="bool" setter="set_animate_physical_bones" getter="get_animate_physical_bones" default="true">
diff --git a/doc/classes/SkeletonModification2D.xml b/doc/classes/SkeletonModification2D.xml
index 77aaf0213b..3a78f13bff 100644
--- a/doc/classes/SkeletonModification2D.xml
+++ b/doc/classes/SkeletonModification2D.xml
@@ -56,7 +56,7 @@
<method name="get_modification_stack">
<return type="SkeletonModificationStack2D" />
<description>
- Returns the [SkeletonModificationStack2D] that this modification is bound to. Through the modification stack, you can access the Skeleton3D the modification is operating on.
+ Returns the [SkeletonModificationStack2D] that this modification is bound to. Through the modification stack, you can access the Skeleton2D the modification is operating on.
</description>
</method>
<method name="set_editor_draw_gizmo">
diff --git a/doc/classes/SkeletonModification3D.xml b/doc/classes/SkeletonModification3D.xml
deleted file mode 100644
index 25431ea96f..0000000000
--- a/doc/classes/SkeletonModification3D.xml
+++ /dev/null
@@ -1,66 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A resource that operates on bones in a [Skeleton3D].
- </brief_description>
- <description>
- This resource provides an interface that can be expanded so code that operates on bones in a [Skeleton3D] can be mixed and matched together to create complex interactions.
- This is used to provide Godot with a flexible and powerful Inverse Kinematics solution that can be adapted for many different uses.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="_execute" qualifiers="virtual">
- <return type="void" />
- <param index="0" name="delta" type="float" />
- <description>
- Executes the given modification. This is where the modification performs whatever function it is designed to do.
- </description>
- </method>
- <method name="_setup_modification" qualifiers="virtual">
- <return type="void" />
- <param index="0" name="modification_stack" type="SkeletonModificationStack3D" />
- <description>
- Sets up the modification so it can be executed. This function should be called automatically by the [SkeletonModificationStack3D] containing this modification.
- If you need to initialize a modification before use, this is the place to do it!
- </description>
- </method>
- <method name="clamp_angle">
- <return type="float" />
- <param index="0" name="angle" type="float" />
- <param index="1" name="min" type="float" />
- <param index="2" name="max" type="float" />
- <param index="3" name="invert" type="bool" />
- <description>
- Takes a angle and clamps it so it is within the passed-in [param min] and [param max] range. [param invert] will inversely clamp the angle, clamping it to the range outside of the given bounds.
- </description>
- </method>
- <method name="get_is_setup" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether this modification has been successfully setup or not.
- </description>
- </method>
- <method name="get_modification_stack">
- <return type="SkeletonModificationStack3D" />
- <description>
- Returns the [SkeletonModificationStack3D] that this modification is bound to. Through the modification stack, you can access the Skeleton3D the modification is operating on.
- </description>
- </method>
- <method name="set_is_setup">
- <return type="void" />
- <param index="0" name="is_setup" type="bool" />
- <description>
- Manually allows you to set the setup state of the modification. This function should only rarely be used, as the [SkeletonModificationStack3D] the modification is bound to should handle setting the modification up.
- </description>
- </method>
- </methods>
- <members>
- <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="true">
- When true, the modification's [method _execute] function will be called by the [SkeletonModificationStack3D].
- </member>
- <member name="execution_mode" type="int" setter="set_execution_mode" getter="get_execution_mode" default="0">
- The execution mode for the modification. This tells the modification stack when to execute the modification. Some modifications have settings that are only available in certain execution modes.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DCCDIK.xml b/doc/classes/SkeletonModification3DCCDIK.xml
deleted file mode 100644
index 90b2e78449..0000000000
--- a/doc/classes/SkeletonModification3DCCDIK.xml
+++ /dev/null
@@ -1,136 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DCCDIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that uses CCDIK to manipulate a series of bones to reach a target.
- </brief_description>
- <description>
- This [SkeletonModification3D] uses an algorithm called Cyclic Coordinate Descent Inverse Kinematics, or CCDIK, to manipulate a chain of bones in a Skeleton so it reaches a defined target.
- CCDIK works by rotating a set of bones, typically called a "bone chain", on a single axis. Each bone is rotated to face the target from the tip (by default), which over a chain of bones allow it to rotate properly to reach the target. Because the bones only rotate on a single axis, CCDIK [i]can[/i] look more robotic than other IK solvers.
- [b]Note:[/b] The CCDIK modifier has [code]ccdik_joints[/code], which are the data objects that hold the data for each joint in the CCDIK chain. This is different from a bone! CCDIK joints hold the data needed for each bone in the bone chain used by CCDIK.
- CCDIK also fully supports angle constraints, allowing for more control over how a solution is met.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_ccdik_joint_bone_index" qualifiers="const">
- <return type="int" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the bone index of the bone assigned to the CCDIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_ccdik_joint_bone_name" qualifiers="const">
- <return type="String" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the name of the bone that is assigned to the CCDIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_ccdik_joint_ccdik_axis" qualifiers="const">
- <return type="int" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the integer representing the joint axis of the CCDIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_ccdik_joint_constraint_angle_max" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the maximum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle is in degrees!
- </description>
- </method>
- <method name="get_ccdik_joint_constraint_angle_min" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the minimum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle is in degrees!
- </description>
- </method>
- <method name="get_ccdik_joint_constraint_invert" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint. See [method set_ccdik_joint_constraint_invert] for details.
- </description>
- </method>
- <method name="get_ccdik_joint_enable_joint_constraint" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Enables angle constraints to the CCDIK joint at [param joint_idx].
- </description>
- </method>
- <method name="set_ccdik_joint_bone_index">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_index" type="int" />
- <description>
- Sets the bone index, [param bone_index], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the CCDIK joint based on data provided by the linked skeleton.
- </description>
- </method>
- <method name="set_ccdik_joint_bone_name">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_name" type="String" />
- <description>
- Sets the bone name, [param bone_name], of the CCDIK joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the CCDIK joint based on data provided by the linked skeleton.
- </description>
- </method>
- <method name="set_ccdik_joint_ccdik_axis">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="axis" type="int" />
- <description>
- Sets the joint axis of the CCDIK joint at [param joint_idx] to the passed-in joint axis, [param axis].
- </description>
- </method>
- <method name="set_ccdik_joint_constraint_angle_max">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="max_angle" type="float" />
- <description>
- Sets the maximum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle must be in radians!
- </description>
- </method>
- <method name="set_ccdik_joint_constraint_angle_min">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="min_angle" type="float" />
- <description>
- Sets the minimum angle constraint for the joint at [param joint_idx]. [b]Note:[/b] This angle must be in radians!
- </description>
- </method>
- <method name="set_ccdik_joint_constraint_invert">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="invert" type="bool" />
- <description>
- Sets whether the CCDIK joint at [param joint_idx] uses an inverted joint constraint.
- An inverted joint constraint only constraints the CCDIK joint to the angles [i]outside of[/i] the inputted minimum and maximum angles. For this reason, it is referred to as an inverted joint constraint, as it constraints the joint to the outside of the inputted values.
- </description>
- </method>
- <method name="set_ccdik_joint_enable_joint_constraint">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="enable" type="bool" />
- <description>
- Sets whether joint constraints are enabled for the CCDIK joint at [param joint_idx].
- </description>
- </method>
- </methods>
- <members>
- <member name="ccdik_data_chain_length" type="int" setter="set_ccdik_data_chain_length" getter="get_ccdik_data_chain_length" default="0">
- The number of CCDIK joints in the CCDIK modification.
- </member>
- <member name="high_quality_solve" type="bool" setter="set_use_high_quality_solve" getter="get_use_high_quality_solve" default="true">
- When true, the CCDIK algorithm will perform a higher quality solve that returns more natural results. A high quality solve requires more computation power to solve though, and therefore can be disabled to save performance.
- </member>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the CCDIK modification. This node is what the CCDIK chain will attempt to rotate the bone chain to.
- </member>
- <member name="tip_nodepath" type="NodePath" setter="set_tip_node" getter="get_tip_node" default="NodePath(&quot;&quot;)">
- The end position of the CCDIK chain. Typically, this should be a child of a [BoneAttachment3D] node attached to the final bone in the CCDIK chain, where the child node is offset so it is at the end of the final bone.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DFABRIK.xml b/doc/classes/SkeletonModification3DFABRIK.xml
deleted file mode 100644
index a2bec2b559..0000000000
--- a/doc/classes/SkeletonModification3DFABRIK.xml
+++ /dev/null
@@ -1,161 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DFABRIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that uses FABRIK to manipulate a series of bones to reach a target.
- </brief_description>
- <description>
- This [SkeletonModification3D] uses an algorithm called Forward And Backward Reaching Inverse Kinematics, or FABRIK, to rotate a bone chain so that it reaches a target.
- FABRIK works by knowing the positions and lengths of a series of bones, typically called a "bone chain". It first starts by running a forward pass, which places the final bone at the target's position. Then all other bones are moved towards the tip bone, so they stay at the defined bone length away. Then a backwards pass is performed, where the root/first bone in the FABRIK chain is placed back at the origin. then all other bones are moved so they stay at the defined bone length away. This positions the bone chain so that it reaches the target when possible, but all of the bones stay the correct length away from each other.
- Because of how FABRIK works, it often gives more natural results than those seen in [SkeletonModification3DCCDIK], though FABRIK currently does not support joint constraints.
- [b]Note:[/b] The FABRIK modifier has [code]fabrik_joints[/code], which are the data objects that hold the data for each joint in the FABRIK chain. This is different from a bone! FABRIK joints hold the data needed for each bone in the bone chain used by FABRIK.
- To help control how the FABRIK joints move, a magnet vector can be passed, which can nudge the bones in a certain direction prior to solving, giving a level of control over the final result.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="fabrik_joint_auto_calculate_length">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Will attempt to automatically calculate the length of the bone assigned to the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_auto_calculate_length" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a boolean that indicates whether this modification will attempt to autocalculate the length of the bone assigned to the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_bone_index" qualifiers="const">
- <return type="int" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the bone index of the bone assigned to the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_bone_name" qualifiers="const">
- <return type="String" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the name of the bone that is assigned to the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_length" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the length of the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_magnet" qualifiers="const">
- <return type="Vector3" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the magnet vector of the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="get_fabrik_joint_tip_node" qualifiers="const">
- <return type="NodePath" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the [Node3D]-based node placed at the tip of the FABRIK joint at [param joint_idx], if one has been set.
- </description>
- </method>
- <method name="get_fabrik_joint_use_target_basis" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a boolean indicating whether the FABRIK joint uses the target's [Basis] for its rotation.
- [b]Note:[/b] This option is only available for the final bone in the FABRIK chain, with this setting being ignored for all other bones.
- </description>
- </method>
- <method name="get_fabrik_joint_use_tip_node" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Sets the [Node3D]-based node that will be used as the tip of the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="set_fabrik_joint_auto_calculate_length">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="auto_calculate_length" type="bool" />
- <description>
- When [code]true[/code], this modification will attempt to automatically calculate the length of the bone for the FABRIK joint at [param joint_idx]. It does this by either using the tip node assigned, if there is one assigned, or the distance the of the bone's children, if the bone has any. If the bone has no children and no tip node is assigned, then the modification [b]cannot[/b] autocalculate the joint's length. In this case, the joint length should be entered manually or a tip node assigned.
- </description>
- </method>
- <method name="set_fabrik_joint_bone_index">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_index" type="int" />
- <description>
- Sets the bone index, [param bone_index], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the FABRIK joint based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_fabrik_joint_bone_name">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_name" type="String" />
- <description>
- Sets the bone name, [param bone_name], of the FABRIK joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the FABRIK joint based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_fabrik_joint_length">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="length" type="float" />
- <description>
- Sets the joint length, [param length], of the FABRIK joint at [param joint_idx].
- </description>
- </method>
- <method name="set_fabrik_joint_magnet">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="magnet_position" type="Vector3" />
- <description>
- Sets the magenet position to [param magnet_position] for the joint at [param joint_idx]. The magnet position is used to nudge the joint in that direction when solving, which gives some control over how that joint will bend when being solved.
- </description>
- </method>
- <method name="set_fabrik_joint_tip_node">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="tip_node" type="NodePath" />
- <description>
- Sets the nodepath of the FARIK joint at [param joint_idx] to [param tip_node]. The tip node is used to calculate the length of the FABRIK joint when set to automatically calculate joint length.
- [b]Note:[/b] The tip node should generally be a child node of a [BoneAttachment3D] node attached to the bone that this FABRIK joint operates on, with the child node being offset so it is at the end of the bone.
- </description>
- </method>
- <method name="set_fabrik_joint_use_target_basis">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="use_target_basis" type="bool" />
- <description>
- Sets whether the FABRIK joint at [param joint_idx] uses the target's [Basis] for its rotation.
- [b]Note:[/b] This option is only available for the final bone in the FABRIK chain, with this setting being ignored for all other bones.
- </description>
- </method>
- <method name="set_fabrik_joint_use_tip_node">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="use_tip_node" type="bool" />
- <description>
- Sets whether the tip node should be used when autocalculating the joint length for the FABRIK joint at [param joint_idx]. This will only work if there is a node assigned to the tip nodepath for this joint.
- </description>
- </method>
- </methods>
- <members>
- <member name="chain_max_iterations" type="int" setter="set_chain_max_iterations" getter="get_chain_max_iterations" default="10">
- The number of times FABRIK will try to solve each time the [code]execute[/code] function is called. Setting this value to a lower number will be result in better performance, but this can also result in harsher movements and slower solves.
- </member>
- <member name="chain_tolerance" type="float" setter="set_chain_tolerance" getter="get_chain_tolerance" default="0.01">
- The minimum distance the target has to be from the tip of the final bone in the bone chain. Setting this value to a higher number allows for greater performance, but less accurate solves.
- </member>
- <member name="fabrik_data_chain_length" type="int" setter="set_fabrik_data_chain_length" getter="get_fabrik_data_chain_length" default="0">
- The amount of FABRIK joints in the FABRIK modification.
- </member>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the FABRIK modification. This node is what the FABRIK chain will attempt to rotate the bone chain to.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DJiggle.xml b/doc/classes/SkeletonModification3DJiggle.xml
deleted file mode 100644
index 304f08bb20..0000000000
--- a/doc/classes/SkeletonModification3DJiggle.xml
+++ /dev/null
@@ -1,199 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DJiggle" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that jiggles bones as they move towards a target.
- </brief_description>
- <description>
- This modification moves a series of bones, typically called a bone chain, towards a target. What makes this modification special is that it calculates the velocity and acceleration for each bone in the bone chain, and runs a very light physics-like calculation using the inputted values. This allows the bones to overshoot the target and "jiggle" around. It can be configured to act more like a spring, or sway around like cloth might.
- This modification is useful for adding additional motion to things like hair, the edges of clothing, and more. It has several settings to that allow control over how the joint moves when the target moves.
- [b]Note:[/b] The Jiggle modifier has [code]jiggle_joints[/code], which are the data objects that hold the data for each joint in the Jiggle chain. This is different from a bone! Jiggle joints hold the data needed for each bone in the bone chain used by the Jiggle modification.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_collision_mask" qualifiers="const">
- <return type="int" />
- <description>
- Returns the collision mask that the Jiggle modifier will take into account when performing physics calculations.
- </description>
- </method>
- <method name="get_jiggle_joint_bone_index" qualifiers="const">
- <return type="int" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the bone index of the bone assigned to the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_bone_name" qualifiers="const">
- <return type="String" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the name of the bone that is assigned to the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_damping" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the amount of dampening of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_gravity" qualifiers="const">
- <return type="Vector3" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a [Vector3] representign the amount of gravity the Jiggle joint at [param joint_idx] is influenced by.
- </description>
- </method>
- <method name="get_jiggle_joint_mass" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the amount of mass of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_override" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a boolean that indicates whether the joint at [param joint_idx] is overriding the default jiggle joint data defined in the modification.
- </description>
- </method>
- <method name="get_jiggle_joint_roll" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the amount of roll/twist applied to the bone that the Jiggle joint is applied to.
- </description>
- </method>
- <method name="get_jiggle_joint_stiffness" qualifiers="const">
- <return type="float" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns the stiffness of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="get_jiggle_joint_use_gravity" qualifiers="const">
- <return type="bool" />
- <param index="0" name="joint_idx" type="int" />
- <description>
- Returns a boolean that indicates whether the joint at [param joint_idx] is using gravity or not.
- </description>
- </method>
- <method name="get_use_colliders" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the Jiggle modifier is taking physics colliders into account when solving.
- </description>
- </method>
- <method name="set_collision_mask">
- <return type="void" />
- <param index="0" name="mask" type="int" />
- <description>
- Sets the collision mask that the Jiggle modifier takes into account when performing physics calculations.
- </description>
- </method>
- <method name="set_jiggle_joint_bone_index">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="bone_idx" type="int" />
- <description>
- Sets the bone index, [param bone_idx], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone_name[/code] of the Jiggle joint based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_jiggle_joint_bone_name">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="name" type="String" />
- <description>
- Sets the bone name, [param name], of the Jiggle joint at [param joint_idx]. When possible, this will also update the [code]bone_index[/code] of the Jiggle joint based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_jiggle_joint_damping">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="damping" type="float" />
- <description>
- Sets the amount of dampening of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="set_jiggle_joint_gravity">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="gravity" type="Vector3" />
- <description>
- Sets the gravity vector of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="set_jiggle_joint_mass">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="mass" type="float" />
- <description>
- Sets the of mass of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="set_jiggle_joint_override">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="override" type="bool" />
- <description>
- Sets whether the Jiggle joint at [param joint_idx] should override the default Jiggle joint settings. Setting this to true will make the joint use its own settings rather than the default ones attached to the modification.
- </description>
- </method>
- <method name="set_jiggle_joint_roll">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="roll" type="float" />
- <description>
- Sets the amount of roll/twist on the bone the Jiggle joint is attached to.
- </description>
- </method>
- <method name="set_jiggle_joint_stiffness">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="stiffness" type="float" />
- <description>
- Sets the of stiffness of the Jiggle joint at [param joint_idx].
- </description>
- </method>
- <method name="set_jiggle_joint_use_gravity">
- <return type="void" />
- <param index="0" name="joint_idx" type="int" />
- <param index="1" name="use_gravity" type="bool" />
- <description>
- Sets whether the Jiggle joint at [param joint_idx] should use gravity.
- </description>
- </method>
- <method name="set_use_colliders">
- <return type="void" />
- <param index="0" name="use_colliders" type="bool" />
- <description>
- When [code]true[/code], the Jiggle modifier will use raycasting to prevent the Jiggle joints from rotating themselves into collision objects when solving.
- </description>
- </method>
- </methods>
- <members>
- <member name="damping" type="float" setter="set_damping" getter="get_damping" default="0.75">
- The default amount of dampening applied to the Jiggle joints, if they are not overridden. Higher values lead to more of the calculated velocity being applied.
- </member>
- <member name="gravity" type="Vector3" setter="set_gravity" getter="get_gravity" default="Vector3(0, -6, 0)">
- The default amount of gravity applied to the Jiggle joints, if they are not overridden.
- </member>
- <member name="jiggle_data_chain_length" type="int" setter="set_jiggle_data_chain_length" getter="get_jiggle_data_chain_length" default="0">
- The amount of Jiggle joints in the Jiggle modification.
- </member>
- <member name="mass" type="float" setter="set_mass" getter="get_mass" default="0.75">
- The default amount of mass assigned to the Jiggle joints, if they are not overridden. Higher values lead to faster movements and more overshooting.
- </member>
- <member name="stiffness" type="float" setter="set_stiffness" getter="get_stiffness" default="3.0">
- The default amount of stiffness assigned to the Jiggle joints, if they are not overridden. Higher values act more like springs, quickly moving into the correct position.
- </member>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the Jiggle modification. This node is what the Jiggle chain will attempt to rotate the bone chain to.
- </member>
- <member name="use_gravity" type="bool" setter="set_use_gravity" getter="get_use_gravity" default="false">
- Whether the gravity vector, [member gravity], should be applied to the Jiggle joints, assuming they are not overriding the default settings.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DLookAt.xml b/doc/classes/SkeletonModification3DLookAt.xml
deleted file mode 100644
index aeed953ca9..0000000000
--- a/doc/classes/SkeletonModification3DLookAt.xml
+++ /dev/null
@@ -1,64 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DLookAt" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that rotates a bone to look at a target.
- </brief_description>
- <description>
- This [SkeletonModification3D] rotates a bone to look a target. This is extremely helpful for moving character's heads to look at the player, rotating a turret to look at a target, or any other case where you want to make a bone rotate towards something quickly and easily.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_additional_rotation" qualifiers="const">
- <return type="Vector3" />
- <description>
- Returns the amount of extra rotation that is applied to the bone after the LookAt modification executes.
- </description>
- </method>
- <method name="get_lock_rotation_plane" qualifiers="const">
- <return type="int" />
- <description>
- Returns the plane that the LookAt modification is limiting rotation to.
- </description>
- </method>
- <method name="get_lock_rotation_to_plane" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the LookAt modification is limiting rotation to a single plane in 3D space.
- </description>
- </method>
- <method name="set_additional_rotation">
- <return type="void" />
- <param index="0" name="additional_rotation" type="Vector3" />
- <description>
- Sets the amount of extra rotation to be applied after the LookAt modification executes. This allows you to adjust the finished result.
- </description>
- </method>
- <method name="set_lock_rotation_plane">
- <return type="void" />
- <param index="0" name="plane" type="int" />
- <description>
- </description>
- </method>
- <method name="set_lock_rotation_to_plane">
- <return type="void" />
- <param index="0" name="lock_to_plane" type="bool" />
- <description>
- When [code]true[/code], the LookAt modification will limit its rotation to a single plane in 3D space. The plane used can be configured using the [code]set_lock_rotation_plane[/code] function.
- </description>
- </method>
- </methods>
- <members>
- <member name="bone_index" type="int" setter="set_bone_index" getter="get_bone_index" default="-2">
- The bone index of the bone that should be operated on by this modification.
- When possible, this will also update the [member bone_name] based on data provided by the [Skeleton3D].
- </member>
- <member name="bone_name" type="String" setter="set_bone_name" getter="get_bone_name" default="&quot;&quot;">
- The name of the bone that should be operated on by this modification.
- When possible, this will also update the [member bone_index] based on data provided by the [Skeleton3D].
- </member>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the modification.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModification3DStackHolder.xml b/doc/classes/SkeletonModification3DStackHolder.xml
deleted file mode 100644
index 9448e2c783..0000000000
--- a/doc/classes/SkeletonModification3DStackHolder.xml
+++ /dev/null
@@ -1,27 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DStackHolder" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that holds and executes a [SkeletonModificationStack3D].
- </brief_description>
- <description>
- This [SkeletonModification3D] holds a reference to a [SkeletonModificationStack3D], allowing you to use multiple modification stacks on a single [Skeleton3D].
- [b]Note:[/b] The modifications in the held [SkeletonModificationStack3D] will only be executed if their execution mode matches the execution mode of the SkeletonModification3DStackHolder.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_held_modification_stack" qualifiers="const">
- <return type="SkeletonModificationStack3D" />
- <description>
- Returns the [SkeletonModificationStack3D] that this modification is holding.
- </description>
- </method>
- <method name="set_held_modification_stack">
- <return type="void" />
- <param index="0" name="held_modification_stack" type="SkeletonModificationStack3D" />
- <description>
- Sets the [SkeletonModificationStack3D] that this modification is holding. This modification stack will then be executed when this modification is executed.
- </description>
- </method>
- </methods>
-</class>
diff --git a/doc/classes/SkeletonModification3DTwoBoneIK.xml b/doc/classes/SkeletonModification3DTwoBoneIK.xml
deleted file mode 100644
index 0e7ffd5c80..0000000000
--- a/doc/classes/SkeletonModification3DTwoBoneIK.xml
+++ /dev/null
@@ -1,191 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModification3DTwoBoneIK" inherits="SkeletonModification3D" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A modification that moves two bones to reach the target.
- </brief_description>
- <description>
- This [SkeletonModification3D] uses an algorithm typically called TwoBoneIK. This algorithm works by leveraging the law of cosigns and the lengths of the bones to figure out what rotation the bones currently have, and what rotation they need to make a complete triangle, where the first bone, the second bone, and the target form the three vertices of the triangle. Because the algorithm works by making a triangle, it can only operate on two bones.
- TwoBoneIK is great for arms, legs, and really any joints that can be represented by just two bones that bend to reach a target. This solver is more lightweight than [SkeletonModification3DFABRIK], but gives similar, natural looking results.
- A [Node3D]-based node can be used to define the pole, or bend direction, allowing control over which direction the joint takes when bending to reach the target when the target is within reach.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="get_auto_calculate_joint_length" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the TwoBoneIK modification will attempt to autocalculate the lengths of the two bones.
- </description>
- </method>
- <method name="get_joint_one_bone_idx" qualifiers="const">
- <return type="int" />
- <description>
- Returns the bone index of the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_one_bone_name" qualifiers="const">
- <return type="String" />
- <description>
- Returns the name of the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_one_length" qualifiers="const">
- <return type="float" />
- <description>
- Returns the length of the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_one_roll" qualifiers="const">
- <return type="float" />
- <description>
- Returns the amount of roll/twist applied to the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_two_bone_idx" qualifiers="const">
- <return type="int" />
- <description>
- Returns the bone index of the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_two_bone_name" qualifiers="const">
- <return type="String" />
- <description>
- Returns the name of the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_two_length" qualifiers="const">
- <return type="float" />
- <description>
- Returns the length of the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_joint_two_roll" qualifiers="const">
- <return type="float" />
- <description>
- Returns the amount of roll/twist applied to the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="get_pole_node" qualifiers="const">
- <return type="NodePath" />
- <description>
- Returns the node that is being used as the pole node for the TwoBoneIK modification, if a pole node has been set.
- </description>
- </method>
- <method name="get_tip_node" qualifiers="const">
- <return type="NodePath" />
- <description>
- Returns the node that is being used to calculate the tip position of the second bone in the TwoBoneIK modification, if a tip node has been set.
- </description>
- </method>
- <method name="get_use_pole_node" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the TwoBoneIK modification will attempt to use the pole node to figure out which direction to bend, if a pole node has been set.
- </description>
- </method>
- <method name="get_use_tip_node" qualifiers="const">
- <return type="bool" />
- <description>
- Returns whether the TwoBoneIK modification will attempt to use the tip node to figure out the length and position of the tip of the second bone.
- </description>
- </method>
- <method name="set_auto_calculate_joint_length">
- <return type="void" />
- <param index="0" name="auto_calculate_joint_length" type="bool" />
- <description>
- If true, the TwoBoneIK modification will attempt to autocalculate the lengths of the bones being used. The first bone will be calculated by using the distance from the origin of the first bone to the origin of the second bone.
- The second bone will be calculated either using the tip node if that setting is enabled, or by using the distances of the second bone's children. If the tip node is not enabled and the bone has no children, then the length cannot be autocalculated. In this case, the length will either have to be manually inputted or a tip node used to calculate the length.
- </description>
- </method>
- <method name="set_joint_one_bone_idx">
- <return type="void" />
- <param index="0" name="bone_idx" type="int" />
- <description>
- Sets the bone index, [param bone_idx], of the first bone. When possible, this will also update the [code]bone_name[/code] of the first bone based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_joint_one_bone_name">
- <return type="void" />
- <param index="0" name="bone_name" type="String" />
- <description>
- Sets the bone name, [param bone_name], of the first bone. When possible, this will also update the [code]bone_index[/code] of the first bone based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_joint_one_length">
- <return type="void" />
- <param index="0" name="bone_length" type="float" />
- <description>
- Sets the length of the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="set_joint_one_roll">
- <return type="void" />
- <param index="0" name="roll" type="float" />
- <description>
- Sets the amount of roll/twist applied to the first bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="set_joint_two_bone_idx">
- <return type="void" />
- <param index="0" name="bone_idx" type="int" />
- <description>
- Sets the bone index, [param bone_idx], of the second bone. When possible, this will also update the [code]bone_name[/code] of the second bone based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_joint_two_bone_name">
- <return type="void" />
- <param index="0" name="bone_name" type="String" />
- <description>
- Sets the bone name, [param bone_name], of the second bone. When possible, this will also update the [code]bone_index[/code] of the second bone based on data provided by the [Skeleton3D].
- </description>
- </method>
- <method name="set_joint_two_length">
- <return type="void" />
- <param index="0" name="bone_length" type="float" />
- <description>
- Sets the length of the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="set_joint_two_roll">
- <return type="void" />
- <param index="0" name="roll" type="float" />
- <description>
- Sets the amount of roll/twist applied to the second bone in the TwoBoneIK modification.
- </description>
- </method>
- <method name="set_pole_node">
- <return type="void" />
- <param index="0" name="pole_nodepath" type="NodePath" />
- <description>
- Sets the node to be used as the for the pole of the TwoBoneIK. When a node is set and the modification is set to use the pole node, the TwoBoneIK modification will bend the nodes in the direction towards this node when the bones need to bend.
- </description>
- </method>
- <method name="set_tip_node">
- <return type="void" />
- <param index="0" name="tip_nodepath" type="NodePath" />
- <description>
- Sets the node to be used as the tip for the second bone. This is used to calculate the length and position of the end of the second bone in the TwoBoneIK modification.
- [b]Note:[/b] The tip node should generally be a child node of a [BoneAttachment3D] node attached to the second bone, with the child node being offset so it is at the end of the bone.
- </description>
- </method>
- <method name="set_use_pole_node">
- <return type="void" />
- <param index="0" name="use_pole_node" type="bool" />
- <description>
- When [code]true[/code], the TwoBoneIK modification will bend the bones towards the pole node, if one has been set. This gives control over the direction the TwoBoneIK solver will bend, which is helpful for joints like elbows that only bend in certain directions.
- </description>
- </method>
- <method name="set_use_tip_node">
- <return type="void" />
- <param index="0" name="use_tip_node" type="bool" />
- <description>
- When [code]true[/code], the TwoBoneIK modification will use the tip node to calculate the distance and position of the end/tip of the second bone. This is the most stable solution for knowing the tip position and length of the second bone.
- </description>
- </method>
- </methods>
- <members>
- <member name="target_nodepath" type="NodePath" setter="set_target_node" getter="get_target_node" default="NodePath(&quot;&quot;)">
- The NodePath to the node that is the target for the TwoBoneIK modification. This node is what the modification will attempt to rotate the bones to reach.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonModificationStack3D.xml b/doc/classes/SkeletonModificationStack3D.xml
deleted file mode 100644
index 9eaeeefd8e..0000000000
--- a/doc/classes/SkeletonModificationStack3D.xml
+++ /dev/null
@@ -1,88 +0,0 @@
-<?xml version="1.0" encoding="UTF-8" ?>
-<class name="SkeletonModificationStack3D" inherits="Resource" is_deprecated="true" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
- <brief_description>
- A resource that holds a stack of [SkeletonModification3D]s.
- </brief_description>
- <description>
- This resource is used by the Skeleton and holds a stack of [SkeletonModification3D]s. The SkeletonModificationStack3D controls the order of the modifications, which controls how they are applied. Modification order is especially important for full-body IK setups, as you need to execute the modifications in the correct order to get the desired results. For example, you want to execute a modification on the spine [i]before[/i] the arms on a humanoid skeleton.
- Additionally, the SkeletonModificationStack3D also controls how strongly the modifications are applied to the [Skeleton3D] node.
- </description>
- <tutorials>
- </tutorials>
- <methods>
- <method name="add_modification">
- <return type="void" />
- <param index="0" name="modification" type="SkeletonModification3D" />
- <description>
- Adds the passed-in [SkeletonModification3D] to the stack.
- </description>
- </method>
- <method name="delete_modification">
- <return type="void" />
- <param index="0" name="mod_idx" type="int" />
- <description>
- Deletes the [SkeletonModification3D] at the index position [param mod_idx], if it exists.
- </description>
- </method>
- <method name="enable_all_modifications">
- <return type="void" />
- <param index="0" name="enabled" type="bool" />
- <description>
- Enables all [SkeletonModification3D]s in the stack.
- </description>
- </method>
- <method name="execute">
- <return type="void" />
- <param index="0" name="delta" type="float" />
- <param index="1" name="execution_mode" type="int" />
- <description>
- Executes all of the [SkeletonModification3D]s in the stack that use the same execution mode as the passed-in [param execution_mode], starting from index [code]0[/code] to [member modification_count].
- [b]Note:[/b] The order of the modifications can matter depending on the modifications. For example, modifications on a spine should operate before modifications on the arms in order to get proper results.
- </description>
- </method>
- <method name="get_is_setup" qualifiers="const">
- <return type="bool" />
- <description>
- Returns a boolean that indicates whether the modification stack is setup and can execute.
- </description>
- </method>
- <method name="get_modification" qualifiers="const">
- <return type="SkeletonModification3D" />
- <param index="0" name="mod_idx" type="int" />
- <description>
- Returns the [SkeletonModification3D] at the passed-in index, [param mod_idx].
- </description>
- </method>
- <method name="get_skeleton" qualifiers="const">
- <return type="Skeleton3D" />
- <description>
- Returns the [Skeleton3D] node that the SkeletonModificationStack3D is bound to.
- </description>
- </method>
- <method name="set_modification">
- <return type="void" />
- <param index="0" name="mod_idx" type="int" />
- <param index="1" name="modification" type="SkeletonModification3D" />
- <description>
- Sets the modification at [param mod_idx] to the passed-in modification, [param modification].
- </description>
- </method>
- <method name="setup">
- <return type="void" />
- <description>
- Sets up the modification stack so it can execute. This function should be called by [Skeleton3D] and shouldn't be called unless you know what you are doing.
- </description>
- </method>
- </methods>
- <members>
- <member name="enabled" type="bool" setter="set_enabled" getter="get_enabled" default="false">
- When true, the modification's in the stack will be called. This is handled automatically through the [Skeleton3D] node.
- </member>
- <member name="modification_count" type="int" setter="set_modification_count" getter="get_modification_count" default="0">
- The number of modifications in the stack.
- </member>
- <member name="strength" type="float" setter="set_strength" getter="get_strength" default="1.0">
- The interpolation strength of the modifications in stack. A value of [code]0[/code] will make it where the modifications are not applied, a strength of [code]0.5[/code] will be half applied, and a strength of [code]1[/code] will allow the modifications to be fully applied and override the skeleton bone poses.
- </member>
- </members>
-</class>
diff --git a/doc/classes/SkeletonProfile.xml b/doc/classes/SkeletonProfile.xml
index 57bdd52d9e..6fb311bcee 100644
--- a/doc/classes/SkeletonProfile.xml
+++ b/doc/classes/SkeletonProfile.xml
@@ -5,6 +5,7 @@
</brief_description>
<description>
This resource is used in [EditorScenePostImport]. Some parameters are referring to bones in [Skeleton3D], [Skin], [Animation], and some other nodes are rewritten based on the parameters of [SkeletonProfile].
+ [b]Note:[/b] These parameters need to be set only when creating a custom profile. In [SkeletonProfileHumanoid], they are defined internally as read-only values.
</description>
<tutorials>
<link title="Retargeting 3D Skeletons">$DOCS_URL/tutorials/assets_pipeline/retargeting_3d_skeletons.html</link>
@@ -160,16 +161,18 @@
</methods>
<members>
<member name="bone_size" type="int" setter="set_bone_size" getter="get_bone_size" default="0">
+ The amount of bones in retargeting section's [BoneMap] editor. For example, [SkeletonProfileHumanoid] has 56 bones.
+ The size of elements in [BoneMap] updates when changing this property in it's assigned [SkeletonProfile].
</member>
<member name="group_size" type="int" setter="set_group_size" getter="get_group_size" default="0">
+ The amount of groups of bones in retargeting section's [BoneMap] editor. For example, [SkeletonProfileHumanoid] has 4 groups.
+ This property exists to separate the bone list into several sections in the editor.
</member>
<member name="root_bone" type="StringName" setter="set_root_bone" getter="get_root_bone" default="&amp;&quot;&quot;">
- A name of bone that will be used as the root bone in [AnimationTree].
- [b]Note:[/b] In most cases, it is the bone of the parent of the hips that exists at the world origin in the humanoid model.
+ A bone name that will be used as the root bone in [AnimationTree]. This should be the bone of the parent of hips that exists at the world origin.
</member>
<member name="scale_base_bone" type="StringName" setter="set_scale_base_bone" getter="get_scale_base_bone" default="&amp;&quot;&quot;">
- A name of bone which height will be used as the coefficient for normalization.
- [b]Note:[/b] In most cases, it is hips in the humanoid model.
+ A bone name which will use model's height as the coefficient for normalization. For example, [SkeletonProfileHumanoid] defines it as [code]Hips[/code].
</member>
</members>
<signals>
diff --git a/doc/classes/SkeletonProfileHumanoid.xml b/doc/classes/SkeletonProfileHumanoid.xml
index 0dbd66d8d6..7445272ccc 100644
--- a/doc/classes/SkeletonProfileHumanoid.xml
+++ b/doc/classes/SkeletonProfileHumanoid.xml
@@ -1,6 +1,7 @@
<?xml version="1.0" encoding="UTF-8" ?>
<class name="SkeletonProfileHumanoid" inherits="SkeletonProfile" version="4.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:noNamespaceSchemaLocation="../class.xsd">
<brief_description>
+ A humanoid [SkeletonProfile] preset.
</brief_description>
<description>
A [SkeletonProfile] as a preset that is optimized for the human form. This exists for standardization, so all parameters are read-only.
diff --git a/doc/classes/SpriteFrames.xml b/doc/classes/SpriteFrames.xml
index 87b823bd2a..195f3598d5 100644
--- a/doc/classes/SpriteFrames.xml
+++ b/doc/classes/SpriteFrames.xml
@@ -5,7 +5,6 @@
</brief_description>
<description>
Sprite frame library for an [AnimatedSprite2D] or [AnimatedSprite3D] node. Contains frames and animation data for playback.
- [b]Note:[/b] You can associate a set of normal or specular maps by creating additional [SpriteFrames] resources with a [code]_normal[/code] or [code]_specular[/code] suffix. For example, having 3 [SpriteFrames] resources [code]run[/code], [code]run_normal[/code], and [code]run_specular[/code] will make it so the [code]run[/code] animation uses normal and specular maps.
</description>
<tutorials>
</tutorials>
@@ -14,7 +13,7 @@
<return type="void" />
<param index="0" name="anim" type="StringName" />
<description>
- Adds a new animation to the library.
+ Adds a new [param anim] animation to the library.
</description>
</method>
<method name="add_frame">
@@ -24,20 +23,20 @@
<param index="2" name="duration" type="float" default="1.0" />
<param index="3" name="at_position" type="int" default="-1" />
<description>
- Adds a frame to the given animation.
+ Adds a frame to the [param anim] animation. If [param at_position] is [code]-1[/code], the frame will be added to the end of the animation.
</description>
</method>
<method name="clear">
<return type="void" />
<param index="0" name="anim" type="StringName" />
<description>
- Removes all frames from the given animation.
+ Removes all frames from the [param anim] animation.
</description>
</method>
<method name="clear_all">
<return type="void" />
<description>
- Removes all animations. A "default" animation will be created.
+ Removes all animations. An empty [code]default[/code] animation will be created.
</description>
</method>
<method name="get_animation_loop" qualifiers="const">
@@ -91,14 +90,14 @@
<return type="bool" />
<param index="0" name="anim" type="StringName" />
<description>
- If [code]true[/code], the named animation exists.
+ Returns [code]true[/code] if the [param anim] animation exists.
</description>
</method>
<method name="remove_animation">
<return type="void" />
<param index="0" name="anim" type="StringName" />
<description>
- Removes the given animation.
+ Removes the [param anim] animation.
</description>
</method>
<method name="remove_frame">
@@ -106,7 +105,7 @@
<param index="0" name="anim" type="StringName" />
<param index="1" name="idx" type="int" />
<description>
- Removes the animation's selected frame.
+ Removes the [param anim] animation's frame [param idx].
</description>
</method>
<method name="rename_animation">
@@ -114,7 +113,7 @@
<param index="0" name="anim" type="StringName" />
<param index="1" name="newname" type="StringName" />
<description>
- Changes the animation's name to [param newname].
+ Changes the [param anim] animation's name to [param newname].
</description>
</method>
<method name="set_animation_loop">
@@ -122,7 +121,7 @@
<param index="0" name="anim" type="StringName" />
<param index="1" name="loop" type="bool" />
<description>
- If [code]true[/code], the animation will loop.
+ If [param loop] is [code]true[/code], the [param anim] animation will loop when it reaches the end, or the start if it is played in reverse.
</description>
</method>
<method name="set_animation_speed">
@@ -140,7 +139,7 @@
<param index="2" name="texture" type="Texture2D" />
<param index="3" name="duration" type="float" default="1.0" />
<description>
- Sets the texture and the duration of the frame [param idx] in the [param anim] animation.
+ Sets the [param texture] and the [param duration] of the frame [param idx] in the [param anim] animation.
</description>
</method>
</methods>
diff --git a/doc/classes/TextServer.xml b/doc/classes/TextServer.xml
index d2c6dee373..711fb89217 100644
--- a/doc/classes/TextServer.xml
+++ b/doc/classes/TextServer.xml
@@ -1042,7 +1042,7 @@
</description>
</method>
<method name="parse_structured_text" qualifiers="const">
- <return type="Vector2i[]" />
+ <return type="Vector3i[]" />
<param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
<param index="1" name="args" type="Array" />
<param index="2" name="text" type="String" />
@@ -1634,6 +1634,9 @@
<constant name="DIRECTION_RTL" value="2" enum="Direction">
Text is written from right to left.
</constant>
+ <constant name="DIRECTION_INHERITED" value="3" enum="Direction">
+ Text writing direction is the same as base string writing direction. Used for BiDi override only.
+ </constant>
<constant name="ORIENTATION_HORIZONTAL" value="0" enum="Orientation">
Text is written horizontally.
</constant>
@@ -1881,7 +1884,7 @@
Font have fixed-width characters.
</constant>
<constant name="STRUCTURED_TEXT_DEFAULT" value="0" enum="StructuredTextParser">
- Use default behavior. Same as [constant STRUCTURED_TEXT_NONE] unless specified otherwise in the control description.
+ Use default Unicode BiDi algorithm.
</constant>
<constant name="STRUCTURED_TEXT_URI" value="1" enum="StructuredTextParser">
BiDi override for URI.
@@ -1896,8 +1899,8 @@
BiDi override for lists.
Structured text options: list separator [code]String[/code].
</constant>
- <constant name="STRUCTURED_TEXT_NONE" value="5" enum="StructuredTextParser">
- Use default Unicode BiDi algorithm.
+ <constant name="STRUCTURED_TEXT_GDSCRIPT" value="5" enum="StructuredTextParser">
+ BiDi override for GDScript.
</constant>
<constant name="STRUCTURED_TEXT_CUSTOM" value="6" enum="StructuredTextParser">
User defined structured text BiDi override function.
diff --git a/doc/classes/TextServerExtension.xml b/doc/classes/TextServerExtension.xml
index e144b09eb6..f4b306cf96 100644
--- a/doc/classes/TextServerExtension.xml
+++ b/doc/classes/TextServerExtension.xml
@@ -896,7 +896,7 @@
</description>
</method>
<method name="_parse_structured_text" qualifiers="virtual const">
- <return type="Vector2i[]" />
+ <return type="Vector3i[]" />
<param index="0" name="parser_type" type="int" enum="TextServer.StructuredTextParser" />
<param index="1" name="args" type="Array" />
<param index="2" name="text" type="String" />
diff --git a/doc/classes/TileMap.xml b/doc/classes/TileMap.xml
index 8176901ff7..f67b84f96f 100644
--- a/doc/classes/TileMap.xml
+++ b/doc/classes/TileMap.xml
@@ -185,7 +185,19 @@
<return type="Vector2i[]" />
<param index="0" name="layer" type="int" />
<description>
- Returns a [Vector2] array with the positions of all cells containing a tile in the given layer. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
+ Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
+ </description>
+ </method>
+ <method name="get_used_cells_by_id" qualifiers="const">
+ <return type="Vector2i[]" />
+ <param index="0" name="layer" type="int" />
+ <param index="1" name="source_id" type="int" default="-1" />
+ <param index="2" name="atlas_coords" type="Vector2i" default="Vector2i(-1, -1)" />
+ <param index="3" name="alternative_tile" type="int" default="-1" />
+ <description>
+ Returns a [Vector2i] array with the positions of all cells containing a tile in the given layer. Tiles may be filtered according to their source ([param source_id]), their atlas coordinates ([param atlas_coords]) or alternative id ([param source_id]).
+ If a parameter has it's value set to the default one, this parameter is not used to filter a cell. Thus, if all parameters have their respective default value, this method returns the same result as [method get_used_cells].
+ A cell is considered empty if its source identifier equals -1, its atlas coordinates identifiers is [code]Vector2(-1, -1)[/code] and its alternative identifier is -1.
</description>
</method>
<method name="get_used_rect">
diff --git a/doc/classes/Transform3D.xml b/doc/classes/Transform3D.xml
index b3145ea022..90c10e3664 100644
--- a/doc/classes/Transform3D.xml
+++ b/doc/classes/Transform3D.xml
@@ -41,6 +41,7 @@
<return type="Transform3D" />
<param index="0" name="from" type="Projection" />
<description>
+ Constructs a Transform3D from a [Projection] by trimming the last row of the projection matrix ([code]from.x.w[/code], [code]from.y.w[/code], [code]from.z.w[/code], and [code]from.w.w[/code] are not copied over).
</description>
</constructor>
<constructor name="Transform3D">
diff --git a/doc/classes/Tree.xml b/doc/classes/Tree.xml
index bfabd2d97d..ff5a665bfd 100644
--- a/doc/classes/Tree.xml
+++ b/doc/classes/Tree.xml
@@ -45,11 +45,11 @@
<method name="create_item">
<return type="TreeItem" />
<param index="0" name="parent" type="TreeItem" default="null" />
- <param index="1" name="idx" type="int" default="-1" />
+ <param index="1" name="index" type="int" default="-1" />
<description>
Creates an item in the tree and adds it as a child of [param parent], which can be either a valid [TreeItem] or [code]null[/code].
If [param parent] is [code]null[/code], the root item will be the parent, or the new item will be the root itself if the tree is empty.
- The new item will be the [param idx]th child of parent, or it will be the last child if there are not enough siblings.
+ The new item will be the [param index]-th child of parent, or it will be the last child if there are not enough siblings.
</description>
</method>
<method name="deselect_all">
diff --git a/doc/classes/TreeItem.xml b/doc/classes/TreeItem.xml
index ec6b166e57..91248092d9 100644
--- a/doc/classes/TreeItem.xml
+++ b/doc/classes/TreeItem.xml
@@ -18,7 +18,7 @@
<param index="3" name="disabled" type="bool" default="false" />
<param index="4" name="tooltip_text" type="String" default="&quot;&quot;" />
<description>
- Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text].
+ Adds a button with [Texture2D] [param button] at column [param column]. The [param id] is used to identify the button in the according [signal Tree.button_clicked] signal and can be different from the buttons index. If not specified, the next available index is used, which may be retrieved by calling [method get_button_count] immediately before this method. Optionally, the button can be [param disabled] and have a [param tooltip_text].
</description>
</method>
<method name="call_recursive" qualifiers="vararg">
@@ -44,10 +44,10 @@
</method>
<method name="create_child">
<return type="TreeItem" />
- <param index="0" name="idx" type="int" default="-1" />
+ <param index="0" name="index" type="int" default="-1" />
<description>
Creates an item and adds it as a child.
- The new item will be inserted as position [param idx] (the default value [code]-1[/code] means the last position), or it will be the last child if [param idx] is higher than the child count.
+ The new item will be inserted as position [param index] (the default value [code]-1[/code] means the last position), or it will be the last child if [param index] is higher than the child count.
</description>
</method>
<method name="deselect">
@@ -60,17 +60,17 @@
<method name="erase_button">
<return type="void" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Removes the button at index [param button_idx] in column [param column].
+ Removes the button at index [param button_index] in column [param column].
</description>
</method>
<method name="get_button" qualifiers="const">
<return type="Texture2D" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Returns the [Texture2D] of the button at index [param button_idx] in column [param column].
+ Returns the [Texture2D] of the button at index [param button_index] in column [param column].
</description>
</method>
<method name="get_button_by_id" qualifiers="const">
@@ -91,17 +91,17 @@
<method name="get_button_id" qualifiers="const">
<return type="int" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Returns the ID for the button at index [param button_idx] in column [param column].
+ Returns the ID for the button at index [param button_index] in column [param column].
</description>
</method>
<method name="get_button_tooltip_text" qualifiers="const">
<return type="String" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Returns the tooltip text for the button at index [param button_idx] in column [param column].
+ Returns the tooltip text for the button at index [param button_index] in column [param column].
</description>
</method>
<method name="get_cell_mode" qualifiers="const">
@@ -113,9 +113,9 @@
</method>
<method name="get_child">
<return type="TreeItem" />
- <param index="0" name="idx" type="int" />
+ <param index="0" name="index" type="int" />
<description>
- Returns a child item by its index (see [method get_child_count]). This method is often used for iterating all children of an item.
+ Returns a child item by its [param index] (see [method get_child_count]). This method is often used for iterating all children of an item.
Negative indices access the children from the last one.
</description>
</method>
@@ -332,9 +332,9 @@
<method name="is_button_disabled" qualifiers="const">
<return type="bool" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<description>
- Returns [code]true[/code] if the button at index [param button_idx] for the given [param column] is disabled.
+ Returns [code]true[/code] if the button at index [param button_index] for the given [param column] is disabled.
</description>
</method>
<method name="is_checked" qualifiers="const">
@@ -419,28 +419,28 @@
<method name="set_button">
<return type="void" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<param index="2" name="button" type="Texture2D" />
<description>
- Sets the given column's button [Texture2D] at index [param button_idx] to [param button].
+ Sets the given column's button [Texture2D] at index [param button_index] to [param button].
</description>
</method>
<method name="set_button_color">
<return type="void" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<param index="2" name="color" type="Color" />
<description>
- Sets the given column's button color at index [param button_idx] to [param color].
+ Sets the given column's button color at index [param button_index] to [param color].
</description>
</method>
<method name="set_button_disabled">
<return type="void" />
<param index="0" name="column" type="int" />
- <param index="1" name="button_idx" type="int" />
+ <param index="1" name="button_index" type="int" />
<param index="2" name="disabled" type="bool" />
<description>
- If [code]true[/code], disables the button at index [param button_idx] in the given [param column].
+ If [code]true[/code], disables the button at index [param button_index] in the given [param column].
</description>
</method>
<method name="set_cell_mode">
diff --git a/doc/classes/Tween.xml b/doc/classes/Tween.xml
index eef35049e5..fc0dd9f05d 100644
--- a/doc/classes/Tween.xml
+++ b/doc/classes/Tween.xml
@@ -11,7 +11,7 @@
[codeblocks]
[gdscript]
var tween = get_tree().create_tween()
- tween.tween_property($Sprite, "modulate", Color.red, 1)
+ tween.tween_property($Sprite, "modulate", Color.RED, 1)
tween.tween_property($Sprite, "scale", Vector2(), 1)
tween.tween_callback($Sprite.queue_free)
[/gdscript]
@@ -27,7 +27,7 @@
[codeblocks]
[gdscript]
var tween = get_tree().create_tween()
- tween.tween_property($Sprite, "modulate", Color.red, 1).set_trans(Tween.TRANS_SINE)
+ tween.tween_property($Sprite, "modulate", Color.RED, 1).set_trans(Tween.TRANS_SINE)
tween.tween_property($Sprite, "scale", Vector2(), 1).set_trans(Tween.TRANS_BOUNCE)
tween.tween_callback($Sprite.queue_free)
[/gdscript]
@@ -42,7 +42,7 @@
[codeblocks]
[gdscript]
var tween = get_tree().create_tween().bind_node(self).set_trans(Tween.TRANS_ELASTIC)
- tween.tween_property($Sprite, "modulate", Color.red, 1)
+ tween.tween_property($Sprite, "modulate", Color.RED, 1)
tween.tween_property($Sprite, "scale", Vector2(), 1)
tween.tween_callback($Sprite.queue_free)
[/gdscript]
@@ -288,8 +288,8 @@
[codeblocks]
[gdscript]
var tween = get_tree().create_tween()
- tween.tween_callback($Sprite.set_modulate.bind(Color.red)).set_delay(2)
- tween.tween_callback($Sprite.set_modulate.bind(Color.blue)).set_delay(2)
+ tween.tween_callback($Sprite.set_modulate.bind(Color.RED)).set_delay(2)
+ tween.tween_callback($Sprite.set_modulate.bind(Color.BLUE)).set_delay(2)
[/gdscript]
[csharp]
Tween tween = GetTree().CreateTween();
diff --git a/doc/classes/UndoRedo.xml b/doc/classes/UndoRedo.xml
index 7258efbdda..42baf7728d 100644
--- a/doc/classes/UndoRedo.xml
+++ b/doc/classes/UndoRedo.xml
@@ -17,7 +17,7 @@
func undo_something():
pass # Put here the code that reverts what's done by "do_something()".
- func _on_MyButton_pressed():
+ func _on_my_button_pressed():
var node = get_node("MyNode2D")
undo_redo.create_action("Move the node")
undo_redo.add_do_method(self, "do_something")
diff --git a/doc/classes/Variant.xml b/doc/classes/Variant.xml
index 6b384d6a77..5416468ab6 100644
--- a/doc/classes/Variant.xml
+++ b/doc/classes/Variant.xml
@@ -38,7 +38,7 @@
# To get the name of the underlying Object type, you need the `get_class()` method.
print("foo is a(n) %s" % foo.get_class()) # inject the class name into a formatted string.
# Note also that there is not yet any way to get a script's `class_name` string easily.
- # To fetch that value, you need to dig deeply into a hidden ProjectSettings setting: an Array of Dictionaries called "_global_script_classes".
+ # To fetch that value, you can parse the [code]res://.godot/global_script_class_cache.cfg[/code] file with the [ConfigFile] API.
# Open your project.godot file to see it up close.
[/gdscript]
[csharp]
@@ -70,6 +70,6 @@
Modifications to a container will modify all references to it. A [Mutex] should be created to lock it if multi-threaded access is desired.
</description>
<tutorials>
- <link title="Variant class">$DOCS_URL/development/cpp/variant_class.html</link>
+ <link title="Variant class introduction">$DOCS_URL/contributing/development/core_and_modules/variant_class.html</link>
</tutorials>
</class>
diff --git a/doc/classes/VisualInstance3D.xml b/doc/classes/VisualInstance3D.xml
index e069642e50..3781045c02 100644
--- a/doc/classes/VisualInstance3D.xml
+++ b/doc/classes/VisualInstance3D.xml
@@ -64,7 +64,7 @@
<member name="sorting_offset" type="float" setter="set_sorting_offset" getter="get_sorting_offset" default="0.0">
The sorting offset used by this [VisualInstance3D]. Adjusting it to a higher value will make the [VisualInstance3D] reliably draw on top of other [VisualInstance3D]s that are otherwise positioned at the same spot.
</member>
- <member name="sorting_use_aabb_center" type="bool" setter="set_sorting_use_aabb_center" getter="is_sorting_use_aabb_center" default="true">
+ <member name="sorting_use_aabb_center" type="bool" setter="set_sorting_use_aabb_center" getter="is_sorting_use_aabb_center">
If [code]true[/code], the object is sorted based on the [AABB] center. The object will be sorted based on the global position otherwise.
The [AABB] center based sorting is generally more accurate for 3D models. The position based sorting instead allows to better control the drawing order when working with [GPUParticles3D] and [CPUParticles3D].
</member>
diff --git a/doc/classes/VisualShaderNode.xml b/doc/classes/VisualShaderNode.xml
index f95f871e52..685f5d5eef 100644
--- a/doc/classes/VisualShaderNode.xml
+++ b/doc/classes/VisualShaderNode.xml
@@ -58,13 +58,6 @@
Sets the output port index which will be showed for preview. If set to [code]-1[/code] no port will be open for preview.
</member>
</members>
- <signals>
- <signal name="editor_refresh_request">
- <description>
- Emitted when the node requests an editor refresh. Currently called only in setter of [member VisualShaderNodeTexture.source], [VisualShaderNodeTexture], and [VisualShaderNodeCubemap] (and their derivatives).
- </description>
- </signal>
- </signals>
<constants>
<constant name="PORT_TYPE_SCALAR" value="0" enum="PortType">
Floating-point scalar. Translated to [code]float[/code] type in shader code.
diff --git a/doc/classes/VisualShaderNodeTexture.xml b/doc/classes/VisualShaderNodeTexture.xml
index 72a7fadf1a..38fa98b21e 100644
--- a/doc/classes/VisualShaderNodeTexture.xml
+++ b/doc/classes/VisualShaderNodeTexture.xml
@@ -33,12 +33,18 @@
Use the texture from this shader's normal map built-in.
</constant>
<constant name="SOURCE_DEPTH" value="4" enum="Source">
- Use the depth texture available for this shader.
+ Use the depth texture captured during the depth prepass. Only available when the depth prepass is used (i.e. in spatial shaders and in the forward_plus or gl_compatibility renderers).
</constant>
<constant name="SOURCE_PORT" value="5" enum="Source">
Use the texture provided in the input port for this function.
</constant>
- <constant name="SOURCE_MAX" value="6" enum="Source">
+ <constant name="SOURCE_3D_NORMAL" value="6" enum="Source">
+ Use the normal buffer captured during the depth prepass. Only available when the normal-roughness buffer is available (i.e. in spatial shaders and in the forward_plus renderer).
+ </constant>
+ <constant name="SOURCE_ROUGHNESS" value="7" enum="Source">
+ Use the roughness buffer captured during the depth prepass. Only available when the normal-roughness buffer is available (i.e. in spatial shaders and in the forward_plus renderer).
+ </constant>
+ <constant name="SOURCE_MAX" value="8" enum="Source">
Represents the size of the [enum Source] enum.
</constant>
<constant name="TYPE_DATA" value="0" enum="TextureType">
diff --git a/doc/classes/VisualShaderNodeTextureParameter.xml b/doc/classes/VisualShaderNodeTextureParameter.xml
index 333226dc58..8a08bea659 100644
--- a/doc/classes/VisualShaderNodeTextureParameter.xml
+++ b/doc/classes/VisualShaderNodeTextureParameter.xml
@@ -18,6 +18,9 @@
<member name="texture_repeat" type="int" setter="set_texture_repeat" getter="get_texture_repeat" enum="VisualShaderNodeTextureParameter.TextureRepeat" default="0">
Sets the texture repeating mode. See [enum TextureRepeat] for options.
</member>
+ <member name="texture_source" type="int" setter="set_texture_source" getter="get_texture_source" enum="VisualShaderNodeTextureParameter.TextureSource" default="0">
+ Sets the texture source mode. Used for reading from the screen, depth, or normal_roughness texture. see [enum TextureSource] for options.
+ </member>
<member name="texture_type" type="int" setter="set_texture_type" getter="get_texture_type" enum="VisualShaderNodeTextureParameter.TextureType" default="0">
Defines the type of data provided by the source texture. See [enum TextureType] for options.
</member>
@@ -88,5 +91,20 @@
<constant name="REPEAT_MAX" value="3" enum="TextureRepeat">
Represents the size of the [enum TextureRepeat] enum.
</constant>
+ <constant name="SOURCE_NONE" value="0" enum="TextureSource">
+ The texture source is not specified in the shader.
+ </constant>
+ <constant name="SOURCE_SCREEN" value="1" enum="TextureSource">
+ The texture source is the screen texture which captures all opaque objects drawn this frame.
+ </constant>
+ <constant name="SOURCE_DEPTH" value="2" enum="TextureSource">
+ The texture source is the depth texture from the depth prepass.
+ </constant>
+ <constant name="SOURCE_NORMAL_ROUGHNESS" value="3" enum="TextureSource">
+ The texture source is the normal-roughness buffer from the depth prepass.
+ </constant>
+ <constant name="SOURCE_MAX" value="4" enum="TextureSource">
+ Represents the size of the [enum TextureSource] enum.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Window.xml b/doc/classes/Window.xml
index 4cd6cf41da..da31e6761e 100644
--- a/doc/classes/Window.xml
+++ b/doc/classes/Window.xml
@@ -527,6 +527,39 @@
Set's the window's current mode.
[b]Note:[/b] Fullscreen mode is not exclusive full screen on Windows and Linux.
</member>
+ <member name="mouse_passthrough" type="bool" setter="set_flag" getter="get_flag" default="false">
+ If [code]true[/code], all mouse event as passed to the underlying window of the same application. See also [member mouse_passthrough_polygon].
+ [b]Note:[/b] This property is implemented on Linux (X11), macOS and Windows.
+ </member>
+ <member name="mouse_passthrough_polygon" type="PackedVector2Array" setter="set_mouse_passthrough_polygon" getter="get_mouse_passthrough_polygon" default="PackedVector2Array()">
+ Sets a polygonal region of the window which accepts mouse events. Mouse events outside the region will be passed through.
+ Passing an empty array will disable passthrough support (all mouse events will be intercepted by the window, which is the default behavior).
+ [codeblocks]
+ [gdscript]
+ # Set region, using Path2D node.
+ $Window.mouse_passthrough_polygon = $Path2D.curve.get_baked_points()
+
+ # Set region, using Polygon2D node.
+ $Window.mouse_passthrough_polygon = $Polygon2D.polygon
+
+ # Reset region to default.
+ $Window.mouse_passthrough_polygon = []
+ [/gdscript]
+ [csharp]
+ // Set region, using Path2D node.
+ GetNode&lt;Window&gt;("Window").MousePassthrough = GetNode&lt;Path2D&gt;("Path2D").Curve.GetBakedPoints();
+
+ // Set region, using Polygon2D node.
+ GetNode&lt;Window&gt;("Window").MousePassthrough = GetNode&lt;Polygon2D&gt;("Polygon2D").Polygon;
+
+ // Reset region to default.
+ GetNode&lt;Window&gt;("Window").MousePassthrough = new Vector2[] {};
+ [/csharp]
+ [/codeblocks]
+ [b]Note:[/b] This property is ignored if [member mouse_passthrough] is set to [code]true[/code].
+ [b]Note:[/b] On Windows, the portion of a window that lies outside the region is not drawn, while on Linux (X11) and macOS it is.
+ [b]Note:[/b] This property is implemented on Linux (X11), macOS and Windows.
+ </member>
<member name="popup_window" type="bool" setter="set_flag" getter="get_flag" default="false">
If [code]true[/code], the [Window] will be considered a popup. Popups are sub-windows that don't show as separate windows in system's window manager's window list and will send close request when anything is clicked outside of them (unless [member exclusive] is enabled).
</member>
@@ -695,7 +728,10 @@
Window content is expanded to the full size of the window. Unlike borderless window, the frame is left intact and can be used to resize the window, title bar is transparent, but have minimize/maximize/close buttons. Set with [member extend_to_title].
[b]Note:[/b] This flag is implemented on macOS.
</constant>
- <constant name="FLAG_MAX" value="7" enum="Flags">
+ <constant name="FLAG_MOUSE_PASSTHROUGH" value="7" enum="Flags">
+ All mouse events are passed to the underlying window of the same application.
+ </constant>
+ <constant name="FLAG_MAX" value="8" enum="Flags">
Max value of the [enum Flags].
</constant>
<constant name="CONTENT_SCALE_MODE_DISABLED" value="0" enum="ContentScaleMode">
diff --git a/doc/classes/bool.xml b/doc/classes/bool.xml
index d0ef664281..e1a98f0ea4 100644
--- a/doc/classes/bool.xml
+++ b/doc/classes/bool.xml
@@ -60,7 +60,7 @@
_can_shoot = false
_cool_down.start()
- func _on_CoolDownTimer_timeout():
+ func _on_cool_down_timer_timeout():
_can_shoot = true
[/gdscript]
[csharp]
diff --git a/doc/translations/ar.po b/doc/translations/ar.po
index 751017b573..eb8e6dc7b6 100644
--- a/doc/translations/ar.po
+++ b/doc/translations/ar.po
@@ -30107,7 +30107,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/ca.po b/doc/translations/ca.po
index 1552c15271..cce60f13ac 100644
--- a/doc/translations/ca.po
+++ b/doc/translations/ca.po
@@ -30023,7 +30023,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/classes.pot b/doc/translations/classes.pot
index 40ab5e3413..3c793335e2 100644
--- a/doc/translations/classes.pot
+++ b/doc/translations/classes.pot
@@ -1,6 +1,6 @@
# LANGUAGE translation of the Godot Engine class reference.
-# Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.
-# Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).
+# Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md).
+# Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
# This file is distributed under the same license as the Godot source code.
#
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
@@ -29900,7 +29900,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/cs.po b/doc/translations/cs.po
index 1bd920e19b..b2072217a1 100644
--- a/doc/translations/cs.po
+++ b/doc/translations/cs.po
@@ -30498,7 +30498,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/de.po b/doc/translations/de.po
index 1533aa651d..14d2291f8c 100644
--- a/doc/translations/de.po
+++ b/doc/translations/de.po
@@ -33701,7 +33701,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/el.po b/doc/translations/el.po
index 13c4fbfe68..63ddea8f7b 100644
--- a/doc/translations/el.po
+++ b/doc/translations/el.po
@@ -29951,7 +29951,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/es.po b/doc/translations/es.po
index 8ed223238d..9462004570 100644
--- a/doc/translations/es.po
+++ b/doc/translations/es.po
@@ -39,12 +39,13 @@
# Keyla Arroyos <keylaarroyos@protonmail.com>, 2022.
# Victor Stancioiu <victorstancioiu@gmail.com>, 2022.
# yohanger <yohangerariel@gmail.com>, 2022.
+# Mateo <mfdez920@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-11-29 20:23+0000\n"
-"Last-Translator: yohanger <yohangerariel@gmail.com>\n"
+"PO-Revision-Date: 2023-01-12 06:06+0000\n"
+"Last-Translator: Mateo <mfdez920@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/es/>\n"
"Language: es\n"
@@ -52,7 +53,7 @@ msgstr ""
"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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -751,7 +752,6 @@ msgstr ""
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns an array of dictionaries representing the current call stack. See "
"also [method print_stack].\n"
@@ -776,7 +776,7 @@ msgid ""
"projects exported in debug mode if not connected to a debugging server."
msgstr ""
"Devuelve un conjunto de diccionarios que representan la pila de llamadas "
-"actual.\n"
+"actual. Véase también [method print_stack].\n"
"[codeblock]\n"
"func _ready():\n"
" foo()\n"
@@ -39560,6 +39560,7 @@ msgid ""
msgstr ""
#: doc/classes/Input.xml
+#, fuzzy
msgid ""
"Sets a custom mouse cursor image, which is only visible inside the game "
"window. The hotspot can also be specified. Passing [code]null[/code] to the "
@@ -39571,7 +39572,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
"Establece una imagen personalizada del cursor del ratón, que sólo es visible "
"dentro de la ventana del juego. También se puede especificar el punto de "
diff --git a/doc/translations/et.po b/doc/translations/et.po
index 7f92671d8f..b7512b6ae5 100644
--- a/doc/translations/et.po
+++ b/doc/translations/et.po
@@ -29913,7 +29913,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/fa.po b/doc/translations/fa.po
index 787c7ff937..ce5dd6b0c2 100644
--- a/doc/translations/fa.po
+++ b/doc/translations/fa.po
@@ -30352,7 +30352,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/fi.po b/doc/translations/fi.po
index fc517a6ff5..0f19296424 100644
--- a/doc/translations/fi.po
+++ b/doc/translations/fi.po
@@ -30034,7 +30034,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/fil.po b/doc/translations/fil.po
index 749fea9ef9..bfa8c75c7a 100644
--- a/doc/translations/fil.po
+++ b/doc/translations/fil.po
@@ -29919,7 +29919,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/fr.po b/doc/translations/fr.po
index 2898e9ec19..a57c138429 100644
--- a/doc/translations/fr.po
+++ b/doc/translations/fr.po
@@ -60,13 +60,14 @@
# Augustin Ambiehl <ambiehlaugustin@gmail.com>, 2022.
# Landry Simo <landrysimo99@gmail.com>, 2022.
# Alexis Coudert <coudert.alex@gmail.com>, 2022.
+# Callim Ethee <callimethee@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-12-03 00:47+0000\n"
-"Last-Translator: Alexis Coudert <coudert.alex@gmail.com>\n"
+"PO-Revision-Date: 2023-01-01 02:51+0000\n"
+"Last-Translator: Callim Ethee <callimethee@gmail.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/fr/>\n"
"Language: fr\n"
@@ -74,7 +75,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -137,9 +138,8 @@ msgid "Default"
msgstr "Défaut"
#: doc/tools/make_rst.py
-#, fuzzy
msgid "Setter"
-msgstr "Setter"
+msgstr "Donneur"
#: doc/tools/make_rst.py
msgid "value"
@@ -39456,7 +39456,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/gl.po b/doc/translations/gl.po
index 67bd7d902f..9b3ea41370 100644
--- a/doc/translations/gl.po
+++ b/doc/translations/gl.po
@@ -29908,7 +29908,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/hi.po b/doc/translations/hi.po
index 75318a4554..ca1ba04874 100644
--- a/doc/translations/hi.po
+++ b/doc/translations/hi.po
@@ -29907,7 +29907,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/hu.po b/doc/translations/hu.po
index e99babd548..f5a053dfc9 100644
--- a/doc/translations/hu.po
+++ b/doc/translations/hu.po
@@ -29927,7 +29927,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/id.po b/doc/translations/id.po
index ad63a828e5..8a1e757105 100644
--- a/doc/translations/id.po
+++ b/doc/translations/id.po
@@ -30324,7 +30324,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/is.po b/doc/translations/is.po
index 6bf49858f4..0afd2be589 100644
--- a/doc/translations/is.po
+++ b/doc/translations/is.po
@@ -29907,7 +29907,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/it.po b/doc/translations/it.po
index 37488c9ebd..35ff1ac6f3 100644
--- a/doc/translations/it.po
+++ b/doc/translations/it.po
@@ -31127,7 +31127,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/ja.po b/doc/translations/ja.po
index cabf1da54a..2798995dfa 100644
--- a/doc/translations/ja.po
+++ b/doc/translations/ja.po
@@ -33191,7 +33191,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/ko.po b/doc/translations/ko.po
index 72a7780a4c..3b3137f849 100644
--- a/doc/translations/ko.po
+++ b/doc/translations/ko.po
@@ -19,12 +19,13 @@
# ì´ì§€ë¯¼ <jiminaleejung@gmail.com>, 2022.
# nulltable <un5450@naver.com>, 2022.
# Godoto <aicompose@gmail.com>, 2022.
+# 오지훈 <jule1130@naver.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-10-18 18:00+0000\n"
-"Last-Translator: Godoto <aicompose@gmail.com>\n"
+"PO-Revision-Date: 2023-01-19 14:47+0000\n"
+"Last-Translator: 오지훈 <jule1130@naver.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/ko/>\n"
"Language: ko\n"
@@ -32,11 +33,11 @@ msgstr ""
"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.15-dev\n"
+"X-Generator: Weblate 4.15.1\n"
#: doc/tools/make_rst.py
msgid "Description"
-msgstr "서술"
+msgstr "설명"
#: doc/tools/make_rst.py
msgid "Tutorials"
@@ -30234,7 +30235,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/lt.po b/doc/translations/lt.po
index 1cf0ffef48..c52d238af9 100644
--- a/doc/translations/lt.po
+++ b/doc/translations/lt.po
@@ -29917,7 +29917,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/lv.po b/doc/translations/lv.po
index fd9ddf6f51..bf5aa78341 100644
--- a/doc/translations/lv.po
+++ b/doc/translations/lv.po
@@ -29925,7 +29925,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/mr.po b/doc/translations/mr.po
index 19db2e5f94..71013cc0e7 100644
--- a/doc/translations/mr.po
+++ b/doc/translations/mr.po
@@ -29905,7 +29905,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/nb.po b/doc/translations/nb.po
index 3b7f482e48..6431d1756d 100644
--- a/doc/translations/nb.po
+++ b/doc/translations/nb.po
@@ -29917,7 +29917,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/ne.po b/doc/translations/ne.po
index c616f7b4e1..b043d7c5af 100644
--- a/doc/translations/ne.po
+++ b/doc/translations/ne.po
@@ -29905,7 +29905,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/nl.po b/doc/translations/nl.po
index cf40d032cf..de3a4a7497 100644
--- a/doc/translations/nl.po
+++ b/doc/translations/nl.po
@@ -29978,7 +29978,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/pl.po b/doc/translations/pl.po
index cd2bedd302..a5c59f489b 100644
--- a/doc/translations/pl.po
+++ b/doc/translations/pl.po
@@ -30529,7 +30529,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/pt.po b/doc/translations/pt.po
index d3d9b9aadf..0f7b9f54e3 100644
--- a/doc/translations/pt.po
+++ b/doc/translations/pt.po
@@ -4,7 +4,7 @@
# This file is distributed under the same license as the Godot source code.
#
# Reubens Sanders <reubensst@protonmail.com>, 2021.
-# ssantos <ssantos@web.de>, 2022.
+# ssantos <ssantos@web.de>, 2022, 2023.
# Felipe SiFa <felipe@logus.digital>, 2022.
# Renu <ifpilucas@gmail.com>, 2022.
# Diogo Gomes <dgomes@graphnode.com>, 2022.
@@ -18,7 +18,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-11-18 16:48+0000\n"
+"PO-Revision-Date: 2023-01-11 16:51+0000\n"
"Last-Translator: ssantos <ssantos@web.de>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/pt/>\n"
@@ -27,7 +27,7 @@ msgstr ""
"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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -394,8 +394,8 @@ msgid ""
"[/codeblock]\n"
"This is the inverse of [method ord]."
msgstr ""
-"Retorna um caractere como uma String de um dado code point Unicode (que é "
-"compatível com ASCII code);\n"
+"Retorna um caractere como uma cadeia de caracteres de um dado code point "
+"Unicode (compatível com ASCII code);\n"
"[codeblock]\n"
"a = char(65) # a é \"A\"\n"
"a = char(65 + 32) # a é \"a\"\n"
@@ -517,15 +517,15 @@ msgid ""
"want a true content-aware comparison, you have to use [code]deep_equal[/"
"code]."
msgstr ""
-"Compara dois valores verificando seu conteúdo real, por meio de recursão em "
-"um [Array] ou [Dictionary] em todos os seus níveis.\n"
-"Esta função se asemelha ou difere de [code]==[/code] de diversas maneiras:\n"
+"Compara dois valores verificando o conteúdo real deles, por meio de recursão "
+"em um [Array] ou [Dictionary] em todos os seus níveis.\n"
+"Esta função compara a [code]==[/code] de diversas maneiras:\n"
"- Para [code]null[/code], [code]int[/code], [code]float[/code], "
"[code]String[/code], [code]Object[/code] e [code] RID[/code] tanto "
"[code]deep_equal[/code] quanto [code]==[/code] funcionam da mesma forma.\n"
"- Para [code]Dictionary[/code], [code]==[/code] considera-se igual se, e "
"somente se, ambas as variáveis apontarem para o mesmo [code]Dictionary[/"
-"code], sem recursão ou checagem de seu conteúdo.\n"
+"code], sem recursão ou checagem do seu conteúdo.\n"
"- Para [code]Array[/code], [code]==[/code] considera igual se, e somente se, "
"cada item no primeiro [code]Array[/code] for igual ao seu homólogo no "
"segundo [ code]Array[/code], conforme informado pelo próprio [code]==[/"
@@ -928,7 +928,7 @@ msgid ""
"[/codeblock]"
msgstr ""
"Retorna o comprimento da Variant [code]var[/code]. Comprimento é a contagem "
-"de caracteres de uma String, contagem de elementos de uma Array, o tamanho "
+"de caracteres de uma cadeia, contagem de elementos de uma Array, o tamanho "
"de um Dicionario, etc.\n"
"[b]Note:[/b] Gera um erro fatal se Variant não puder retornar um "
"comprimento.\n"
@@ -1361,7 +1361,7 @@ msgid ""
"distinguishes them from print messages used for debugging purposes, while "
"also displaying a stack trace when an error or warning is printed."
msgstr ""
-"Converte um ou mais argumentos de qualquer tipo para string da melhor "
+"Converte um ou mais argumentos de qualquer tipo para cadeia da melhor "
"maneira possível e imprime no console\n"
"[codeblock]\n"
"a = [1, 2, 3]\n"
@@ -1370,7 +1370,7 @@ msgstr ""
"[b]Nota:[/b] Considere usar [method push_error] e [method push_warning] para "
"imprimir mensagens de erro e aviso ao invés de [method print]. Isso os "
"distinguirá de impressões com propósito de depuração e também mostrará um "
-"rastreamento de pilha quando um erro ou aviso é impresso ."
+"rastreamento de pilha quando um erro ou aviso é impresso."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -1890,7 +1890,7 @@ msgid ""
"len(b) # Returns 12\n"
"[/codeblock]"
msgstr ""
-"Converte um ou mais argumentos de quaisquer tipos para string na melhor "
+"Converte um ou mais argumentos de quaisquer tipos para cadeia na melhor "
"maneira possível.\n"
"[codeblock]\n"
"var a = [10, 20, 30]\n"
@@ -1909,7 +1909,7 @@ msgid ""
"print(b[\"a\"]) # Prints 1\n"
"[/codeblock]"
msgstr ""
-"Converte um string formatado que foi retornado por [method var2str] para o "
+"Converte uma cadeia formatada que foi retornada por [method var2str] para o "
"valor original.\n"
"[codeblock]\n"
"a = '{ \"a\": 1, \"b\": 2 }'\n"
@@ -2025,8 +2025,8 @@ msgid ""
" push_error(\"Invalid JSON: \" + v)\n"
"[/codeblock]"
msgstr ""
-"Verifica se [code]json[/code] contém dados JSON válidos. Retorna um String "
-"vazio se válido, ou uma mensagem de erro caso contrário.\n"
+"Verifica se [code]json[/code] contém dados JSON válidos. Retorna uma cadeia "
+"vazia se for válida ou uma mensagem de erro caso contrário.\n"
"[codeblock]\n"
"j = to_json([1, 2, 3])\n"
"v = validate_json(j)\n"
@@ -2062,8 +2062,8 @@ msgid ""
"}\n"
"[/codeblock]"
msgstr ""
-"Converte uma Variant [code]var[/code] para um string formatado que pode ser "
-"convertido de volta com [method str2var].\n"
+"Converte uma Variant [code]var[/code] para uma cadeia formatada que pode ser "
+"convertida de volta com [method str2var].\n"
"[codeblock]\n"
"a = { \"a\": 1, \"b\": 2 }\n"
"print(var2str(a))\n"
@@ -3555,59 +3555,59 @@ msgstr "Máscara da tecla Group Switch."
#: doc/classes/@GlobalScope.xml
msgid "Left mouse button."
-msgstr "Botão esquerdo do mouse."
+msgstr "Botão esquerdo do rato."
#: doc/classes/@GlobalScope.xml
msgid "Right mouse button."
-msgstr "Botão direito do mouse."
+msgstr "Botão direito do rato."
#: doc/classes/@GlobalScope.xml
msgid "Middle mouse button."
-msgstr "Botão central do mouse."
+msgstr "Botão central do rato."
#: doc/classes/@GlobalScope.xml
msgid "Extra mouse button 1 (only present on some mice)."
-msgstr "Primeiro botão extra do mouse (disponível em apenas alguns mouses)."
+msgstr "Primeiro botão extra do rato (disponível em apenas alguns ratos)."
#: doc/classes/@GlobalScope.xml
msgid "Extra mouse button 2 (only present on some mice)."
-msgstr "Segundo botão extra do mouse (disponível em apenas alguns mouses)."
+msgstr "Segundo botão extra do rato (disponível em apenas alguns ratos)."
#: doc/classes/@GlobalScope.xml
msgid "Mouse wheel up."
-msgstr "Roda do mouse para cima."
+msgstr "Roda do rato para cima."
#: doc/classes/@GlobalScope.xml
msgid "Mouse wheel down."
-msgstr "Roda do mouse para baixo."
+msgstr "Roda do rato para baixo."
#: doc/classes/@GlobalScope.xml
msgid "Mouse wheel left button (only present on some mice)."
-msgstr "Botão esquerdo da roda do mouse (disponível em apenas alguns mouses)."
+msgstr "Botão esquerdo da roda do rato (disponível em apenas alguns ratos)."
#: doc/classes/@GlobalScope.xml
msgid "Mouse wheel right button (only present on some mice)."
-msgstr "Botão direito da roda do mouse (disponível em apenas alguns mouses)."
+msgstr "Botão direito da roda do rato (disponível em apenas alguns ratos)."
#: doc/classes/@GlobalScope.xml
msgid "Left mouse button mask."
-msgstr "Máscara do botão esquerdo do mouse."
+msgstr "Máscara do botão esquerdo do rato."
#: doc/classes/@GlobalScope.xml
msgid "Right mouse button mask."
-msgstr "Máscara do botão direito do mouse."
+msgstr "Máscara do botão direito do rato."
#: doc/classes/@GlobalScope.xml
msgid "Middle mouse button mask."
-msgstr "Máscara do botão central do mouse."
+msgstr "Máscara do botão central do rato."
#: doc/classes/@GlobalScope.xml
msgid "Extra mouse button 1 mask."
-msgstr "Máscara do primeiro botão extra do mouse."
+msgstr "Máscara do primeiro botão extra do rato."
#: doc/classes/@GlobalScope.xml
msgid "Extra mouse button 2 mask."
-msgstr "Máscara do segundo botão extra do mouse."
+msgstr "Máscara do segundo botão extra do rato."
#: doc/classes/@GlobalScope.xml
msgid "Invalid button or axis."
@@ -4354,7 +4354,6 @@ msgid ""
msgstr ""
#: doc/classes/@GlobalScope.xml
-#, fuzzy
msgid ""
"Hints that a float property should be edited via an exponential easing "
"function. The hint string can include [code]\"attenuation\"[/code] to flip "
@@ -4362,9 +4361,9 @@ msgid ""
"easing."
msgstr ""
"Sugere que uma propriedade float deve ser editada através de uma função de "
-"suavização. A string de sugestão pode incluir [code]\"attenuation\"[/code] "
-"para virar a curva horizontalmente e/ou [code]\"inout\"[/code] para incluir "
-"também a suavização in/out."
+"flexibilização. A cadeia de sugestão pode incluir [code]\"attenuation\"[/"
+"code] para virar a curva horizontalmente e/ou [code]\"inout\"[/code] para "
+"incluir também a flexibilização in/out."
#: doc/classes/@GlobalScope.xml
msgid "Deprecated hint, unused."
@@ -17844,11 +17843,11 @@ msgstr ""
#: doc/classes/Control.xml
msgid "Sent when the mouse pointer enters the node."
-msgstr "Enviado quando o ponteiro do mouse entra no nó."
+msgstr "Enviado quando o ponteiro do rato entra no nó."
#: doc/classes/Control.xml
msgid "Sent when the mouse pointer exits the node."
-msgstr "Enviado quando o ponteiro do mouse sai do nó."
+msgstr "Enviado quando o ponteiro do rato sai do nó."
#: doc/classes/Control.xml
msgid "Sent when the node grabs focus."
@@ -30979,7 +30978,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
@@ -37028,7 +37031,7 @@ msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
#, fuzzy
msgid "Sets the position of the agent in world space."
-msgstr "Retorna a posição global do mouse."
+msgstr "Retorna a posição global do rato."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
#, fuzzy
@@ -37256,7 +37259,7 @@ msgstr ""
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
#, fuzzy
msgid "Sets the global transformation for the region."
-msgstr "Retorna a posição global do mouse."
+msgstr "Retorna a posição global do rato."
#: doc/classes/Navigation2DServer.xml doc/classes/NavigationServer.xml
#, fuzzy
@@ -65291,11 +65294,11 @@ msgstr "Emitido quando um item é editado."
#: doc/classes/Tree.xml
msgid "Emitted when an item is edited using the right mouse button."
-msgstr "Emitido quando um item é editado com botão direito do mouse."
+msgstr "Emitido quando um item é editado com botão direito do rato."
#: doc/classes/Tree.xml
msgid "Emitted when an item is selected with the right mouse button."
-msgstr "Emitido quando um item é selecionado com o botão direito do mouse."
+msgstr "Emitido quando um item é selecionado com o botão direito do rato."
#: doc/classes/Tree.xml
msgid "Emitted when an item is selected."
@@ -65310,7 +65313,7 @@ msgstr ""
#: doc/classes/Tree.xml
msgid "Emitted when a left mouse button click does not select any item."
msgstr ""
-"Emitido quando um clique com o botão esquerdo do mouse não seleciona nenhum "
+"Emitido quando um clique com o botão esquerdo do rato não seleciona nenhum "
"item."
#: doc/classes/Tree.xml
diff --git a/doc/translations/pt_BR.po b/doc/translations/pt_BR.po
index 463bc9c957..687566bef1 100644
--- a/doc/translations/pt_BR.po
+++ b/doc/translations/pt_BR.po
@@ -45,12 +45,13 @@
# Mr.Albino <ricmorsoleto@gmail.com>, 2022.
# Zer0-Zer0 <dankmemerson@tutanota.com>, 2022.
# Julio Yagami <juliohenrique31501234@hotmail.com>, 2022.
+# Andrey Gonçalves <kaptaryd@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-12-09 19:48+0000\n"
-"Last-Translator: Julio Yagami <juliohenrique31501234@hotmail.com>\n"
+"PO-Revision-Date: 2023-01-09 20:42+0000\n"
+"Last-Translator: Andrey Gonçalves <kaptaryd@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot-class-reference/pt_BR/>\n"
"Language: pt_BR\n"
@@ -58,7 +59,7 @@ msgstr ""
"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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -860,7 +861,6 @@ msgstr ""
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns an interpolation or extrapolation factor considering the range "
"specified in [code]from[/code] and [code]to[/code], and the interpolated "
@@ -883,8 +883,26 @@ msgid ""
"See also [method lerp] which performs the reverse of this operation, and "
"[method range_lerp] to map a continuous series of values to another."
msgstr ""
-"Retornar a interpolação ou extrapolação do fator considerando o ranger "
-"específico [code ]para[/code]"
+"Retorna o fator de interpolação ou extrapolação considerando o intervalo "
+"especificado no [code]de[/code] e [code]para[/code], e o valor interpolado "
+"especificado no [code]peso[/code]. O valor retornado irá ser entre "
+"[code]0.0[/code] e [code]1.0[/code] se [code]peso[/code] for entre [code]de[/"
+"code] e [code]para[/code] (inclusivo). Se [code]peso[/code] está fora do "
+"intervalo especificado, então um fator de extrapolação será retornado "
+"(retorna valor menor que [code]0.0[/code] ou maior que [code]1.0[/code]). "
+"Use [method clamp] no resultado do [method inverse_lerp] se isso não for o "
+"desejado.\n"
+"[codeblock]\n"
+"# A razão da interpolação no uso do `lerp()` abaixo é 0.75.\n"
+"var meio = lerp(20, 30, 0.75)\n"
+"#`meio` agora é 27.5.\n"
+"# Agora, vamos fingir que esquecemos a razão original e o queremos de "
+"volta.\n"
+"var razao = inverse_lerp(20, 30, 27.5)\n"
+"#`razao` agora é 0.75.\n"
+"[/codeblock]\n"
+"Veja também o [method lerp] que faz o inverso desta operação, e [method "
+"range_lerp] para mapear uma série contínua de valores uns aos outros."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -1423,6 +1441,17 @@ msgid ""
"print_stack] will not work in projects exported in release mode, or in "
"projects exported in debug mode if not connected to a debugging server."
msgstr ""
+"Imprime um rastreamento de pilha no local do código atual. Veja também "
+"[method get_stack]\n"
+"A saída no console seria mais ou menos assim:\n"
+"[codeblock]\n"
+"Frame 0 - res://test.gd:16 in function '_process'\n"
+"[/codeblock]\n"
+"[b]Nota:[/b] [method print_stack] só funciona se a instância em execução "
+"estiver conectada a um servidor de depuração (ou seja, uma instância do "
+"editor). [method print_stack] não funcionará em projetos exportados no modo "
+"de lançamento ou em projetos exportados no modo de depuração se não estiver "
+"conectado a um servidor de depuração."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -4070,74 +4099,105 @@ msgid ""
"down on the key after it \"bottoms out\". This message is different from "
"polyphonic after-touch as it indicates the highest pressure across all keys."
msgstr ""
+"Mensagem de pressão do canal MIDI. Esta mensagem geralmente é enviada ao "
+"pressionar a tecla após ela \"ir de dentro pra fora\". Essa mensagem é "
+"diferente do pós-toque polifônico, pois indica a pressão mais alta em todas "
+"as teclas."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI pitch bend message. This message is sent to indicate a change in the "
"pitch bender (wheel or lever, typically)."
msgstr ""
+"Mensagem MIDI de dobra de tom (pitch bend). Esta mensagem é enviada para "
+"indicar uma mudança no dobrador de tom (roda ou alavanca, tipicamente)."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI system exclusive message. This has behavior exclusive to the device "
"you're receiving input from. Getting this data is not implemented in Godot."
msgstr ""
+"Mensagem exclusiva do sistema MIDI. Isso tem um comportamento exclusivo do "
+"dispositivo do qual você está recebendo entrada. A obtenção desses dados não "
+"está implementada no Godot."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI quarter frame message. Contains timing information that is used to "
"synchronize MIDI devices. Getting this data is not implemented in Godot."
msgstr ""
+"Mensagem MIDI de um quarto de quadro. Contém informações de tempo usadas "
+"para sincronizar dispositivos MIDI. A obtenção desses dados não está "
+"implementada no Godot."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI song position pointer message. Gives the number of 16th notes since the "
"start of the song. Getting this data is not implemented in Godot."
msgstr ""
+"Mensagem de ponteiro de posição de música MIDI. Dá o número de semicolcheias "
+"(cada 16ª nota) desde o início da música. A obtenção desses dados não está "
+"implementada no Godot."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI song select message. Specifies which sequence or song is to be played. "
"Getting this data is not implemented in Godot."
msgstr ""
+"Mensagem MIDI de seleção de música. Especifica qual sequência ou música será "
+"tocada. A obtenção desses dados não está implementada no Godot."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI tune request message. Upon receiving a tune request, all analog "
"synthesizers should tune their oscillators."
msgstr ""
+"Mensagem de solicitação de sintonia MIDI. Ao receber uma solicitação de "
+"sintonia, todos os sintetizadores analógicos devem sintonizar seus "
+"osciladores."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI timing clock message. Sent 24 times per quarter note when "
"synchronization is required."
msgstr ""
+"Mensagem de relógio de tempo MIDI. Enviado 24 vezes por semínima quando a "
+"sincronização é necessária."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI start message. Start the current sequence playing. This message will be "
"followed with Timing Clocks."
msgstr ""
+"mensagem de início MIDI. Inicie a reprodução da sequência atual. Esta "
+"mensagem será seguida de relógios de temporização."
#: doc/classes/@GlobalScope.xml
msgid "MIDI continue message. Continue at the point the sequence was stopped."
msgstr ""
+"Mensagem de continuação MIDI. Continue no ponto em que a sequência foi "
+"interrompida."
#: doc/classes/@GlobalScope.xml
msgid "MIDI stop message. Stop the current sequence."
-msgstr ""
+msgstr "Mensagem de parada MIDI. Pare a sequência atual."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI active sensing message. This message is intended to be sent repeatedly "
"to tell the receiver that a connection is alive."
msgstr ""
+"Mensagem de detecção ativa de MIDI. Esta mensagem deve ser enviada "
+"repetidamente para informar ao receptor que uma conexão está ativa."
#: doc/classes/@GlobalScope.xml
msgid ""
"MIDI system reset message. Reset all receivers in the system to power-up "
"status. It should not be sent on power-up itself."
msgstr ""
+"Mensagem de reinicialização do sistema MIDI. Redefina todos os receptores no "
+"sistema para o status de inicialização. Ele não deve ser enviado no próprio "
+"power-up."
#: doc/classes/@GlobalScope.xml
msgid ""
@@ -31205,7 +31265,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/ro.po b/doc/translations/ro.po
index dd88e8d66b..94c966c61c 100644
--- a/doc/translations/ro.po
+++ b/doc/translations/ro.po
@@ -29940,7 +29940,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/ru.po b/doc/translations/ru.po
index 9d569d7760..b76873e4f1 100644
--- a/doc/translations/ru.po
+++ b/doc/translations/ru.po
@@ -57,12 +57,14 @@
# Handsless coder <yfintktajy1@gmail.com>, 2022.
# Evgeniy Khramov <thejenjagamertjg@gmail.com>, 2022.
# Григорий <bolon667@gmail.com>, 2022.
+# Artur Leonov (Depish) <depish.eskry@yandex.ru>, 2022.
+# Patrik <avdmur@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-12-06 11:48+0000\n"
-"Last-Translator: Григорий <bolon667@gmail.com>\n"
+"PO-Revision-Date: 2022-12-23 10:00+0000\n"
+"Last-Translator: Patrik <avdmur@gmail.com>\n"
"Language-Team: Russian <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/ru/>\n"
"Language: ru\n"
@@ -71,7 +73,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -127,7 +129,7 @@ msgstr "УнаÑледовано:"
#: doc/tools/make_rst.py
msgid "(overrides %s)"
-msgstr "(переназначает %s)"
+msgstr "(переопределÑет %s)"
#: doc/tools/make_rst.py
msgid "Default"
@@ -461,9 +463,9 @@ msgstr ""
"Ограничивает [code]value[/code], Ð²Ð¾Ð·Ð²Ñ€Ð°Ñ‰Ð°Ñ Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ðµ не меньше [code]min[/"
"code] и не больше [code]max[/code].\n"
"[codeblock]\n"
-"a = clamp(1000, 1, 20) # a будет 20\n"
-"a = clamp(-10, 1, 20) # a будет 1\n"
-"a = clamp(15, 1, 20) # a будет 15\n"
+"a = clamp(1000, 1, 20) # вернёт 20\n"
+"a = clamp(-10, 1, 20) # вернёт 1\n"
+"a = clamp(15, 1, 20) # вернёт 15\n"
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
@@ -534,12 +536,12 @@ msgid ""
"a = dectime(60, 10, 0.1)) # a is 59.0\n"
"[/codeblock]"
msgstr ""
-"[b]Примечание:[/b] [code]dectime[/code] был уÑтаревшим и будет удален в "
-"Godot 4.0, пожалуйÑта, иÑпользуйте [метод move_toward] вмеÑто него.\n"
+"[b]Примечание:[/b] [code]dectime[/code] уÑтарел и будет удален в Godot 4.0, "
+"пожалуйÑта, иÑпользуйте [method move_toward] вмеÑто него.\n"
"Возвращает результат [code]value[/code], уменьшенный на [code]step[/code] * "
"[code]amount[/code].\n"
"[codeblock]\n"
-"a = dectime(60, 10, 0.1)) # a равно 59.0\n"
+"a = dectime(60, 10, 0.1)) # вернёт59.0\n"
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
@@ -635,7 +637,7 @@ msgstr ""
"[/codeblock]\n"
"[url=https://raw.githubusercontent.com/godotengine/godot-docs/3.4/img/"
"ease_cheatsheet.png]ease() шпаргалка значений кривой[/url]\n"
-"См. также [метод smoothstep]. ЕÑли вам нужно выполнить более Ñложные "
+"См. также [method smoothstep]. ЕÑли вам нужно выполнить более Ñложные "
"переходы, иÑпользуйте [Tween] или [AnimationPlayer]."
#: modules/gdscript/doc_classes/@GDScript.xml
@@ -766,7 +768,6 @@ msgstr ""
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns an array of dictionaries representing the current call stack. See "
"also [method print_stack].\n"
@@ -790,22 +791,27 @@ msgid ""
"get_stack] will not work in projects exported in release mode, or in "
"projects exported in debug mode if not connected to a debugging server."
msgstr ""
-"Возвращает маÑÑив Ñловарей, предÑтавлÑющий текущий Ñтек вызовов.\n"
+"Возвращает маÑÑив Ñловарей, предÑтавлÑющий текущий Ñтек вызовов. См. также "
+"[method print_stack].\n"
"[codeblock]\n"
"func _ready():\n"
-" foo()\n"
+"\tfoo()\n"
"\n"
"func foo():\n"
-" bar()\n"
+"\tbar()\n"
"\n"
"func bar():\n"
-" print(get_stack())\n"
+"\tprint(get_stack())\n"
"[/codeblock]\n"
"выведет\n"
"[codeblock]\n"
"[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, "
"source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]\n"
-"[/codeblock]"
+"[/codeblock]\n"
+"[b]Примечание:[/b] [method get_stack] работает только при подключенном "
+"Ñервере отладки (например в редакторе). [method get_stack] не будет работать "
+"в проектах, ÑкÑпортированных в режиме release или в проектах "
+"ÑкÑпортированных в режиме debug, еÑли они не подключены к Ñерверу отладки."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -914,7 +920,8 @@ msgstr ""
"var ratio = inverse_lerp(20, 30, 27.5)\n"
"# `ratio` теперь 0.75.\n"
"[/codeblock]\n"
-"Смотрите также [метод lerp], который выполнÑет обратную Ñтой операцию."
+"Смотрите также [method lerp], который выполнÑет обратную операцию и [method "
+"range_lerp] Ð´Ð»Ñ Ð¾Ñ‚Ð¾Ð±Ñ€Ð°Ð¶ÐµÐ½Ð¸Ñ Ð¿Ð¾Ñледовательного Ñ€Ñда значений в другом."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -1048,23 +1055,23 @@ msgid ""
msgstr ""
"Ð›Ð¸Ð½ÐµÐ¹Ð½Ð°Ñ Ð¸Ð½Ñ‚ÐµÑ€Ð¿Ð¾Ð»ÑÑ†Ð¸Ñ Ð¼ÐµÐ¶Ð´Ñƒ Ð´Ð²ÑƒÐ¼Ñ ÑƒÐ³Ð»Ð°Ð¼Ð¸ (в радианах) по нормализованному "
"значению.\n"
-"Ðналогично [методу lerp], но корректно интерполируетÑÑ, когда углы "
-"оборачивают вокруг [конÑтанты @GDScript.TAU]. Чтобы выполнить упрощенную "
-"интерполÑцию Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [метода lerp_angle], объедините его Ñ [методом ease] "
-"или [методом smoothstep].\n"
+"Ðналогично [method lerp], но корректно интерполируетÑÑ, когда углы "
+"оборачивают вокруг [constant @GDScript.TAU]. Чтобы выполнить упрощенную "
+"интерполÑцию Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [method lerp_angle], объедините его Ñ [method ease] "
+"или [method smoothstep].\n"
"[codeblock]\n"
"extends Sprite\n"
"var elapsed = 0.0\n"
"func _process(delta):\n"
-" var min_angle = deg2rad(0.0)\n"
-" var max_angle = deg2rad(90.0)\n"
-" rotation = lerp_angle(min_angle, max_angle, elapsed)\n"
-" elapsed += delta\n"
+"\tvar min_angle = deg2rad(0.0)\n"
+"\tvar max_angle = deg2rad(90.0)\n"
+"\trotation = lerp_angle(min_angle, max_angle, elapsed)\n"
+"\telapsed += delta\n"
"[/codeblock]\n"
"[b]Примечание:[/b] Этот метод проходит через кратчайший путь между "
"[code]from[/code] и [code]to[/code]. Тем не менее, еÑли разница между Ñтими "
-"Ð´Ð²ÑƒÐ¼Ñ ÑƒÐ³Ð»Ð°Ð¼Ð¸ и любым целым чиÑлом [code]k[/code] приблизительно [code]PI + "
-"k * TAU[/code], неочевидно в какую Ñторону [/code]из-за ошибок в точноÑти "
+"Ð´Ð²ÑƒÐ¼Ñ ÑƒÐ³Ð»Ð°Ð¼Ð¸ и любым целым чиÑлом [code]k[/code] приблизительно [code]PI + k "
+"* TAU[/code], неочевидно в какую Ñторону [/code]из-за ошибок в точноÑти "
"чиÑел Ñ Ð¿Ð»Ð°Ð²Ð°ÑŽÑ‰ÐµÐ¹ точкой. Ðапример, [code]lerp_angle(0, PI, weight)[/code] "
"оборачиваетÑÑ Ð¿Ñ€Ð¾Ñ‚Ð¸Ð² чаÑовой Ñтрелки, а [code]lerp_angle(0, PI + 5 * TAU, "
"weight)[/code] оборачиваетÑÑ Ð¿Ð¾ чаÑовой."
@@ -1098,6 +1105,7 @@ msgstr ""
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
+#, fuzzy
msgid ""
"Loads a resource from the filesystem located at [code]path[/code]. The "
"resource is loaded on the method call (unless it's referenced already "
@@ -1124,19 +1132,19 @@ msgstr ""
"ÑÑылаютÑÑ Ð² другом меÑте, например, в другом Ñкрипте или в Ñцене), что может "
"вызвать небольшую задержку, оÑобенно при загрузке Ñцен. Чтобы избежать "
"ненужных задержек при многократной загрузке чего-либо, либо Ñохраните реÑÑƒÑ€Ñ "
-"в переменной, либо иÑпользуйте [метод preload].\n"
+"в переменной, либо иÑпользуйте [method preload].\n"
"[b]Примечание: [/b] Пути к реÑурÑам можно получить, щёлкнув правой кнопкой "
"мыши на реÑурÑе в панели Â«Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема» и выбрав \"Копировать путь\" или "
"перетащив файл из панели Â«Ð¤Ð°Ð¹Ð»Ð¾Ð²Ð°Ñ ÑиÑтема» в Ñценарий.\n"
"[codeblock]\n"
"# Load a scene called main located in the root of the project directory and "
"cache it in a variable.\n"
-"var main = load(\"res://main.tscn\") # main will contain a PackedScene "
-"resource.\n"
+"var main = load(\"res://main.tscn\") # main будет Ñодержать объект "
+"PackedScene.\n"
"[/codeblock]\n"
"[b]Важно:[/b] Путь должен быть абÑолютным, локальный путь проÑто вернет "
"[code]null[/code].\n"
-"Этот метод предÑтавлÑет Ñобой упрощенную верÑию [метода ResourceLoader."
+"Этот метод предÑтавлÑет Ñобой упрощенную верÑию [method ResourceLoader."
"load], который можно иÑпользовать Ð´Ð»Ñ Ð±Ð¾Ð»ÐµÐµ Ñложных Ñценариев."
#: modules/gdscript/doc_classes/@GDScript.xml
@@ -1449,6 +1457,16 @@ msgid ""
"print_stack] will not work in projects exported in release mode, or in "
"projects exported in debug mode if not connected to a debugging server."
msgstr ""
+"Выводит Ñтек вызовов из текущей функции. Смотрите также: [method "
+"get_stack].\n"
+"Вывод в конÑоли будет примерно таким:\n"
+"[codeblock]\n"
+"Frame 0 - res://test.gd:16 in function '_process'\n"
+"[/codeblock]\n"
+"[b]Примечание:[/b] [method print_stack] работает только при подключенном "
+"Ñервере отладки (например в редакторе). [method print_stack] не будет "
+"работать в проектах, ÑкÑпортированных в режиме release или в проектах "
+"ÑкÑпортированных в режиме debug, еÑли они не подключены к Ñерверу отладки."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -1687,7 +1705,7 @@ msgid ""
"3\n"
"[/codeblock]"
msgstr ""
-"Возвращает маÑÑив Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñ‹Ð¼ диапазоном. [метод range] может быть вызван "
+"Возвращает маÑÑив Ñ Ð·Ð°Ð´Ð°Ð½Ð½Ñ‹Ð¼ диапазоном. [method range] может быть вызван "
"Ñ‚Ñ€ÐµÐ¼Ñ ÑпоÑобами:\n"
"[code]range(n: int)[/code]: ÐачинаетÑÑ Ñ 0, увеличиваетÑÑ Ñ ÑˆÐ°Ð³Ð¾Ð¼ в 1 и "
"оÑтанавливаетÑÑ [i]перед[/i] [code]n[/code]. Ðргумент [code]n[/code] Ñто "
@@ -1702,16 +1720,16 @@ msgstr ""
"[b]инклюзив[/b] и [b]ÑкÑклюзив[/b], ÑоответÑтвенно. Ðргумент [code]s[/code] "
"[b]может[/b] быть негативным, но не [code]0[/code]. ЕÑли [code]s[/code] Ñто "
"[code]0[/code], будет выведено Ñообщение об ошибке.\n"
-"[метод range] преобразует вÑе аргументы в [int] перед обработкой.\n"
+"[method range] преобразует вÑе аргументы в [int] перед обработкой.\n"
"[b]Примечание:[/b] Возвращает пуÑтой маÑÑив, еÑли ни одно значение не "
"удовлетворÑет ограничению на значение (e.g. [code]range(2, 5, -1)[/code] или "
"[code]range(5, 5, 1)[/code]).\n"
"Примеры:\n"
"[codeblock]\n"
-"print(range(4)) # Prints [0, 1, 2, 3]\n"
-"print(range(2, 5)) # Prints [2, 3, 4]\n"
-"print(range(0, 6, 2)) # Prints [0, 2, 4]\n"
-"print(range(4, 1, -1)) # Prints [4, 3, 2]\n"
+"print(range(4)) # Выведет [0, 1, 2, 3]\n"
+"print(range(2, 5)) # Выведет [2, 3, 4]\n"
+"print(range(0, 6, 2)) # Выведет [0, 2, 4]\n"
+"print(range(4, 1, -1)) # Выведет [4, 3, 2]\n"
"[/codeblock]\n"
"Чтобы выполнить итерацию по [Array] в обратном порÑдке, иÑпользуйте:\n"
"[codeblock]\n"
@@ -1739,6 +1757,18 @@ msgid ""
"For complex use cases where you need multiple ranges, consider using [Curve] "
"or [Gradient] instead."
msgstr ""
+"Ограничивает [code]значение[/code] из диапазона [code][istart, istop][/code] "
+"до диапазона [code][ostart, ostop][/code]. Смотрите также [method lerp] и "
+"[method inverse_lerp]. ЕÑли [code]значение[/code] за пределами [code]"
+"[istart, istop][/code], тогда, выходное значение тоже будет за пределами "
+"[code][ostart, ostop][/code]. ИÑпользуйте [method clamp] Ñо значением "
+"полученным от [method range_lerp] еÑли не хотите выходить за пределы.[/"
+"code]\n"
+"[codeblock]\n"
+"range_lerp(75, 0, 100, -1, 1) # Возвращает 0.5\n"
+"[/codeblock]\n"
+"Ð”Ð»Ñ Ñлучаев где вам нужно неÑколько диапазонов, иÑпользуйте [Curve] или "
+"[Gradient]."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -1755,10 +1785,10 @@ msgstr ""
"в большую Ñторону.\n"
"[codeblock]\n"
"a = round(2.49) # Возвращает 2.0\n"
-"a = round(2.5) # Возвращает 3.0\n"
+"a = round(2.5)\t# Возвращает 3.0\n"
"a = round(2.51) # Возвращает 3.0\n"
"[/codeblock]\n"
-"См. также[метод floor], [метод ceil], [метод stepify], и [int]."
+"См. также[method floor], [method ceil], [method stepify], и [int]."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -1852,14 +1882,15 @@ msgstr ""
"S-образной кривой, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ ÑоответÑтвует значению [code]s[/code] между "
"[code]0[/code] и [code]1[/code].\n"
"S-Ð¾Ð±Ñ€Ð°Ð·Ð½Ð°Ñ ÐºÑ€Ð¸Ð²Ð°Ñ ÑвлÑетÑÑ ÐºÑƒÐ±Ð¸Ñ‡ÐµÑким Ñрмитовым Ñплайном, заданным функцией "
-"[code]f(s) = 3*s^2 - 2*s^3[/code].\n"
+"[code]f(y) = 3*y^2 - 2*y^3[/code], где [code]y = (x-from) / (to-from)[/"
+"code].\n"
"[codeblock]\n"
"smoothstep(0, 2, -5.0) # Возвращает 0.0\n"
"smoothstep(0, 2, 0.5) # Возвращает 0.15625\n"
"smoothstep(0, 2, 1.0) # Возвращает 0.5\n"
"smoothstep(0, 2, 2.0) # Возвращает 1.0\n"
"[/codeblock]\n"
-"Ð’ Ñравнении Ñ [method ease] Ñо значение кривой [code]-1.6521[/code], [метод "
+"Ð’ Ñравнении Ñ [method ease] Ñо значение кривой [code]-1.6521[/code], [method "
"smoothstep] возвращает наиболее плавную кривую без внезапных изменений "
"производной. ЕÑли вам нужно выполнить более продвинутые перемещениÑ, "
"иÑпользуйте [Tween] или [AnimationPlayer].\n"
@@ -1956,8 +1987,8 @@ msgid ""
"print(b[\"a\"]) # Prints 1\n"
"[/codeblock]"
msgstr ""
-"Преобразует форматированную Ñтроку, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±Ñ‹Ð»Ð° возвращена [методом "
-"var2str] в иÑходное значение.\n"
+"Преобразует форматированную Ñтроку, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð±Ñ‹Ð»Ð° возвращена [method var2str] "
+"в иÑходное значение.\n"
"[codeblock]\n"
"a = '{ \"a\": 1, \"b\": 2 }'\n"
"b = str2var(a)\n"
@@ -2265,7 +2296,7 @@ msgid ""
msgstr ""
"ОÑтанавливает выполнение функции и возвращает текущее приоÑтановленное "
"ÑоÑтоÑние вызывающей функции.\n"
-"Ð’Ñ‹Ð·Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° вызвать [метод GDScriptFunctionState.resume] на "
+"Ð’Ñ‹Ð·Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ñ Ð´Ð¾Ð»Ð¶Ð½Ð° вызвать [method GDScriptFunctionState.resume] на "
"ÑоÑтоÑнии Ð´Ð»Ñ Ð²Ð¾Ð·Ð¾Ð±Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ð²Ñ‹Ð¿Ð¾Ð»Ð½ÐµÐ½Ð¸Ñ. Это аннулирует ÑоÑтоÑние. Внутри "
"возобновленной функции [code]yield()[/code] возвращает вÑе, что было "
"передано в вызов функции [code]resume()[/code].\n"
@@ -2278,21 +2309,21 @@ msgstr ""
"работы функции:\n"
"[codeblock].\n"
"func _ready():\n"
-" yield(countdown(), \"completed\") # ожидание Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ "
+"\tyield(countdown(), \"completed\") # ожидание Ð·Ð°Ð²ÐµÑ€ÑˆÐµÐ½Ð¸Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ "
"countdown()\n"
-" print('Ready')\n"
+"\tprint('Ready')\n"
"\n"
"func countdown():\n"
-" yield(get_tree(), \"idle_frame\") # возвращает объект "
+"\tyield(get_tree(), \"idle_frame\") # возвращает объект "
"GDScriptFunctionState Ð´Ð»Ñ Ñ„ÑƒÐ½ÐºÑ†Ð¸Ð¸ _ready()\n"
-" print(3)\n"
-" yield(get_tree().create_timer(1.0), \"timeout\")\n"
-" print(2)\n"
-" yield(get_tree().create_timer(1.0), \"timeout\")\n"
-" print(1)\n"
-" yield(get_tree().create_timer(1.0), \"timeout\")\n"
+"\tprint(3)\n"
+"\tyield(get_tree().create_timer(1.0), \"timeout\")\n"
+"\tprint(2)\n"
+"\tyield(get_tree().create_timer(1.0), \"timeout\")\n"
+"\tprint(1)\n"
+"\tyield(get_tree().create_timer(1.0), \"timeout\")\n"
"\n"
-"# печатает:\n"
+"# выведет:\n"
"# 3\n"
"# 2\n"
"# 1\n"
@@ -13808,6 +13839,7 @@ msgid "Camera node for 2D scenes."
msgstr ""
#: doc/classes/Camera2D.xml
+#, fuzzy
msgid ""
"Camera node for 2D scenes. It forces the screen (current layer) to scroll "
"following this node. This makes it easier (and faster) to program scrollable "
@@ -13836,7 +13868,7 @@ msgstr ""
"Обратите внимание, что положение узла [Camera2D] [code][/code] не отражает "
"фактичеÑкое положение Ñкрана, которое может отличатьÑÑ Ð¸Ð·-за примененного "
"ÑÐ³Ð»Ð°Ð¶Ð¸Ð²Ð°Ð½Ð¸Ñ Ð¸Ð»Ð¸ ограничений. Ð”Ð»Ñ Ð¿Ð¾Ð»ÑƒÑ‡ÐµÐ½Ð¸Ñ Ñ€ÐµÐ°Ð»ÑŒÐ½Ð¾Ð³Ð¾ Ð¿Ð¾Ð»Ð¾Ð¶ÐµÐ½Ð¸Ñ Ð¼Ð¾Ð¶Ð½Ð¾ "
-"иÑпользовать [метод get_camera_screen_center]."
+"иÑпользовать [method get_camera_screen_center]."
#: doc/classes/Camera2D.xml doc/classes/TileMap.xml doc/classes/TileSet.xml
msgid "2D Isometric Demo"
@@ -16052,11 +16084,11 @@ msgstr ""
"ÑвойÑтва (например, CanvasItem.modulate) могут принимать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð±Ð¾Ð»ÑŒÑˆÐµ 1 "
"(переÑвет или цвета HDR).\n"
"Ð’Ñ‹ также можете Ñоздать цвет из Ñтандартизированных имен цветов Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ "
-"[метода @GDScript.ColorN] или непоÑредÑтвенно иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ñ‹Ðµ здеÑÑŒ "
+"[method @GDScript.ColorN] или непоÑредÑтвенно иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ð¾Ð¿Ñ€ÐµÐ´ÐµÐ»ÐµÐ½Ð½Ñ‹Ðµ здеÑÑŒ "
"цветовые конÑтанты. Стандартизированный набор цветов оÑнован на [url=https://"
"en.wikipedia.org/wiki/X11_color_names]именах цветов X11[/url].\n"
"ЕÑли вы хотите задать Ð·Ð½Ð°Ñ‡ÐµÐ½Ð¸Ñ Ð² диапазоне от 0 до 255, вам Ñледует "
-"иÑпользовать [метод @GDScript.Color8].\n"
+"иÑпользовать [method @GDScript.Color8].\n"
"[b]Примечание:[/b] Ð’ булевом контекÑте значение Color будет равно "
"[code]false[/code], еÑли оно равно [code]Color(0, 0, 0, 0, 1)[/code] "
"(непрозрачный черный). Ð’ противном Ñлучае значение Color вÑегда будет равно "
@@ -17703,24 +17735,24 @@ msgid ""
msgstr ""
"Виртуальный метод, который должен быть реализован пользователем. ИÑпользуйте "
"Ñтот метод Ð´Ð»Ñ Ð¾Ð±Ñ€Ð°Ð±Ð¾Ñ‚ÐºÐ¸ и приема входных данных на Ñлементах "
-"пользовательÑкого интерфейÑа. См. [метод accept_event].\n"
+"пользовательÑкого интерфейÑа. См. [method accept_event].\n"
"Пример: щелчок по Ñлементу управлениÑ.\n"
"[codeblock].\n"
"func _gui_input(event):\n"
-" if event is InputEventMouseButton:\n"
-" if event.button_index == BUTTON_LEFT and event.pressed:\n"
-" print(\"Ðа Ð¼ÐµÐ½Ñ Ð½Ð°Ð¶Ð°Ð»Ð¸ D:\")\n"
+"\tif event is InputEventMouseButton:\n"
+"\t\tif event.button_index == BUTTON_LEFT and event.pressed:\n"
+"\t\t\tprint(\"Ðа Ð¼ÐµÐ½Ñ Ð½Ð°Ð¶Ð°Ð»Ð¸ D:\")\n"
"[/codeblock].\n"
"Событие не Ñработает, еÑли:\n"
-"* щелчок вне Ñлемента ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (Ñм. [метод has_point]);\n"
+"* щелчок вне Ñлемента ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ (Ñм. [method has_point]);\n"
"* у Ñлемента ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ [member mouse_filter] уÑтановлено значение [constant "
"MOUSE_FILTER_IGNORE];\n"
"* Ñлемент ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð·Ð°Ð³Ð¾Ñ€Ð¾Ð¶ÐµÐ½ другим [Control] Ñверху, у которого [member "
"mouse_filter] не уÑтановлен на [constant MOUSE_FILTER_IGNORE];\n"
"* родитель Ñлемента ÑƒÐ¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð¸Ñ Ð¸Ð¼ÐµÐµÑ‚ [member mouse_filter], уÑтановленный на "
"[constant MOUSE_FILTER_STOP] или принÑл Ñобытие;\n"
-"* Ñобытие проиÑходит вне прÑмоугольника родителÑ, и у Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½ [член "
-"rect_clip_content] или [метод _clips_input].\n"
+"* Ñобытие проиÑходит вне прÑмоугольника родителÑ, и у Ñ€Ð¾Ð´Ð¸Ñ‚ÐµÐ»Ñ Ð²ÐºÐ»ÑŽÑ‡ÐµÐ½ "
+"[member rect_clip_content] или [method _clips_input].\n"
"[b]Примечание:[/b] Положение ÑÐ¾Ð±Ñ‹Ñ‚Ð¸Ñ Ð¾Ñ‚Ð½Ð¾Ñительно начала Ñлемента управлениÑ."
#: doc/classes/Control.xml
@@ -17852,7 +17884,7 @@ msgstr ""
"получении Ñлементов темы Ð´Ð»Ñ Ñлемента управлениÑ.\n"
"[b]Примечание:[/b] Переопределение можно удалить, приÑвоив ему значение "
"[code]null[/code]. Это поведение уÑтарело и будет удалено в верÑии 4.0, "
-"иÑпользуйте [метод remove_stylebox_override] вмеÑто Ñтого.\n"
+"иÑпользуйте [method remove_stylebox_override] вмеÑто Ñтого.\n"
"См. также [метод get_stylebox].\n"
"[b]Пример Ð¸Ð·Ð¼ÐµÐ½ÐµÐ½Ð¸Ñ ÑвойÑтва в StyleBox путем его дублированиÑ:[/b]\n"
"[codeblock]\n"
@@ -17867,7 +17899,7 @@ msgstr ""
"$MyButton.add_stylebox_override(\"normal\", new_stylebox_normal)\n"
"# Удалите переопределение Ñтилей.\n"
"$MyButton.add_stylebox_override(\"normal\", null)\n"
-"[/codeblock]."
+"[/codeblock]"
#: doc/classes/Control.xml
msgid ""
@@ -18583,7 +18615,7 @@ msgstr ""
"необходимое Ð´Ð»Ñ Ð¿Ð¾ÑÐ²Ð»ÐµÐ½Ð¸Ñ Ð²Ñплывающей подÑказки Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ опции [code]gui/"
"timers/tooltip_delay_sec[/code] в ÐаÑтройках проекта.\n"
"Ð’ÑÐ¿Ð»Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ð¿Ð¾Ð´Ñказка будет иÑпользовать либо реализацию по умолчанию, либо "
-"пользовательÑкую, которую вы можете Ñоздать, переопределив [метод "
+"пользовательÑкую, которую вы можете Ñоздать, переопределив [method "
"_make_custom_tooltip]. Ð’ÑÐ¿Ð»Ñ‹Ð²Ð°ÑŽÑ‰Ð°Ñ Ð¿Ð¾Ð´Ñказка по умолчанию включает "
"[PopupPanel] и [Label], ÑвойÑтва темы которых можно наÑтроить Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ "
"методов [Theme] Ñ [code]\"TooltipPanel\"[/code] и [code]\"TooltipLabel\"[/"
@@ -23673,17 +23705,17 @@ msgstr ""
"ÑоÑтоÑние можно было воÑÑтановить при возврате на вкладку). Эти данные "
"автоматичеÑки ÑохранÑÑŽÑ‚ÑÑ Ð´Ð»Ñ ÐºÐ°Ð¶Ð´Ð¾Ð¹ Ñцены в файле [code]editstate[/code] в "
"папке метаданных редактора. ЕÑли вы хотите Ñохранить глобальные (незавиÑимые "
-"от Ñцены) данные редактора Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ плагина, вы можете иÑпользовать [метод "
-"get_window_layout] вмеÑто Ñтого.\n"
+"от Ñцены) данные редактора Ð´Ð»Ñ Ð²Ð°ÑˆÐµÐ³Ð¾ плагина, вы можете иÑпользовать "
+"[method get_window_layout] вмеÑто Ñтого.\n"
"ИÑпользуйте [method set_state] Ð´Ð»Ñ Ð²Ð¾ÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ Ñохраненного ÑоÑтоÑниÑ.\n"
"[b]Примечание:[/b] Этот метод не Ñледует иÑпользовать Ð´Ð»Ñ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð²Ð°Ð¶Ð½Ñ‹Ñ… "
"наÑтроек, которые должны ÑохранÑÑ‚ÑŒÑÑ Ð² проекте.\n"
"[b]Примечание:[/b] Ð”Ð»Ñ ÐºÐ¾Ñ€Ñ€ÐµÐºÑ‚Ð½Ð¾Ð³Ð¾ ÑÐ¾Ñ…Ñ€Ð°Ð½ÐµÐ½Ð¸Ñ Ð¸ воÑÑÑ‚Ð°Ð½Ð¾Ð²Ð»ÐµÐ½Ð¸Ñ ÑоÑтоÑÐ½Ð¸Ñ "
-"необходимо реализовать [метод get_plugin_name].\n"
+"необходимо реализовать [method get_plugin_name].\n"
"[codeblock].\n"
"func get_state():\n"
-" var state = {\"zoom\": zoom, \"preferred_color\": my_color}\n"
-" return state\n"
+"\tvar state = {\"zoom\": zoom, \"preferred_color\": my_color}\n"
+"\treturn state\n"
"[/codeblock]"
#: doc/classes/EditorPlugin.xml
@@ -27854,7 +27886,7 @@ msgstr ""
"Вершины каждого многоугольника будут округлены в ÑоответÑтвии Ñ Ñ‚Ð¸Ð¿Ð¾Ð¼ "
"[code]join_type[/code], Ñм. [enum PolyJoinType].\n"
"В результате операции может быть получен внешний многоугольник (граница) и "
-"внутренний многоугольник (отверÑтие), которые можно отличить, вызвав [метод "
+"внутренний многоугольник (отверÑтие), которые можно отличить, вызвав [method "
"is_polygon_clockwise].\n"
"[b]Примечание:[/b] Ð”Ð»Ñ Ñпециального перевода вершин многоугольника "
"иÑпользуйте метод [method Transform2D.xform]:\n"
@@ -28261,9 +28293,9 @@ msgstr ""
"занимает от 5 до 20 Ñекунд в большинÑтве Ñцен. Уменьшение [member subdiv] "
"может уÑкорить запекание.\n"
"[b]Примечание:[/b] [GeometryInstance]Ñ‹ и [Light]Ñ‹ должны быть полноÑтью "
-"готовы до вызова [метода bake]. ЕÑли вы Ñоздаете их процедурно и некоторые "
+"готовы до вызова [method bake]. ЕÑли вы Ñоздаете их процедурно и некоторые "
"Ñетки или оÑвещение отÑутÑтвуют в вашем запекаемом [GIProbe], иÑпользуйте "
-"[code]call_deferred(\"bake\")[/code] вмеÑто прÑмого вызова [метода bake]."
+"[code]call_deferred(\"bake\")[/code] вмеÑто прÑмого вызова [method bake]."
#: doc/classes/GIProbe.xml
msgid "Calls [method bake] with [code]create_visual_debug[/code] enabled."
@@ -30899,14 +30931,14 @@ msgid ""
"in the URL. See [method String.http_escape] for an example."
msgstr ""
"Создает Ð·Ð°Ð¿Ñ€Ð¾Ñ Ð½Ð° базовом [HTTPClient]. ЕÑли нет ошибок конфигурации, "
-"пытаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ [метод HTTPClient.connect_to_host] и "
-"передает параметры в [метод HTTPClient.request].\n"
+"пытаетÑÑ Ð¿Ð¾Ð´ÐºÐ»ÑŽÑ‡Ð¸Ñ‚ÑŒÑÑ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ [method HTTPClient.connect_to_host] и "
+"передает параметры в [method HTTPClient.request].\n"
"Возвращает [constant OK], еÑли Ð·Ð°Ð¿Ñ€Ð¾Ñ ÑƒÑпешно Ñоздан. (Это не означает, что "
-"Ñервер ответил), [конÑтанта ERR_UNCONFIGURED], еÑли не находитÑÑ Ð² дереве, "
-"[конÑтанта ERR_BUSY], еÑли вÑе еще обрабатывает предыдущий запроÑ, "
-"[конÑтанта ERR_INVALID_PARAMETER], еÑли Ð·Ð°Ð´Ð°Ð½Ð½Ð°Ñ Ñтрока не ÑвлÑетÑÑ "
-"правильным форматом URL, или [конÑтанта ERR_CANT_CONNECT], еÑли не "
-"иÑпользуетÑÑ Ð¿Ð¾Ñ‚Ð¾Ðº и [HTTPClient] не может ÑоединитьÑÑ Ñ Ñ…Ð¾Ñтом.\n"
+"Ñервер ответил), [constant ERR_UNCONFIGURED], еÑли не находитÑÑ Ð² дереве, "
+"[constant ERR_BUSY], еÑли вÑе еще обрабатывает предыдущий запроÑ, [constant "
+"ERR_INVALID_PARAMETER], еÑли Ð·Ð°Ð´Ð°Ð½Ð½Ð°Ñ Ñтрока не ÑвлÑетÑÑ Ð¿Ñ€Ð°Ð²Ð¸Ð»ÑŒÐ½Ñ‹Ð¼ форматом "
+"URL, или [constant ERR_CANT_CONNECT], еÑли не иÑпользуетÑÑ Ð¿Ð¾Ñ‚Ð¾Ðº и "
+"[HTTPClient] не может ÑоединитьÑÑ Ñ Ñ…Ð¾Ñтом.\n"
"[b]Примечание:[/b] ЕÑли [code]метод[/code] ÑвлÑетÑÑ [constant HTTPClient."
"METHOD_GET], Ð¿Ð¾Ð»ÐµÐ·Ð½Ð°Ñ Ð½Ð°Ð³Ñ€ÑƒÐ·ÐºÐ°, Ð¾Ñ‚Ð¿Ñ€Ð°Ð²Ð»ÐµÐ½Ð½Ð°Ñ Ñ‡ÐµÑ€ÐµÐ· [code]request_data[/"
"code], может быть проигнорирована Ñервером или даже привеÑти к отклонению "
@@ -32299,7 +32331,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
@@ -34067,38 +34103,38 @@ msgid ""
"[b]Note:[/b] Only available in the HTML5 platform."
msgstr ""
"JavaScriptObject иÑпользуетÑÑ Ð´Ð»Ñ Ð²Ð·Ð°Ð¸Ð¼Ð¾Ð´ÐµÐ¹ÑÑ‚Ð²Ð¸Ñ Ñ Ð¾Ð±ÑŠÐµÐºÑ‚Ð°Ð¼Ð¸ JavaScript, "
-"полученными или Ñозданными Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [метода JavaScript.get_interface], "
-"[метода JavaScript.create_object] или [метода JavaScript.create_callback].\n"
+"полученными или Ñозданными Ñ Ð¿Ð¾Ð¼Ð¾Ñ‰ÑŒÑŽ [method JavaScript.get_interface], "
+"[method JavaScript.create_object] или [method JavaScript.create_callback].\n"
"Пример:\n"
"[codeblock]\n"
-"раÑширÑет Node\n"
+"extends Node\n"
"\n"
"var _my_js_callback = JavaScript.create_callback(self, \"myCallback\") # Эта "
"ÑÑылка должна быть Ñохранена\n"
"var console = JavaScript.get_interface(\"console\")\n"
"\n"
"func _init():\n"
-" var buf = JavaScript.create_object(\"ArrayBuffer\", 10) # новый "
+"\tvar buf = JavaScript.create_object(\"ArrayBuffer\", 10) # новый "
"ArrayBuffer(10)\n"
-" print(buf) # печатает [JavaScriptObject:OBJECT_ID]\n"
-" var uint8arr = JavaScript.create_object(\"Uint8Array\", buf) # новый "
+"\tprint(buf) # печатает [JavaScriptObject:OBJECT_ID]\n"
+"\tvar uint8arr = JavaScript.create_object(\"Uint8Array\", buf) # новый "
"Uint8Array(buf)\n"
-" uint8arr[1] = 255\n"
-" prints(uint8arr[1], uint8arr.byteLength) # печатает 255 10\n"
-" console.log(uint8arr) # печатает в конÑоли браузера \"Uint8Array(10) "
-"[ 0, 255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\"\n"
+"\tuint8arr[1] = 255\n"
+"\tprints(uint8arr[1], uint8arr.byteLength) # печатает 255 10\n"
+"\tconsole.log(uint8arr) # печатает в конÑоли браузера \"Uint8Array(10) [ 0, "
+"255, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]\"\n"
"\n"
-" # Эквивалент JavaScript: Array.from(uint8arr).forEach(myCallback)\n"
-" JavaScript.get_interface(\"Array\").from(uint8arr)."
+"\t# Эквивалент JavaScript: Array.from(uint8arr).forEach(myCallback)\n"
+"\tJavaScript.get_interface(\"Array\").from(uint8arr)."
"forEach(_my_js_callback)\n"
"\n"
"func myCallback(args):\n"
-" # Будет вызван Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°Ð¼Ð¸, переданными в обратный вызов \"forEach\".\n"
-" # [0, 0, [JavaScriptObject:1173]]\n"
-" # [255, 1, [JavaScriptObject:1173]]\n"
-" # ...\n"
-" # [0, 9, [JavaScriptObject:1180]]\n"
-" print(args)\n"
+"\t# Будет вызван Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ð°Ð¼Ð¸, переданными в обратный вызов \"forEach\".\n"
+"\t# [0, 0, [JavaScriptObject:1173]]\n"
+"\t# [255, 1, [JavaScriptObject:1173]]\n"
+"\t# ...\n"
+"\t# [0, 9, [JavaScriptObject:1180]]\n"
+"\tprint(args)\n"
"[/codeblock].\n"
"[b]Примечание:[/b] ДоÑтупно только в платформе HTML5."
@@ -39775,7 +39811,7 @@ msgstr "Возвращает значение задержки данного к
msgid ""
"Returns the normal for the point returned by [method map_get_closest_point]."
msgstr ""
-"Возвращает нормаль Ð´Ð»Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸, возвращенной [методом map_get_closest_point]."
+"Возвращает нормаль Ð´Ð»Ñ Ñ‚Ð¾Ñ‡ÐºÐ¸, возвращенной [method map_get_closest_point]."
#: doc/classes/NavigationServer.xml
msgid ""
@@ -39976,10 +40012,10 @@ msgstr ""
"пирами, чтобы гарантировать, что пропуÑÐºÐ½Ð°Ñ ÑпоÑобноÑÑ‚ÑŒ пиров не будет "
"превышена. Параметры пропуÑкной ÑпоÑобноÑти также определÑÑŽÑ‚ размер окна "
"ÑоединениÑ, которое ограничивает количеÑтво надежных пакетов, которые могут "
-"находитьÑÑ Ð² пути в любой момент времени. Возвращает [конÑтанту OK], еÑли "
-"клиент был Ñоздан, [конÑтанту ERR_ALREADY_IN_USE], еÑли данный ÑкземплÑÑ€ "
+"находитьÑÑ Ð² пути в любой момент времени. Возвращает [constant OK], еÑли "
+"клиент был Ñоздан, [constant ERR_ALREADY_IN_USE], еÑли данный ÑкземплÑÑ€ "
"NetworkedMultiplayerENet уже имеет открытое Ñоединение (в Ñтом Ñлучае "
-"необходимо Ñначала вызвать [метод close_connection]) или [конÑтанту "
+"необходимо Ñначала вызвать [method close_connection]) или [constant "
"ERR_CANT_CREATE], еÑли клиент не может быть Ñоздан. ЕÑли указано "
"[code]client_port[/code], клиент также будет Ñлушать указанный порт; Ñто "
"полезно Ð´Ð»Ñ Ð½ÐµÐºÐ¾Ñ‚Ð¾Ñ€Ñ‹Ñ… методов обхода NAT."
@@ -75012,23 +75048,24 @@ msgid ""
"viewport_set_render_direct_to_screen]."
msgstr ""
"Копирует видовой Ñкран в облаÑÑ‚ÑŒ Ñкрана, указанную [code]rect[/code]. ЕÑли "
-"[член Viewport.render_direct_to_screen] равен [code]true[/code], то вьюпорт "
-"не иÑпользует фреймбуфер и Ñодержимое вьюпорта выводитÑÑ Ð½ÐµÐ¿Ð¾ÑредÑтвенно на "
-"Ñкран. Однако обратите внимание, что корневой видовой Ñкран риÑуетÑÑ "
-"поÑледним, поÑтому он будет риÑоватьÑÑ Ð¿Ð¾Ð²ÐµÑ€Ñ… Ñкрана. СоответÑтвенно, вы "
-"должны уÑтановить корневой видовой Ñкран на облаÑÑ‚ÑŒ, ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð½Ðµ покрывает "
-"облаÑÑ‚ÑŒ, к которой вы прикрепили Ñтот видовой Ñкран.\n"
+"[member Viewport.render_direct_to_screen] равен [code]true[/code], то "
+"вьюпорт не иÑпользует фреймбуфер и Ñодержимое вьюпорта выводитÑÑ "
+"непоÑредÑтвенно на Ñкран. Однако обратите внимание, что корневой видовой "
+"Ñкран риÑуетÑÑ Ð¿Ð¾Ñледним, поÑтому он будет риÑоватьÑÑ Ð¿Ð¾Ð²ÐµÑ€Ñ… Ñкрана. "
+"СоответÑтвенно, вы должны уÑтановить корневой видовой Ñкран на облаÑÑ‚ÑŒ, "
+"ÐºÐ¾Ñ‚Ð¾Ñ€Ð°Ñ Ð½Ðµ покрывает облаÑÑ‚ÑŒ, к которой вы прикрепили Ñтот видовой Ñкран.\n"
"Ðапример, вы можете уÑтановить корневой видовой Ñкран так, чтобы он вообще "
"не отриÑовывалÑÑ, иÑÐ¿Ð¾Ð»ÑŒÐ·ÑƒÑ Ñледующий код:\n"
"[codeblock].\n"
"func _ready():\n"
-" get_viewport().set_attach_to_screen_rect(Rect2())\n"
-" $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n"
+"\tget_viewport().set_attach_to_screen_rect(Rect2())\n"
+"\t$Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n"
"[/codeblock].\n"
"ИÑпользование Ñтого метода может привеÑти к значительной оптимизации, "
"оÑобенно на уÑтройÑтвах низкого клаÑÑа. Однако за Ñто приходитÑÑ "
"раÑплачиватьÑÑ Ð½ÐµÐ¾Ð±Ñ…Ð¾Ð´Ð¸Ð¼Ð¾Ñтью управлÑÑ‚ÑŒ видовыми Ñкранами вручную. Ð”Ð»Ñ "
-"дальнейшей оптимизации Ñмотрите [метод viewport_set_render_direct_to_screen]."
+"дальнейшей оптимизации Ñмотрите [method "
+"viewport_set_render_direct_to_screen]."
#: doc/classes/VisualServer.xml
msgid ""
diff --git a/doc/translations/sk.po b/doc/translations/sk.po
index 3a58e3f2a9..d82d0b12ee 100644
--- a/doc/translations/sk.po
+++ b/doc/translations/sk.po
@@ -29911,7 +29911,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/sr_Cyrl.po b/doc/translations/sr_Cyrl.po
index 2846de07bb..2fccf2bef4 100644
--- a/doc/translations/sr_Cyrl.po
+++ b/doc/translations/sr_Cyrl.po
@@ -29922,7 +29922,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/sv.po b/doc/translations/sv.po
index 65cad9bf8a..b4ec51f179 100644
--- a/doc/translations/sv.po
+++ b/doc/translations/sv.po
@@ -29909,7 +29909,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/th.po b/doc/translations/th.po
index 54fbdbfe27..0ca308df1c 100644
--- a/doc/translations/th.po
+++ b/doc/translations/th.po
@@ -30049,7 +30049,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/tl.po b/doc/translations/tl.po
index a9b6a9e2a9..a3d46e6b1d 100644
--- a/doc/translations/tl.po
+++ b/doc/translations/tl.po
@@ -29997,7 +29997,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/tr.po b/doc/translations/tr.po
index 5d8f2afe29..a41bb69483 100644
--- a/doc/translations/tr.po
+++ b/doc/translations/tr.po
@@ -30744,7 +30744,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/uk.po b/doc/translations/uk.po
index 3714c11d88..6c071cee85 100644
--- a/doc/translations/uk.po
+++ b/doc/translations/uk.po
@@ -20,8 +20,8 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-11-25 12:13+0000\n"
-"Last-Translator: Лев ДворÑкий <ne3r0n@gmail.com>\n"
+"PO-Revision-Date: 2022-12-28 14:08+0000\n"
+"Last-Translator: KazanskiyMaks <kazanskiy.maks@gmail.com>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot-class-reference/uk/>\n"
"Language: uk\n"
@@ -30,7 +30,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -106,13 +106,11 @@ msgid "Getter"
msgstr "Отримувач"
#: doc/tools/make_rst.py
-#, fuzzy
msgid ""
"This method should typically be overridden by the user to have any effect."
msgstr "Зазвичай, цей метод перевизначаєтьÑÑ ÐºÐ¾Ñ€Ð¸Ñтувачем, щоб він мав вплив."
#: doc/tools/make_rst.py
-#, fuzzy
msgid ""
"This method has no side effects. It doesn't modify any of the instance's "
"member variables."
@@ -120,13 +118,11 @@ msgstr ""
"Цей метод не має побічних ефектів. Ðе змінює ніÑку змінну екземплÑра об'єкта."
#: doc/tools/make_rst.py
-#, fuzzy
msgid ""
"This method accepts any number of arguments after the ones described here."
msgstr "Цей метод приймає будь-Ñке чиÑло аргументів піÑÐ»Ñ Ð¾Ð¿Ð¸Ñаних тут."
#: doc/tools/make_rst.py
-#, fuzzy
msgid "This method is used to construct a type."
msgstr "Цей метод викориÑтовуєтьÑÑ Ð´Ð»Ñ Ð¿Ð¾Ð±ÑƒÐ´Ð¾Ð²Ð¸ типів."
@@ -136,8 +132,8 @@ msgid ""
"This method doesn't need an instance to be called, so it can be called "
"directly using the class name."
msgstr ""
-"Ð”Ð»Ñ Ð²Ð¸ÐºÐ¾Ñ€Ð¸ÑтаннÑ, цей метод не потребує ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¾Ð±'єкта, тому він може "
-"бути викликаним напрÑму вказавши назву клаÑу."
+"Ð”Ð»Ñ Ð²Ð¸ÐºÐ»Ð¸ÐºÑƒ, метод не потребує ÑÑ‚Ð²Ð¾Ñ€ÐµÐ½Ð½Ñ Ð¾Ð±'єкта, тому він може бути "
+"викориÑтаним проÑто вказавши назву клаÑу."
#: doc/tools/make_rst.py
msgid ""
@@ -285,22 +281,22 @@ msgid ""
"[/codeblock]"
msgstr ""
"ПеревірÑÑ”, чи [code]condition[/code] дорівнює [code]true[/code]. Якщо "
-"[code]condition[/code] дорівнює [code]false[/code], буде згенеровано "
-"помилку. Якщо виконуєтьÑÑ Ñƒ редакторі, проєкт буде також призупинено, поки "
-"ви не продовжите його. Може бути викориÑтано, Ñк більш дієва форма [method "
-"push_error] Ð´Ð»Ñ Ð·Ð²Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº розробникам проєкту, або допоміжним "
-"кориÑтувачам.\n"
+"[code]condition[/code] дорівнює [code]false[/code], буде Ñтворено помилку. "
+"Якщо виконуєтьÑÑ Ð² редакторі, проєкт також буде призупинено, поки ви не "
+"відновите його роботу. Можна викориÑтати, Ñк більш дієву форму [method "
+"push_error] Ð´Ð»Ñ Ð·Ð²Ñ–Ñ‚ÑƒÐ²Ð°Ð½Ð½Ñ Ð¿Ð¾Ð¼Ð¸Ð»Ð¾Ðº розробникам проєкту, або кориÑтувачам "
+"Ð´Ð¾Ð¿Ð¾Ð²Ð½ÐµÐ½Ð½Ñ (add-on).\n"
"[b]Ðотатка:[/b] З міркувань продуктивноÑÑ‚Ñ–, код вÑередині [method assert] "
-"виконуєтьÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ у діагноÑтичних збірках, або коли проєкт виконуєтьÑÑ Ñƒ "
-"редакторі. Ðе викориÑтовуйте код, Ñкий негативно впливає на Ð²Ð¸ÐºÐ¾Ð½Ð°Ð½Ð½Ñ "
-"[method assert]. Інакше, проєкт буде поводити Ñебе інакше, Ñкщо він буде "
-"екÑпортованим у режимі публікації.\n"
+"виконуєтьÑÑ Ñ‚Ñ–Ð»ÑŒÐºÐ¸ у діагноÑтичних збірках, або коли проєкт виконуєтьÑÑ Ð² "
+"редакторі. Ðе включайте в код, де викориÑÑ‚Ð°Ð½Ð½Ñ [method assert] призведе до "
+"побічних ефектів. У противному разі, проєкт буде поводити Ñебе інакше, Ñкщо "
+"він буде екÑпортованим у режимі публікації.\n"
"Якщо задано необов'Ñзковий аргумент [code]message[/code], то він буде "
"показаний у додаток до Ð¿Ð¾Ð²Ñ–Ð´Ð¾Ð¼Ð»ÐµÐ½Ð½Ñ \"Assertion failed\". Ви можете "
-"ÑкориÑтатиÑÑ Ñ†Ð¸Ð¼ Ð´Ð»Ñ Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¸Ñ… відомоÑтей щодо того, чому перевірку "
-"не було пройдено.\n"
+"ÑкориÑтатиÑÑ Ñ†Ð¸Ð¼ Ð´Ð»Ñ Ð½Ð°Ð´Ð°Ð½Ð½Ñ Ð´Ð¾Ð´Ð°Ñ‚ÐºÐ¾Ð²Ð¸Ñ… відомоÑтей щодо причини провалу "
+"перевірки.\n"
"[codeblock]\n"
-"# ПрипуÑтимо, що ви хочете, щоб швидкіÑÑ‚ÑŒ (speed) була у межах від 0 до 20.\n"
+"# ПрипуÑтимо, ви хочете, щоб швидкіÑÑ‚ÑŒ (speed) була у межах від 0 до 20.\n"
"var speed = -10\n"
"assert(speed < 20) # ІÑтина, програма продовжить виконаннÑ\n"
"assert(speed >= 0) # Хиба, програму буде зупинено\n"
@@ -375,6 +371,7 @@ msgstr ""
"полÑрну ÑиÑтему (відÑтань до початку координат та кут)."
#: modules/gdscript/doc_classes/@GDScript.xml
+#, fuzzy
msgid ""
"Rounds [code]s[/code] upward (towards positive infinity), returning the "
"smallest whole number that is not less than [code]s[/code].\n"
@@ -384,6 +381,13 @@ msgid ""
"[/codeblock]\n"
"See also [method floor], [method round], [method stepify], and [int]."
msgstr ""
+"Заокруглює [code]s[/code] вгору (до додатної неÑкінченноÑÑ‚Ñ–), повертаючи "
+"найменше чиÑло, ще не менше за [code]s[/code].\n"
+"[codeblock]\n"
+"a = ceil(1.45) # a дорівнює 2.0\n"
+"a = ceil(1.001) # a дорівнює 2.0\n"
+"[/codeblock]\n"
+"Також переглÑньте [method floor], [method round], [method stepify] та [int]."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -396,6 +400,13 @@ msgid ""
"[/codeblock]\n"
"This is the inverse of [method ord]."
msgstr ""
+"Повертає Ñимвол, Ñк РÑдок з даного Юнікод коду(що ÑуміÑний з ASCII кодом).\n"
+"[codeblock]\n"
+"a = char(65) # a дорівнює \"A\"\n"
+"a = char(65 + 32) # a дорівнює \"a\"\n"
+"a = char(8364) # a дорівнює \"€\"\n"
+"[/codeblock]\n"
+"Це протилежніÑÑ‚ÑŒ до [method ord]."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -407,6 +418,13 @@ msgid ""
"a = clamp(15, 1, 20) # a is 15\n"
"[/codeblock]"
msgstr ""
+"ЗатиÑкує [code]value[/code] та повертає значеннÑ, що не менше за [code]min[/"
+"code] і не більше за [code]max[/code].\n"
+"[codeblock]\n"
+"a = clamp(1000, 1, 20) # a дорівнює 20\n"
+"a = clamp(-10, 1, 20) # a дорівнює 1\n"
+"a = clamp(15, 1, 20) # a дорівнює 15\n"
+"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -421,6 +439,16 @@ msgid ""
"print(a.length())\n"
"[/codeblock]"
msgstr ""
+"Конвертує один тип в інший у найкращий ÑпоÑіб. Параметр [code]type[/code] "
+"викориÑтовує Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð· [enum Variant.Type].\n"
+"[codeblock]\n"
+"a = Vector2(1, 0)\n"
+"# Виводить 1\n"
+"print(a.length())\n"
+"a = convert(a, TYPE_STRING)\n"
+"# Виводить 6, бо Ñ€Ñдок \"(1, 0)\" ÑкладаєтьÑÑ Ð· 6 Ñимволів\n"
+"print(a.length())\n"
+"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
#, fuzzy
@@ -431,11 +459,10 @@ msgid ""
"a = cos(PI) # a is -1.0\n"
"[/codeblock]"
msgstr ""
-"Повертає абÑолютне Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð¿Ð°Ñ€Ð°Ð¼ÐµÑ‚Ñ€Ñƒ [code]s[/code] (тобто Ð·Ð½Ð°Ñ‡ÐµÐ½Ð½Ñ Ð±ÐµÐ· "
-"знака, працює Ð´Ð»Ñ Ñ†Ñ–Ð»Ð¸Ñ… чиÑел Ñ– чиÑел із рухомою крапкою).\n"
+"Повертає коÑÐ¸Ð½ÑƒÑ ÐºÑƒÑ‚Ð° [code]s[/code] в радіанах.\n"
"[codeblock]\n"
-"# a дорівнює 1\n"
-"a = abs(-1)\n"
+"a = cos(TAU) # a дорівнює 1.0\n"
+"a = cos(PI) # a дорівнює -1.0\n"
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
@@ -452,11 +479,11 @@ msgstr ""
#: modules/gdscript/doc_classes/@GDScript.xml
msgid "Converts from decibels to linear energy (audio)."
-msgstr ""
+msgstr "Перетворює з децибел в лінійну енергію (аудіо)."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid "Deprecated alias for [method step_decimals]."
-msgstr ""
+msgstr "ЗаÑтарілий пÑевдонім Ð´Ð»Ñ [method step_decimals]."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -468,6 +495,13 @@ msgid ""
"a = dectime(60, 10, 0.1)) # a is 59.0\n"
"[/codeblock]"
msgstr ""
+"[b]Ðотатка:[/b] [code]dectime[/code] заÑтарілий Ñ– буде вилучений в Godot "
+"4.0, натоміÑÑ‚ÑŒ краще викориÑтовуйте [method move_toward].\n"
+"Повертає результат [code]value[/code] зменшений на [code]step[/code] * "
+"[code]amount[/code].\n"
+"[codeblock]\n"
+"a = dectime(60, 10, 0.1)) # a дорівнює 59.0\n"
+"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -489,6 +523,23 @@ msgid ""
"want a true content-aware comparison, you have to use [code]deep_equal[/"
"code]."
msgstr ""
+"Порівнює два значеннÑ, шлÑхом порівнÑÐ½Ð½Ñ Ñ—Ñ… реального вміÑту, рекурÑивно Ð´Ð»Ñ "
+"будь-Ñкого [Array] чи [Dictionary] аж до найглибшого рівнÑ.\n"
+"Порівнюючи з [code]==[/code], відмітимо:\n"
+"- Ð”Ð»Ñ [code]null[/code], [code]int[/code], [code]float[/code], [code]String[/"
+"code], [code]Object[/code] та [code]RID[/code] що [code]deep_equal[/code], "
+"що [code]==[/code] працюють однаково.\n"
+"- Ð”Ð»Ñ [code]Dictionary[/code], [code]==[/code] виÑвлÑÑ” рівніÑÑ‚ÑŒ тоді й "
+"тільки тоді, коли йде порівнÑÐ½Ð½Ñ Ð· цим Ñамим [code]Dictionary[/code], без "
+"рекурÑÑ–Ñ— чи будь-Ñкого Ð²Ñ€Ð°Ñ…ÑƒÐ²Ð°Ð½Ð½Ñ Ð²Ð¼Ñ–Ñту.\n"
+"- Ð”Ð»Ñ [code]Array[/code], [code]==[/code] виÑвлÑÑ” рівніÑÑ‚ÑŒ тоді й тільки "
+"тоді, коли кожний елемент у першому [code]Array[/code] дорівнює відповідному "
+"елементу в другому [code]Array[/code], де порівнÑÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ…Ð¾Ð´Ð¸Ñ‚ÑŒ через "
+"[code]==[/code]. Це означає, що [code]==[/code] рекурÑивно порівнює "
+"[code]Array[/code], але не [code]Dictionary[/code].\n"
+"Загалом, Ñкщо у Ð²Ð°Ñ Ð¿Ð¾Ñ‚ÐµÐ½Ñ†Ñ–Ð¹Ð½Ð¾ викориÑтовуєтьÑÑ [code]Dictionary[/code], Ñ– "
+"вам потрібно порівнÑÐ½Ð½Ñ Ð· урахуваннÑм вміÑту, викориÑтовуйте "
+"[code]deep_equal[/code]."
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -30098,7 +30149,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/vi.po b/doc/translations/vi.po
index 962440bfab..36ef54b096 100644
--- a/doc/translations/vi.po
+++ b/doc/translations/vi.po
@@ -30410,7 +30410,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
diff --git a/doc/translations/zh_CN.po b/doc/translations/zh_CN.po
index 966ec9b0f9..773dda130e 100644
--- a/doc/translations/zh_CN.po
+++ b/doc/translations/zh_CN.po
@@ -3,7 +3,7 @@
# Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).
# This file is distributed under the same license as the Godot source code.
#
-# Haoyu Qiu <timothyqiu32@gmail.com>, 2020, 2021, 2022.
+# Haoyu Qiu <timothyqiu32@gmail.com>, 2020, 2021, 2022, 2023.
# fangxvan <2661712415@qq.com>, 2020.
# yzt <834950797@qq.com>, 2020.
# 懵逼Kitty <m1330586660@163.com>, 2020, 2021.
@@ -37,7 +37,7 @@
# Juer Genie Whang <2695996944@qq.com>, 2021.
# SimonChang <simon_chang@foxmail.com>, 2021.
# zeng haochen <m18621006730@163.com>, 2021.
-# suplife <2634557184@qq.com>, 2021.
+# suplife <2634557184@qq.com>, 2021, 2023.
# Magian <magian1127@gmail.com>, 2021, 2022.
# ji233 <27987772@qq.com>, 2021.
# 沈士超 <shenshichao920@hotmail.com>, 2021.
@@ -64,7 +64,7 @@ msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-12-12 06:48+0000\n"
+"PO-Revision-Date: 2023-01-09 20:42+0000\n"
"Last-Translator: Haoyu Qiu <timothyqiu32@gmail.com>\n"
"Language-Team: Chinese (Simplified) <https://hosted.weblate.org/projects/"
"godot-engine/godot-class-reference/zh_Hans/>\n"
@@ -73,7 +73,7 @@ msgstr ""
"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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -730,7 +730,6 @@ msgstr ""
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns an array of dictionaries representing the current call stack. See "
"also [method print_stack].\n"
@@ -754,7 +753,7 @@ msgid ""
"get_stack] will not work in projects exported in release mode, or in "
"projects exported in debug mode if not connected to a debugging server."
msgstr ""
-"返回一个表示当å‰è°ƒç”¨å †æ ˆçš„字典数组。\n"
+"返回一个表示当å‰è°ƒç”¨å †æ ˆçš„字典数组。å¦è¯·å‚阅 [method print_stack]。\n"
"[codeblock]\n"
"func _ready():\n"
" foo()\n"
@@ -769,7 +768,11 @@ msgstr ""
"[codeblock]\n"
"[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, "
"source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]\n"
-"[/codeblock]"
+"[/codeblock]\n"
+"[b]注æ„:[/b]è¿è¡Œä¸­çš„实例连接到调试æœåŠ¡å™¨ï¼ˆä¾‹å¦‚编辑器实例)åŽï¼Œ[method "
+"get_stack] æ‰èƒ½æ­£å¸¸å·¥ä½œã€‚[method get_stack] 无法在使用å‘布模å¼å¯¼å‡ºçš„项目中正"
+"常工作。使用调试模å¼å¯¼å‡ºçš„项目如果没有连接到调试æœåŠ¡å™¨ï¼Œåˆ™è¯¥å‡½æ•°ä¹Ÿæ— æ³•æ­£å¸¸å·¥"
+"作。"
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -1367,6 +1370,15 @@ msgid ""
"print_stack] will not work in projects exported in release mode, or in "
"projects exported in debug mode if not connected to a debugging server."
msgstr ""
+"输出当å‰ä»£ç ä½ç½®çš„栈追踪。å¦è¯·å‚阅 [method get_stack]。\n"
+"控制å°ä¸­çš„输出是类似这样的:\n"
+"[codeblock]\n"
+"Frame 0 - res://test.gd:16 in function '_process'\n"
+"[/codeblock]\n"
+"[b]注æ„:[/b]è¿è¡Œä¸­çš„实例连接到调试æœåŠ¡å™¨ï¼ˆä¾‹å¦‚编辑器实例)åŽï¼Œ[method "
+"print_stack] æ‰èƒ½æ­£å¸¸å·¥ä½œã€‚[method print_stack] 无法在使用å‘布模å¼å¯¼å‡ºçš„项目"
+"中正常工作。使用调试模å¼å¯¼å‡ºçš„项目如果没有连接到调试æœåŠ¡å™¨ï¼Œåˆ™è¯¥å‡½æ•°ä¹Ÿæ— æ³•æ­£"
+"常工作。"
#: modules/gdscript/doc_classes/@GDScript.xml
msgid ""
@@ -4407,6 +4419,18 @@ msgid ""
"[b]Note:[/b] The final colon is required to specify for properly detecting "
"built-in types."
msgstr ""
+"æ示一个属性代表特定的类型。如果属性为 [constant TYPE_STRING],则å¯ä»¥é€šè¿‡åˆ›å»º"
+"对è¯æ¡†è®¾ç½®å…¶ç±»åž‹ã€‚如果你需è¦åˆ›å»ºä¸€ä¸ª [Array] æ¥æ”¾ç½®ç‰¹å®šç±»åž‹çš„元素,则 "
+"[code]hint_string[/code] 必须使用 [code]\":\"[/code] æ¥ç¼–ç åµŒå¥—类型,使用 "
+"[code]\"/\"[/code] æ¥æŒ‡å®š [Resource] 类型。例如:\n"
+"[codeblock]\n"
+"hint_string = \"%s:\" % [TYPE_INT] # 整数数组。\n"
+"hint_string = \"%s:%s:\" % [TYPE_ARRAY, TYPE_REAL] # 浮点数二维数组。\n"
+"hint_string = \"%s/%s:Resource\" % [TYPE_OBJECT, TYPE_OBJECT] # 资æºæ•°ç»„。\n"
+"hint_string = \"%s:%s/%s:Resource\" % [TYPE_ARRAY, TYPE_OBJECT, TYPE_OBJECT] "
+"# 资æºäºŒç»´æ•°ç»„。\n"
+"[/codeblock]\n"
+"[b]注æ„:[/b]最åŽçš„冒å·æ˜¯å¿…须的,å¦åˆ™æ— æ³•æ­£ç¡®æ£€æµ‹å†…置类型。"
#: doc/classes/@GlobalScope.xml
msgid "The property is serialized and saved in the scene file (default)."
@@ -8808,7 +8832,6 @@ msgstr ""
"较慢。这是因为所有放置在删除元素之åŽçš„元素都必须é‡æ–°ç´¢å¼•ã€‚"
#: doc/classes/Array.xml
-#, fuzzy
msgid ""
"Assigns the given value to all elements in the array. This can typically be "
"used together with [method resize] to create an array with a given size and "
@@ -8828,7 +8851,9 @@ msgstr ""
"var array = []\n"
"array.resize(10)\n"
"array.fill(0) # å°† 10 个元素都åˆå§‹åŒ–为 0。\n"
-"[/codeblock]"
+"[/codeblock]\n"
+"[b]注æ„:[/b]如果 [code]value[/code] 为引用类型(派生自 [Object]ã€[Array]ã€"
+"[Dictionary] 等),那么会用åŒä¸€ä¸ªå¯¹è±¡çš„引用填充该数组,å³ä¸ä¼šåˆ›å»ºå‰¯æœ¬ã€‚"
#: doc/classes/Array.xml doc/classes/PoolByteArray.xml
#: doc/classes/PoolColorArray.xml doc/classes/PoolIntArray.xml
@@ -9076,7 +9101,6 @@ msgstr ""
"索引之间的å˜åŒ–。"
#: doc/classes/Array.xml
-#, fuzzy
msgid ""
"Sorts the array.\n"
"[b]Note:[/b] The sorting algorithm used is not [url=https://en.wikipedia.org/"
@@ -9092,6 +9116,9 @@ msgid ""
"[/codeblock]"
msgstr ""
"对数组进行排åºã€‚\n"
+"[b]注æ„:[/b]排åºæ‰€ä½¿ç”¨çš„算法并ä¸[url=https://zh.wikipedia.org/wiki/"
+"%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95#%E7%A9%A9%E5%AE%9A%E6%80%A7]稳定[/url]。"
+"也就是说,使用 [method sort] 时相等的值之间的顺åºå¯èƒ½ä¼šæ”¹å˜ã€‚\n"
"[b]注æ„:[/b]字符串按字æ¯é¡ºåºæŽ’åºï¼ˆä¸Žè‡ªç„¶é¡ºåºç›¸å)。当对一个以数字åºåˆ—结尾的"
"字符串数组进行排åºæ—¶ï¼Œè¿™å¯èƒ½ä¼šå¯¼è‡´æ„外的行为。请看下é¢çš„例å­ã€‚\n"
"[codeblock]\n"
@@ -9101,7 +9128,6 @@ msgstr ""
"[/codeblock]"
#: doc/classes/Array.xml
-#, fuzzy
msgid ""
"Sorts the array using a custom method. The arguments are an object that "
"holds the method and the name of such method. The custom method receives two "
@@ -9135,8 +9161,11 @@ msgstr ""
"对于两个元素 [code]a[/code] 和 [code]b[/code],如果给定的方法返回 "
"[code]true[/code],数组中的元素 [code]b[/code] 将排在元素 [code]a[/code] 之"
"åŽã€‚\n"
-"[b]注æ„:[/b]ä½ ä¸èƒ½éšæœºåŒ–返回值,因为堆排åºç®—法期望一个确定的结果。而这样åšä¼š"
-"导致æ„外的行为。\n"
+"[b]注æ„:[/b]排åºæ‰€ä½¿ç”¨çš„算法并ä¸[url=https://zh.wikipedia.org/wiki/"
+"%E6%8E%92%E5%BA%8F%E7%AE%97%E6%B3%95#%E7%A9%A9%E5%AE%9A%E6%80%A7]稳定[/url]。"
+"也就是说,使用 [method sort] 时相等的值之间的顺åºå¯èƒ½ä¼šæ”¹å˜ã€‚\n"
+"[b]注æ„:[/b]ä¸èƒ½éšæœºè¿”回一个值,因为堆排åºç®—法期望确定的结果。éšæœºè¿”回一个值"
+"会导致æ„外的行为。\n"
"[codeblock]\n"
"class MyCustomSorter:\n"
" static func sort_ascending(a, b):\n"
@@ -9787,7 +9816,7 @@ msgid ""
"However, at this point in time only one interface can render to an HMD."
msgstr ""
"调用这个æ¥åˆå§‹åŒ–这个接å£ã€‚第一个被åˆå§‹åŒ–的接å£ç¡®å®šä¸ºä¸»æŽ¥å£ï¼Œç”¨äºŽæ¸²æŸ“输出。\n"
-"在åˆå§‹åŒ–了接å£ä¹‹åŽï¼Œéœ€è¦å¯ç”¨è§†çª—çš„ AR/VR 模å¼ï¼Œå°†å¼€å§‹æ¸²æŸ“。\n"
+"在åˆå§‹åŒ–了接å£ä¹‹åŽï¼Œéœ€è¦å¯ç”¨è§†å£çš„ AR/VR 模å¼ï¼Œå°†å¼€å§‹æ¸²æŸ“。\n"
"[b]注æ„:[/b]对于任何使用 Godot 主输出的设备,如移动 VR,你必须在主视å£ä¸Šå¯"
"用 AR/VR 模å¼ã€‚\n"
"如果你为一个处ç†è‡ªå·±è¾“出的平å°è¿™æ ·åšï¼ˆå¦‚ OpenVR),Godot 就会在å±å¹•ä¸Šåªæ˜¾ç¤ºä¸€"
@@ -9844,9 +9873,9 @@ msgid ""
"[method get_render_targetsize]). Using a separate viewport node frees up the "
"main viewport for other purposes."
msgstr ""
-"这个接å£è¾“出到一个外部设备。如果使用主视区,å±å¹•ä¸Šçš„输出是一个未ç»ä¿®æ”¹çš„左眼"
-"或å³çœ¼çš„缓冲区,如果没有将视窗尺寸更改为 [method get_render_targetsize] 的相"
-"åŒé•¿å®½æ¯”,则被拉伸。使用一个å•ç‹¬çš„视窗节点å¯ä»¥é‡Šæ”¾å‡ºä¸»è§†åŒºï¼Œç”¨äºŽå…¶ä»–用途。"
+"这个接å£è¾“出到一个外部设备。如果使用主视å£ï¼Œå±å¹•ä¸Šçš„输出是一个未ç»ä¿®æ”¹çš„左眼"
+"或å³çœ¼çš„缓冲区,如果没有将视å£å°ºå¯¸æ›´æ”¹ä¸º [method get_render_targetsize] 的相"
+"åŒé•¿å®½æ¯”,则被拉伸。使用一个å•ç‹¬çš„视å£èŠ‚点å¯ä»¥é‡Šæ”¾å‡ºä¸»è§†å£ï¼Œç”¨äºŽå…¶ä»–用途。"
#: doc/classes/ARVRInterface.xml
msgid ""
@@ -12402,14 +12431,13 @@ msgid "Clears the audio sample data buffer."
msgstr "清除音频样本数æ®ç¼“冲区。"
#: doc/classes/AudioStreamGeneratorPlayback.xml
-#, fuzzy
msgid ""
"Returns the number of frames that can be pushed to the audio sample data "
"buffer without overflowing it. If the result is [code]0[/code], the buffer "
"is full."
msgstr ""
-"如果å¯ä»¥å°†å¤§å°ä¸º [code]amount[/code] 的缓冲区推é€åˆ°éŸ³é¢‘采样数æ®ç¼“冲区而ä¸ä½¿å…¶"
-"溢出,则返回 [code]true[/code],å¦åˆ™è¿”回 [code]false[/code]。"
+"返回能够推é€åˆ°éŸ³é¢‘采样数æ®ç¼“冲区而ä¸ä½¿å…¶æº¢å‡ºçš„帧数。如果结果为 [code]0[/"
+"code],则缓冲区已满。"
#: doc/classes/AudioStreamGeneratorPlayback.xml
msgid ""
@@ -13042,7 +13070,6 @@ msgstr ""
"[code]texture(SCREEN_TEXTURE, ...)[/code] 函数在ç€è‰²å™¨è„šæœ¬ä¸­å¯¹å…¶è¿›è¡Œè®¿é—®ã€‚"
#: doc/classes/BackBufferCopy.xml
-#, fuzzy
msgid ""
"Node for back-buffering the currently-displayed screen. The region defined "
"in the [BackBufferCopy] node is buffered with the content of the screen it "
@@ -13055,44 +13082,40 @@ msgid ""
"derived nodes as [i]siblings[/i] to the [BackBufferCopy] node instead of "
"adding them as children."
msgstr ""
-"用于对当å‰å±å¹•æ˜¾ç¤ºè¿›è¡ŒåŽå°ç¼“冲的节点。BackBufferCopy 节点中定义的区域与其覆盖"
-"å±å¹•çš„内容一起缓冲,或者根æ®æ‹·è´æ¨¡å¼è®¾ç½®çš„整个å±å¹•è¿›è¡Œç¼“冲。在ç€è‰²å™¨è„šæœ¬ä¸­ä½¿"
-"用 [code]texture(SCREEN_TEXTURE, ...)[/code] 函数æ¥è®¿é—®ç¼“冲区。\n"
+"用于对当å‰æ˜¾ç¤ºçš„å±å¹•è¿›è¡ŒåŽå°ç¼“冲的节点。[BackBufferCopy] 节点中定义的区域与其"
+"覆盖å±å¹•çš„内容一起缓冲,或者根æ®æ‹·è´æ¨¡å¼è®¾ç½®çš„整个å±å¹•è¿›è¡Œç¼“冲。在ç€è‰²å™¨è„šæœ¬"
+"中使用 [code]texture(SCREEN_TEXTURE, ...)[/code] 函数æ¥è®¿é—®ç¼“冲区。\n"
"[b]注æ„:[/b]由于该节点继承自 [Node2D] è€Œéž [Control],锚点和边è·å°†ä¸ä¼šåº”用于"
"从 [Control] 派生的å­èŠ‚点。这在调整窗å£å¤§å°æ—¶å¯èƒ½ä¼šå‡ºçŽ°é—®é¢˜ã€‚为é¿å…è¿™ç§æƒ…况,"
-"请将 [Control] 派生节点添加为 BackBufferCopy 节点的[i]åŒçº§[/i],ä¸è¦å°†å®ƒä»¬æ·»"
-"加为其å­èŠ‚点。"
+"请将 [Control] 派生节点添加为 [BackBufferCopy] 节点的[i]åŒçº§[/i],ä¸è¦å°†å®ƒä»¬"
+"添加为其å­èŠ‚点。"
#: doc/classes/BackBufferCopy.xml
msgid "Buffer mode. See [enum CopyMode] constants."
msgstr "缓冲区模å¼ã€‚è§ [enum CopyMode] 常é‡ã€‚"
#: doc/classes/BackBufferCopy.xml
-#, fuzzy
msgid ""
"The area covered by the [BackBufferCopy]. Only used if [member copy_mode] is "
"[constant COPY_MODE_RECT]."
msgstr ""
-"BackBufferCopy 覆盖的区域。åªæœ‰å½“ [member copy_mode] 是 [constant "
+"该 [BackBufferCopy] 所覆盖的区域。åªæœ‰å½“ [member copy_mode] 为 [constant "
"COPY_MODE_RECT] æ—¶æ‰ä½¿ç”¨ã€‚"
#: doc/classes/BackBufferCopy.xml
-#, fuzzy
msgid ""
"Disables the buffering mode. This means the [BackBufferCopy] node will "
"directly use the portion of screen it covers."
msgstr ""
-"ç¦ç”¨ç¼“冲模å¼ã€‚è¿™æ„å‘³ç€ BackBufferCopy 节点将直接使用它所覆盖的å±å¹•éƒ¨åˆ†ã€‚"
+"ç¦ç”¨ç¼“冲模å¼ã€‚è¿™æ„味ç€è¯¥ [BackBufferCopy] 节点将直接使用它所覆盖的å±å¹•éƒ¨åˆ†ã€‚"
#: doc/classes/BackBufferCopy.xml
-#, fuzzy
msgid "[BackBufferCopy] buffers a rectangular region."
-msgstr "BackBufferCopy 缓冲一个矩形区域。"
+msgstr "[BackBufferCopy] 缓冲一个矩形区域。"
#: doc/classes/BackBufferCopy.xml
-#, fuzzy
msgid "[BackBufferCopy] buffers the entire screen."
-msgstr "BackBufferCopy 缓冲整个å±å¹•ã€‚"
+msgstr "[BackBufferCopy] 缓冲整个å±å¹•ã€‚"
#: doc/classes/BakedLightmap.xml
msgid "Prerendered indirect light map for a scene."
@@ -14561,9 +14584,9 @@ msgid ""
"[Viewport] (or higher viewports) can't be displayed."
msgstr ""
"相机是一个特殊节点,用于显示从其当å‰ä½ç½®å¯è§çš„内容。相机在最近的 [Viewport] "
-"节点中注册自己(当树上行)。æ¯ä¸ªè§†åŒºåªèƒ½æ¿€æ´»ä¸€ä¸ªç›¸æœºã€‚如果在树上没有å¯ç”¨çš„视"
-"区,相机将在全局视区中注册。æ¢å¥è¯è¯´ï¼Œç›¸æœºåªæ˜¯ä¸º [Viewport] æä¾› 3D 显示能"
-"力,如果没有,则无法显示在该 [Viewport] 或更高视区中注册的场景。"
+"节点中注册自己(当树上行)。æ¯ä¸ªè§†å£åªèƒ½æ¿€æ´»ä¸€ä¸ªç›¸æœºã€‚如果在树上没有å¯ç”¨çš„视"
+"å£ï¼Œç›¸æœºå°†åœ¨å…¨å±€è§†å£ä¸­æ³¨å†Œã€‚æ¢å¥è¯è¯´ï¼Œç›¸æœºåªæ˜¯ä¸º [Viewport] æä¾› 3D 显示能"
+"力,如果没有,则无法显示在该 [Viewport] 或更高视å£ä¸­æ³¨å†Œçš„场景。"
#: doc/classes/Camera.xml
msgid ""
@@ -14720,7 +14743,7 @@ msgid ""
"[/codeblock]"
msgstr ""
"返回 [Viewport] 矩形中的 2D å标,该å标映射到世界空间中给定的 3D 点。\n"
-"[b]注æ„:[/b]当使用它æ¥å®šä½ 3D 视区上的 GUI 元素时,如果 3D 点在相机åŽé¢ï¼Œè¯·"
+"[b]注æ„:[/b]当使用它æ¥å®šä½ 3D 视å£ä¸Šçš„ GUI 元素时,如果 3D 点在相机åŽé¢ï¼Œè¯·"
"使用 [method is_position_behind] æ¥é˜²æ­¢å®ƒä»¬æ˜¾ç¤ºã€‚\n"
"[codeblock]\n"
"# 这个代ç å—是继承自 Spatial 的脚本的一部分。\n"
@@ -14768,7 +14791,7 @@ msgstr ""
"[code]_process[/code] 方法中的å˜åŒ–。多普勒效果åªå¯¹ [member "
"AudioStreamPlayer3D.doppler_tracking] 设置为 [constant AudioStreamPlayer3D."
"DOPPLER_TRACKING_DISABLED] 以外的值的 [AudioStreamPlayer3D] 节点进行模拟。\n"
-"[b]注æ„:[/b]è¦åœ¨ç¼–辑器中切æ¢å¤šæ™®å‹’效果预览,使用 3D 视区左上角的é€è§†èœå•ï¼Œå¹¶"
+"[b]注æ„:[/b]è¦åœ¨ç¼–辑器中切æ¢å¤šæ™®å‹’效果预览,使用 3D 视å£å·¦ä¸Šè§’çš„é€è§†èœå•ï¼Œå¹¶"
"切æ¢ä¸º[b]å¯ç”¨å¤šæ™®å‹’[/b]。"
#: doc/classes/Camera.xml
@@ -14816,7 +14839,7 @@ msgstr ""
#: doc/classes/Camera.xml
msgid "The horizontal (X) offset of the camera viewport."
-msgstr "相机视窗的水平(X)å移é‡ã€‚"
+msgstr "相机视å£çš„水平(X)å移é‡ã€‚"
#: doc/classes/Camera.xml
msgid ""
@@ -14852,7 +14875,7 @@ msgstr ""
#: doc/classes/Camera.xml
msgid "The vertical (Y) offset of the camera viewport."
-msgstr "相机视窗的垂直(Y)å移é‡ã€‚"
+msgstr "相机视å£çš„垂直(Y)å移é‡ã€‚"
#: doc/classes/Camera.xml
msgid ""
@@ -15023,7 +15046,7 @@ msgstr ""
msgid ""
"Make this the current 2D camera for the scene (viewport and layer), in case "
"there are many cameras in the scene."
-msgstr "使之æˆä¸ºè¯¥åœºæ™¯ï¼ˆè§†åŒºå’Œå›¾å±‚ï¼‰çš„å½“å‰ 2D 相机,以防场景中有很多相机。"
+msgstr "使之æˆä¸ºè¯¥åœºæ™¯ï¼ˆè§†å£å’Œå›¾å±‚ï¼‰çš„å½“å‰ 2D 相机,以防场景中有很多相机。"
#: doc/classes/Camera2D.xml
msgid ""
@@ -15070,7 +15093,7 @@ msgid ""
"or not a [Viewport], uses the default viewport instead."
msgstr ""
"连接到 [Camera2D] 的自定义 [Viewport] 节点。如果为 [code]null[/code] 或者ä¸"
-"是 [Viewport],则使用默认的视区。"
+"是 [Viewport],则使用默认的视å£ã€‚"
#: doc/classes/Camera2D.xml
msgid ""
@@ -15883,11 +15906,11 @@ msgstr "返回此项目的å˜æ¢çŸ©é˜µã€‚"
#: doc/classes/CanvasItem.xml
msgid "Returns the viewport's boundaries as a [Rect2]."
-msgstr "以 [Rect2] å½¢å¼è¿”回视区的边界。"
+msgstr "以 [Rect2] å½¢å¼è¿”回视å£çš„边界。"
#: doc/classes/CanvasItem.xml
msgid "Returns this item's transform in relation to the viewport."
-msgstr "返回这个项目相对于视区的å˜æ¢ã€‚"
+msgstr "返回这个项目相对于视å£çš„å˜æ¢ã€‚"
#: doc/classes/CanvasItem.xml
msgid "Returns the [World2D] where this item is in."
@@ -16281,7 +16304,7 @@ msgid ""
"Together with [member follow_viewport_scale] it can be used for a pseudo 3D "
"effect."
msgstr ""
-"å¯ç”¨æ—¶ï¼Œè¯¥ [CanvasLayer] 会使用视区的å˜æ¢ï¼Œæ‰€ä»¥å®ƒä¼šéšç›¸æœºç§»åŠ¨ï¼Œè€Œä¸æ˜¯ä¿æŒåœ¨å±"
+"å¯ç”¨æ—¶ï¼Œè¯¥ [CanvasLayer] 会使用视å£çš„å˜æ¢ï¼Œæ‰€ä»¥å®ƒä¼šéšç›¸æœºç§»åŠ¨ï¼Œè€Œä¸æ˜¯ä¿æŒåœ¨å±"
"幕上的æŸä¸ªå›ºå®šä½ç½®ã€‚\n"
"与 [member follow_viewport_scale] é…åˆå¯ä»¥å®žçŽ°ä¼ª 3D 效果。"
@@ -19193,7 +19216,7 @@ msgid ""
msgstr ""
"加载指定为å‚æ•°çš„é…置文件。解æžæ–‡ä»¶çš„内容并将其加载到调用该方法的 "
"[ConfigFile] 对象中。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/ConfigFile.xml
msgid ""
@@ -19204,7 +19227,7 @@ msgid ""
msgstr ""
"加载指定为å‚数的加密é…置文件,使用æ供的 [code]key[/code] 对其解密。解æžæ–‡ä»¶"
"的内容并将其加载到调用该方法的 [ConfigFile] 对象中。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/ConfigFile.xml
msgid ""
@@ -19215,7 +19238,7 @@ msgid ""
msgstr ""
"加载作为å‚数的加密é…置文件,使用æ供的 [code]password[/code] 解密。该文件的内"
"容被解æžå¹¶åŠ è½½åˆ°è°ƒç”¨è¯¥æ–¹æ³•çš„ [ConfigFile] 对象中。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/ConfigFile.xml
msgid ""
@@ -19225,7 +19248,7 @@ msgid ""
msgstr ""
"将传递的字符串解æžä¸ºé…置文件的内容。该字符串被解æžå¹¶åŠ è½½åˆ°è°ƒç”¨è¯¥æ–¹æ³•çš„ "
"ConfigFile 对象中。\n"
-"返回 [enum Error] 常é‡ä¹‹ä¸€ï¼ŒæˆåŠŸæ—¶è¿”回 [code]OK[/code]。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/ConfigFile.xml
msgid ""
@@ -19235,7 +19258,7 @@ msgid ""
msgstr ""
"å°† [ConfigFile] 对象的内容ä¿å­˜åˆ°æŒ‡å®šä¸ºå‚数的文件中。输出文件使用 INI æ ·å¼çš„结"
"构。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/ConfigFile.xml
msgid ""
@@ -19246,7 +19269,7 @@ msgid ""
msgstr ""
"使用æ供的 [code]key[/code] å°† [ConfigFile] 对象的内容ä¿å­˜åˆ°ä½œä¸ºå‚数指定的 "
"AES-256 加密文件中。输出文件使用 INI æ ·å¼çš„结构。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/ConfigFile.xml
msgid ""
@@ -19257,7 +19280,7 @@ msgid ""
msgstr ""
"å°† [ConfigFile] 对象的内容ä¿å­˜åˆ°ä½œä¸ºå‚数指定的 AES-256 加密文件中,使用æä¾›"
"的 [code]password[/code]进行加密。输出文件使用 INI 风格的结构。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/ConfigFile.xml
msgid ""
@@ -19380,7 +19403,7 @@ msgid ""
"code] methods provided by this class."
msgstr ""
"所有 UI 相关节点的基类。[Control] 具有定义其范围的边界矩形ã€ç›¸å¯¹äºŽå…¶çˆ¶æŽ§ä»¶æˆ–"
-"当å‰è§†çª—的锚点ä½ç½®ä»¥åŠè¡¨ç¤ºé”šç‚¹å移的边è·ã€‚当节点ã€å…¶ä»»ä½•çˆ¶èŠ‚点或å±å¹•å°ºå¯¸å‘生"
+"当å‰è§†å£çš„锚点ä½ç½®ä»¥åŠè¡¨ç¤ºé”šç‚¹å移的边è·ã€‚当节点ã€å…¶ä»»ä½•çˆ¶èŠ‚点或å±å¹•å°ºå¯¸å‘生"
"å˜åŒ–时,边è·ä¼šè‡ªåŠ¨æ›´æ–°ã€‚\n"
"更多关于 Godot çš„ UI 系统ã€é”šç‚¹ã€è¾¹è·å’Œå®¹å™¨çš„ä¿¡æ¯ï¼Œè¯·å‚阅手册中的相关教程。è¦"
"构建çµæ´»çš„ UI,您需è¦æ··åˆä½¿ç”¨ä»Ž [Control] å’Œ [Container] 节点继承的 UI å…ƒ"
@@ -19557,8 +19580,8 @@ msgid ""
"propagating, even to nodes listening to [method Node._unhandled_input] or "
"[method Node._unhandled_key_input]."
msgstr ""
-"将输入事件标记为已处ç†ã€‚一旦接å—输入事件,它就会åœæ­¢ä¼ æ’­ï¼Œç”šè‡³ä¼ æ’­åˆ°æ­£åœ¨ä¾¦å¬"
-"[method Node._unhandled_input]或[method Node._unhandled_key_input]的节点。"
+"将输入事件标记为已处ç†ã€‚一旦接å—输入事件,传播就会åœæ­¢ï¼Œä¸ä¼šå†ä¼ æ’­åˆ°æ­£åœ¨ä¾¦å¬ "
+"[method Node._unhandled_input] 和 [method Node._unhandled_key_input] 的节点。"
#: doc/classes/Control.xml
msgid ""
@@ -20647,7 +20670,7 @@ msgid ""
"handled."
msgstr ""
"关闭模æ€æŽ§ä»¶æ—¶ï¼Œè¾“入是å¦ä¼ æ’­ã€‚\n"
-"如果为 [code]false[/code],事件处ç†å°†åœæ­¢åœ¨è§†åŒºçš„输入事件处ç†ã€‚该视区会先将模"
+"如果为 [code]false[/code],事件处ç†å°†åœæ­¢åœ¨è§†å£çš„输入事件处ç†ã€‚该视å£ä¼šå…ˆå°†æ¨¡"
"æ€æŽ§ä»¶éšè—,然åŽå†å°†è¾“入标记为已处ç†ã€‚"
#: doc/classes/Control.xml
@@ -20800,7 +20823,7 @@ msgstr ""
"这个值进行缩放。\n"
"[b]注æ„:[/b]这个属性主è¦ç”¨äºŽåŠ¨ç”»ç”¨é€”。当控件被缩放时,控件内的文本将看起æ¥æ˜¯"
"åƒç´ åŒ–或模糊的。è¦åœ¨ä½ çš„项目支æŒå¤šç§åˆ†è¾¨çŽ‡ï¼Œè¯·ä½¿ç”¨[url=$DOCS_URL/tutorials/"
-"rendering/multiple_resolutions.html]文档[/url]中æè¿°çš„åˆé€‚的视窗拉伸模å¼ï¼Œè€Œ"
+"rendering/multiple_resolutions.html]文档[/url]中æè¿°çš„åˆé€‚的视å£æ‹‰ä¼¸æ¨¡å¼ï¼Œè€Œ"
"ä¸æ˜¯å•ç‹¬ç¼©æ”¾æŽ§ä»¶ã€‚\n"
"[b]注æ„:[/b]如果控件节点是 [Container] 节点的å­èŠ‚点,当场景实例化时,缩放将"
"被é‡ç½®ä¸º [code]Vector2(1, 1)[/code]。è¦åœ¨å®žä¾‹åŒ–时设置控件的缩放,使用 "
@@ -24076,7 +24099,7 @@ msgstr ""
#: doc/classes/CylinderShape.xml
msgid "Cylinder shape for collisions."
-msgstr "碰撞用的圆柱体形状。"
+msgstr "用于碰撞的圆柱体形状。"
#: doc/classes/CylinderShape.xml
msgid ""
@@ -24085,6 +24108,9 @@ msgid ""
"engine, there are several known bugs with cylinder collision shapes. Using "
"[CapsuleShape] or [BoxShape] instead is recommended."
msgstr ""
+"用于碰撞的圆柱体形状。\n"
+"[b]注æ„:[/b]使用 GodotPhysics 而éžé»˜è®¤çš„ Bullet 物ç†å¼•æ“Žæ—¶ï¼Œåœ†æŸ±ä½“碰撞形状存"
+"在已知的问题。推è使用 [CapsuleShape] 或 [BoxShape] 代替。"
#: doc/classes/CylinderShape.xml
msgid "The cylinder's height."
@@ -24665,7 +24691,7 @@ msgstr ""
"将当å‰æ‰“开的目录改为å‚数传递的目录。å‚æ•°å¯ä»¥æ˜¯ç›¸å¯¹äºŽå½“å‰ç›®å½•çš„(例如 "
"[code]newdir[/code] 或 [code].../newdir[/code]),也å¯ä»¥æ˜¯ç»å¯¹è·¯å¾„(例如 "
"[code]/tmp/newdir[/code] 或 [code]res://somedir/newdir[/code])。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆ[code]OK[/code] æˆåŠŸæ—¶ï¼‰ã€‚"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/Directory.xml
msgid ""
@@ -24677,7 +24703,7 @@ msgid ""
msgstr ""
"å°† [code]from[/code] 文件å¤åˆ¶åˆ° [code]to[/code] 目标ä½ç½®ã€‚两个å‚数都应该是相"
"对或ç»å¯¹æ–‡ä»¶çš„路径。如果目标文件存在且没有访问ä¿æŠ¤ï¼Œåˆ™ä¼šè¢«è¦†ç›–。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/Directory.xml
msgid ""
@@ -24685,8 +24711,8 @@ msgid ""
"call is a directory ([code].[/code] and [code]..[/code] are considered "
"directories)."
msgstr ""
-"返回上一次 [method get_next] 调用处ç†çš„当å‰é¡¹ç›®æ˜¯å¦ä¸ºç›®å½•ï¼ˆ[code].[/code]å’Œ"
-"[code].[/code]被认为是目录)。"
+"返回上一次 [method get_next] 调用处ç†çš„当å‰é¡¹ç›®æ˜¯å¦ä¸ºç›®å½•ï¼ˆ[code].[/code] å’Œ "
+"[code].[/code] 属于目录)。"
#: doc/classes/Directory.xml
msgid ""
@@ -24707,16 +24733,16 @@ msgid ""
"Returns the absolute path to the currently opened directory (e.g. "
"[code]res://folder[/code] or [code]C:\\tmp\\folder[/code])."
msgstr ""
-"返回当å‰æ‰“开目录的ç»å¯¹è·¯å¾„(例如[code]res://文件夹[/code]或[code]C:\\tmp\\æ–‡"
-"件夹[/code])。"
+"返回当å‰æ‰“开目录的ç»å¯¹è·¯å¾„(例如 [code]res://文件夹[/code] 或 [code]C:"
+"\\tmp\\文件夹[/code])。"
#: doc/classes/Directory.xml
msgid ""
"Returns the currently opened directory's drive index. See [method get_drive] "
"to convert returned index to the name of the drive."
msgstr ""
-"返回当å‰æ‰“开的目录的驱动器索引。请å‚阅[method get_drive]将返回的索引转æ¢ä¸ºé©±"
-"动器的å称。"
+"返回当å‰æ‰“开的目录的驱动器索引。请å‚阅 [method get_drive] 将返回的索引转æ¢ä¸º"
+"驱动器的å称。"
#: doc/classes/Directory.xml
msgid ""
@@ -24757,11 +24783,12 @@ msgid ""
"closes the stream automatically (i.e. [method list_dir_end] would not be "
"mandatory in such a case)."
msgstr ""
-"返回当å‰ç›®å½•ä¸­çš„下一个元素(文件或目录)(包括[code].[/code]å’Œ[code].[/"
-"code],除éž[code]skip_navigational[/code]被赋予[method list_dir_begin])。\n"
+"返回当å‰ç›®å½•ä¸­çš„下一个元素(文件或目录。除éžå°† [code]skip_navigational[/"
+"code] 赋予 [method list_dir_begin],å¦åˆ™åŒ…括 [code].[/code] å’Œ [code].[/"
+"code])。\n"
"返回的是文件或目录的å称(而ä¸æ˜¯å®ƒçš„完整路径)。一旦æµè¢«å®Œå…¨å¤„ç†ï¼Œè¯¥æ–¹æ³•è¿”回"
-"一个空的String,并自动关闭æµï¼ˆå³åœ¨è¿™ç§æƒ…况下,[method list_dir_end]å°†ä¸æ˜¯å¼ºåˆ¶"
-"性的)。"
+"一个空的 String,并自动关闭æµï¼ˆå³åœ¨è¿™ç§æƒ…况下,[method list_dir_end] å°†ä¸æ˜¯å¼º"
+"制性的)。"
#: doc/classes/Directory.xml
msgid ""
@@ -24808,7 +24835,7 @@ msgstr ""
"创建一个目录。å‚æ•°å¯ä»¥æ˜¯å½“å‰ç›®å½•çš„相对路径,也å¯ä»¥æ˜¯ç»å¯¹è·¯å¾„。目标目录应该放"
"置在一个已ç»å­˜åœ¨çš„目录中(如果è¦é€’归创建完整的路径,请å‚阅 [method "
"make_dir_recursive])。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/Directory.xml
msgid ""
@@ -24817,9 +24844,9 @@ msgid ""
"to the current directory, or an absolute path.\n"
"Returns one of the [enum Error] code constants ([code]OK[/code] on success)."
msgstr ""
-"通过递归调用 [method make_dir]方法,创建一个目标目录和其路径中所有必è¦çš„中间"
+"通过递归调用 [method make_dir] 方法,创建一个目标目录和其路径中所有必è¦çš„中间"
"目录。å‚æ•°å¯ä»¥æ˜¯ç›¸å¯¹äºŽå½“å‰ç›®å½•çš„,也å¯ä»¥æ˜¯ç»å¯¹è·¯å¾„。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/Directory.xml
msgid ""
@@ -24833,7 +24860,7 @@ msgstr ""
"folder[/code]),用户目录([code]user:// folder[/code])或以下ä½ç½®çš„ç»å¯¹è·¯å¾„"
"内:用户文件系统(例如 [code]/tmp/folder[/code] 或 [code]C:\\tmp\\folder[/"
"code])。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/Directory.xml
msgid ""
@@ -24847,7 +24874,7 @@ msgstr ""
"永久删除目标文件或空目录。å‚æ•°å¯ä»¥æ˜¯ç›¸å¯¹äºŽå½“å‰ç›®å½•çš„,也å¯ä»¥æ˜¯ç»å¯¹è·¯å¾„。如果"
"目标目录ä¸æ˜¯ç©ºçš„,æ“作将失败。\n"
"如果你ä¸æƒ³æ°¸ä¹…删除该文件/目录,请使用 [method OS.move_to_trash] 代替。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ˆæˆåŠŸæ—¶è¿”回 [code]OK[/code])。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/Directory.xml
msgid ""
@@ -24860,7 +24887,7 @@ msgstr ""
"å°† [code]from[/code] 文件或目录é‡å‘½å且移动到 [code]to[/code] 目标。两个å‚æ•°"
"都应该是文件或目录的相对路径或ç»å¯¹è·¯å¾„。如果目标文件或目录存在且ä¸å—访问ä¿"
"护,它将被覆盖。\n"
-"返回 [enum Error] 代ç å¸¸é‡ä¹‹ä¸€ï¼ŒæˆåŠŸæ—¶è¿”回 [code]OK[/code]。"
+"返回 [enum Error] 错误ç å¸¸é‡ï¼ˆæˆåŠŸæ—¶ä¸º [code]OK[/code])。"
#: doc/classes/DTLSServer.xml
msgid "Helper class to implement a DTLS server."
@@ -25127,7 +25154,7 @@ msgid ""
"This can be a negative number to make the distance between words smaller."
msgstr ""
"空格字符(在 [member extra_spacing_char] 之外)的é¢å¤–é—´è·ï¼Œå•ä½ä¸ºåƒç´ ã€‚\n"
-"è¿™å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œä½¿å­—符之间的è·ç¦»æ›´å°ã€‚"
+"å¯ä»¥æ˜¯è´Ÿæ•°ï¼Œä¼šä½¿å­—符之间的è·ç¦»æ›´å°ã€‚"
#: doc/classes/DynamicFont.xml
msgid "Extra spacing at the top in pixels."
@@ -25166,9 +25193,9 @@ msgid ""
"control whose size changes over time, unless a pixel art aesthetic is "
"desired."
msgstr ""
-"如果为 [code]true[/code],将使用过滤功能。如果字体过度采样被ç¦ç”¨æˆ–无效,这将"
-"使字体在缩放时å˜å¾—模糊,而éžåƒç´ åŒ–。当在尺寸éšæ—¶å˜åŒ–的控件中使用字体时,建议"
-"å¯ç”¨è¿™ä¸ªåŠŸèƒ½ï¼Œé™¤éžæ˜¯åƒç´ è®¾è®¡ã€‚"
+"如果为 [code]true[/code],将使用过滤功能。如果字体过采样被ç¦ç”¨æˆ–无法生效,字"
+"体在缩放时会å˜å¾—模糊,而éžåƒç´ åŒ–。在尺寸会éšæ—¶å˜åŒ–的控件中使用字体时,建议å¯"
+"用这个功能,除éžæƒ³è¦åƒç´ ç”»é£Žæ ¼ã€‚"
#: doc/classes/DynamicFont.xml
msgid ""
@@ -25176,8 +25203,8 @@ msgid ""
"appearance when downscaling it if font oversampling is disabled or "
"ineffective."
msgstr ""
-"如果为 [code]true[/code],将使用 mipmap 多级æ¸è¿œçº¹ç†ã€‚在字体过度采样被ç¦ç”¨æˆ–"
-"无效时,å¯æ”¹å–„字体缩å°æ—¶çš„表现。"
+"如果为 [code]true[/code],将使用 mipmap 多级æ¸è¿œçº¹ç†ã€‚在字体过采样被ç¦ç”¨æˆ–æ— "
+"法生效时,å¯æ”¹å–„字体缩å°æ—¶çš„表现。"
#: doc/classes/DynamicFont.xml
msgid "Spacing at the top."
@@ -25229,7 +25256,7 @@ msgid ""
"and viewport stretch mode."
msgstr ""
"如果设为比 [code]0.0[/code] 大的值,则会覆盖默认的字体过采样,忽略 [member "
-"SceneTree.use_font_oversampling] 的值和视å£æ‹‰ä¼¸æ¨¡å¼ã€‚"
+"SceneTree.use_font_oversampling] 的值和视å£çš„拉伸模å¼ã€‚"
#: doc/classes/DynamicFontData.xml
msgid "Disables font hinting (smoother but less crisp)."
@@ -26338,7 +26365,7 @@ msgstr ""
"新)加载场景,渲染网格预览,检查和编辑资æºå’Œå¯¹è±¡ã€‚它å…许自定义窗å£ï¼Œä¿å­˜å’Œ"
"(é‡æ–°ï¼‰åŠ è½½åœºæ™¯ï¼Œæ¸²æŸ“网格预览,检查和编辑资æºå’Œå¯¹è±¡ï¼Œå¹¶æ供对 "
"[EditorSettings]ã€[EditorFileSystem]ã€[EditorResourcePreview]ã€"
-"[ScriptEditor]ã€ç¼–辑器视窗和场景信æ¯çš„访问。\n"
+"[ScriptEditor]ã€ç¼–辑器视å£å’Œåœºæ™¯ä¿¡æ¯çš„访问。\n"
"[b]注æ„:[/b]这个类ä¸åº”该直接实例化。相å,使用 [method EditorPlugin."
"get_editor_interface] 访问å•ä¾‹ã€‚"
@@ -26414,7 +26441,7 @@ msgid ""
msgstr ""
"返回主编辑器控件。将其作为主å±å¹•çš„父控件。\n"
"[b]注æ„:[/b]这将返回包å«æ•´ä¸ªç¼–辑器的主编辑器控件,而ä¸æ˜¯å…·ä½“çš„ 2D或 3D 视"
-"窗。\n"
+"å£ã€‚\n"
"[b]警告:[/b]删除和释放这个节点将使编辑器的一部分失去作用,并å¯èƒ½å¯¼è‡´å´©æºƒã€‚"
#: doc/classes/EditorInterface.xml
@@ -26734,7 +26761,7 @@ msgid ""
"custom gizmos to the 3D preview viewport for a [Spatial].\n"
"See [method add_inspector_plugin] for an example of how to register a plugin."
msgstr ""
-"注册一个新的 [EditorSpatialGizmoPlugin]。å°å·¥å…·æ’件å¯ä»¥åœ¨ 3D 预览视区中为 "
+"注册一个新的 [EditorSpatialGizmoPlugin]。å°å·¥å…·æ’件å¯ä»¥åœ¨ 3D 预览视å£ä¸­ä¸º "
"[Spatial] 添加自定义的å°å·¥å…·ã€‚\n"
"注册æ’ä»¶çš„ç¤ºä¾‹è§ [method add_inspector_plugin]。"
@@ -26830,8 +26857,8 @@ msgid ""
" return false\n"
"[/codeblock]"
msgstr ""
-"引擎会在 2D 编辑器的视区å‘生更新时调用。使用 [code]overlay[/code] [Control] "
-"进行绘制。你å¯ä»¥é€šè¿‡è°ƒç”¨ [method update_overlays] 手动更新视窗。\n"
+"引擎会在 2D 编辑器的视å£å‘生更新时调用。使用 [code]overlay[/code] [Control] "
+"进行绘制。你å¯ä»¥é€šè¿‡è°ƒç”¨ [method update_overlays] 手动更新视å£ã€‚\n"
"[codeblock]\n"
"func forward_canvas_draw_over_viewport(overlay):\n"
" # 在光标ä½ç½®ç”»ä¸€ä¸ªåœ†ã€‚\n"
@@ -26840,7 +26867,7 @@ msgstr ""
"\n"
"func forward_canvas_gui_input(event):\n"
" if event is InputEventMouseMotion:\n"
-" # 当光标被移动时,é‡ç»˜è§†çª—。\n"
+" # 当光标被移动时,é‡ç»˜è§†å£ã€‚\n"
" update_overlays()\n"
" return true\n"
" return false\n"
@@ -26883,7 +26910,7 @@ msgid ""
" return forward\n"
"[/codeblock]"
msgstr ""
-"当当å‰ç¼–辑场景中有一个根节点时被调用,[method handles]实现,在2D视窗中å‘生按"
+"当当å‰ç¼–辑场景中有一个根节点时被调用,[method handles]实现,在2D视å£ä¸­å‘生按"
"键输入[InputEvent]。拦截按键输入[InputEvent],如果[code]return true[/code] "
"[EditorPlugin]消耗键值[code]event[/code],å¦åˆ™å°†é”®å€¼[code]event[/code]转å‘ç»™"
"其他Editor类。例å­:\n"
@@ -26922,9 +26949,9 @@ msgid ""
" return false\n"
"[/codeblock]"
msgstr ""
-"引擎会在 3D 编辑器的视区å‘生更新时调用。使用 [code]overlay[/code] 控件 "
+"引擎会在 3D 编辑器的视å£å‘生更新时调用。使用 [code]overlay[/code] 控件 "
"[Control] 进行绘制。你å¯ä»¥é€šè¿‡è°ƒç”¨ [method update_overlays] 更新覆盖手动更新"
-"视窗。\n"
+"视å£ã€‚\n"
"[codeblock]\n"
"func forward_spatial_draw_over_viewport(overlay):\n"
" # 在光标ä½ç½®ç”»ä¸€ä¸ªåœ†ã€‚\n"
@@ -26932,7 +26959,7 @@ msgstr ""
"\n"
"func forward_spatial_gui_input(camera, event):\n"
" if event is InputEventMouseMotion:\n"
-" # 当光标被移动时,é‡ç»˜è§†çª—。\n"
+" # 当光标被移动时,é‡ç»˜è§†å£ã€‚\n"
" update_overlays()\n"
" return true\n"
" return false\n"
@@ -26975,7 +27002,7 @@ msgid ""
" return forward\n"
"[/codeblock]"
msgstr ""
-"在当å‰ç¼–辑的场景中存在根节点时调用,实现[method handles]并在3D视窗中å‘生按键"
+"在当å‰ç¼–辑的场景中存在根节点时调用,实现[method handles]并在3D视å£ä¸­å‘生按键"
"输入[InputEvent]。拦截按键输入[InputEvent],如果[code]return true[/code],则"
"[EditorPlugin]会使用键值[code]event[/code],å¦åˆ™å°†é”®å€¼[code]event[/code]转å‘"
"到其他Editor类。例å­ï¼š\n"
@@ -27245,7 +27272,7 @@ msgid ""
"once and it will work permanently for this plugin."
msgstr ""
"å¯ç”¨ 2D 编辑器的 [method forward_canvas_force_draw_over_viewport] å’Œ 3D 编辑"
-"器的 [method forward_spatial_force_draw_over_viewport] 在其视窗更新时的调用。"
+"器的 [method forward_spatial_force_draw_over_viewport] 在其视å£æ›´æ–°æ—¶çš„调用。"
"ä½ åªéœ€è¦è°ƒç”¨è¿™ä¸ªæ–¹æ³•ä¸€æ¬¡ï¼Œå®ƒå°±ä¼šå¯¹è¿™ä¸ªæ’件永久起作用。"
#: doc/classes/EditorPlugin.xml
@@ -27312,7 +27339,7 @@ msgid ""
"forward_spatial_draw_over_viewport] and [method "
"forward_spatial_force_draw_over_viewport] to be called."
msgstr ""
-"更新 2D 和 3D 编辑器视窗的覆盖层。导致方法 [method "
+"æ›´æ–° 2D å’Œ 3D 编辑器视å£çš„覆盖层。导致方法 [method "
"forward_canvas_draw_over_viewport]ã€[method "
"forward_canvas_force_draw_over_viewport]ã€[method "
"forward_spatial_draw_over_viewport] 和 [method "
@@ -27890,7 +27917,6 @@ msgid "Base script that can be used to add extension functions to the editor."
msgstr "å¯ç”¨äºŽä¸ºç¼–辑器添加扩展功能的基础脚本。"
#: doc/classes/EditorScript.xml
-#, fuzzy
msgid ""
"Scripts extending this class and implementing its [method _run] method can "
"be executed from the Script Editor's [b]File > Run[/b] menu option (or by "
@@ -27927,7 +27953,9 @@ msgstr ""
" print(\"Hello from the Godot Editor!\")\n"
"[/codeblock]\n"
"[b]注æ„:[/b]脚本在编辑器上下文中è¿è¡Œï¼Œè¿™æ„味ç€è¾“出在与编辑器一起å¯åŠ¨çš„控制å°"
-"窗å£ï¼ˆstdout),而ä¸æ˜¯é€šå¸¸çš„ Godot [b]输出[/b]é¢æ¿ 。"
+"窗å£ï¼ˆstdout),而ä¸æ˜¯é€šå¸¸çš„ Godot [b]输出[/b]é¢æ¿ 。\n"
+"[b]注æ„:[/b]EditorScript 进行了引用计数,ä¸å†è¢«å¼•ç”¨æ—¶å°±ä¼šè¢«é”€æ¯ã€‚在进行异步"
+"æ“作时,如果ä¸å†å­˜åœ¨å¯¹è¯¥è„šæœ¬çš„引用,就å¯èƒ½é€ æˆé”™è¯¯ã€‚"
#: doc/classes/EditorScript.xml
msgid "This method is executed by the Editor when [b]File > Run[/b] is used."
@@ -37769,6 +37797,7 @@ msgstr ""
"[b]注æ„:[/b]这个值在 Android å’Œ iOS 上å¯ç«‹å³è¢«ç¡¬ä»¶ä¼ æ„Ÿå™¨çš„值所覆盖。"
#: doc/classes/Input.xml
+#, fuzzy
msgid ""
"Sets a custom mouse cursor image, which is only visible inside the game "
"window. The hotspot can also be specified. Passing [code]null[/code] to the "
@@ -37780,7 +37809,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
"设置一个自定义鼠标光标图åƒï¼Œè¯¥å›¾åƒä»…当游æˆçª—å£å†…å¯è§ã€‚还å¯ä»¥æŒ‡å®šçƒ­ç‚¹ã€‚å°† "
"[code]null[/code] 传递给 image å‚æ•°å°†é‡ç½®ä¸ºç³»ç»Ÿå…‰æ ‡ã€‚有关详细信æ¯ï¼Œè¯·å‚阅 "
@@ -37801,7 +37834,7 @@ msgid ""
"[b]Note:[/b] This method generates an [InputEventMouseMotion] to update "
"cursor immediately."
msgstr ""
-"设置该视区中使用的默认光标形状,而ä¸æ˜¯ [constant CURSOR_ARROW]。\n"
+"设置该视å£ä¸­ä½¿ç”¨çš„默认光标形状,而ä¸æ˜¯ [constant CURSOR_ARROW]。\n"
"[b]注æ„:[/b]如果è¦æ›´æ”¹ [Control] 节点的默认光标形状,请改用 [member Control."
"mouse_default_cursor_shape]。\n"
"[b]注æ„:[/b]这个方法会生æˆä¸€ä¸ª [InputEventMouseMotion] 以立å³æ›´æ–°å…‰æ ‡ã€‚"
@@ -41529,7 +41562,6 @@ msgstr ""
"如果为 [code]true[/code],则光线的效果会逆转,使区域å˜æš—并投射明亮的阴影。"
#: doc/classes/Light.xml
-#, fuzzy
msgid ""
"The size of the light in Godot units. Only considered in baked lightmaps and "
"only if [member light_bake_mode] is set to [constant BAKE_ALL]. Increasing "
@@ -41540,7 +41572,9 @@ msgid ""
msgstr ""
"ç¯å…‰çš„大å°ï¼Œä½¿ç”¨ Godot çš„å•ä½ã€‚åªåœ¨çƒ˜ç„™çš„光照贴图中考虑,并且åªåœ¨ [member "
"light_bake_mode] 被设置为 [constant BAKE_ALL] 时考虑。增加这个值会使阴影看起"
-"æ¥æ›´æ¨¡ç³Šã€‚è¿™å¯ä»¥åœ¨ä¸€å®šç¨‹åº¦ä¸Šç”¨äºŽæ¨¡æ‹ŸåŒºåŸŸç¯å…‰ã€‚"
+"æ¥æ›´æ¨¡ç³Šã€‚è¿™å¯ä»¥åœ¨ä¸€å®šç¨‹åº¦ä¸Šç”¨äºŽæ¨¡æ‹ŸåŒºåŸŸç¯å…‰ã€‚\n"
+"[b]注æ„:[/b][member light_size] ä¸å— [member Spatial.scale] çš„å½±å“(无论是该"
+"ç¯å…‰çš„缩放还是其父节点的缩放)。"
#: doc/classes/Light.xml
msgid ""
@@ -44044,7 +44078,7 @@ msgid ""
"MeshInstance2D[/b] at the top of the 2D editor viewport."
msgstr ""
"用于在 2D 中显示 [Mesh] 的节点。å¯ä»¥é€šè¿‡ç¼–辑器工具æ ä¸Šçš„工具从现有的 "
-"[Sprite] 构建。选中 [Sprite] 节点,然åŽåœ¨ 2D 编辑器视区顶部选择[b]ç²¾çµ > 转æ¢"
+"[Sprite] 构建。选中 [Sprite] 节点,然åŽåœ¨ 2D 编辑器视å£é¡¶éƒ¨é€‰æ‹©[b]ç²¾çµ > 转æ¢"
"为 MeshInstance2D[/b]。"
#: doc/classes/MeshInstance2D.xml
@@ -45547,7 +45581,6 @@ msgid "3D agent used in navigation for collision avoidance."
msgstr "在导航中用于防撞的 3D 代ç†ã€‚"
#: doc/classes/NavigationAgent.xml
-#, fuzzy
msgid ""
"3D agent that is used in navigation to reach a location while avoiding "
"static and dynamic obstacles. The dynamic obstacles are avoided using RVO "
@@ -45574,7 +45607,9 @@ msgstr ""
"[NavigationAgent] 是物ç†å®‰å…¨çš„。\n"
"[b]注æ„:[/b]使用 [method set_target_location] 之åŽï¼Œå¿…须在æ¯ä¸ªç‰©ç†å¸§ä½¿ç”¨ä¸€"
"次 [method get_next_location] 函数æ¥æ›´æ–° NavigationAgent 的内部路径逻辑。这个"
-"函数返回的å‘é‡ä½ç½®åº”该用作该代ç†çš„父节点的下一次移动ä½ç½®ã€‚"
+"函数返回的å‘é‡ä½ç½®åº”该用作该代ç†çš„父节点的下一次移动ä½ç½®ã€‚\n"
+"[b]注æ„:[/b]默认情况下,é¿éšœçš„大强度计算是在å•ç‹¬çš„线程中进行的。在ä¸æ”¯æŒå¤šçº¿"
+"程的 HTML5 导出中,则会在主线程中进行,å¯èƒ½å¯¼è‡´æ€§èƒ½é—®é¢˜ã€‚"
#: doc/classes/NavigationAgent.xml doc/classes/NavigationAgent2D.xml
msgid ""
@@ -45867,7 +45902,6 @@ msgid "2D agent used in navigation for collision avoidance."
msgstr "在导航中用于防撞的 2D 代ç†ã€‚"
#: doc/classes/NavigationAgent2D.xml
-#, fuzzy
msgid ""
"2D agent that is used in navigation to reach a location while avoiding "
"static and dynamic obstacles. The dynamic obstacles are avoided using RVO "
@@ -45894,7 +45928,9 @@ msgstr ""
"[NavigationAgent2D] 是物ç†å®‰å…¨çš„。\n"
"[b]注æ„:[/b]使用 [method set_target_location] 之åŽï¼Œå¿…须在æ¯ä¸ªç‰©ç†å¸§ä½¿ç”¨ä¸€"
"次 [method get_next_location] 函数æ¥æ›´æ–° NavigationAgent 的内部路径逻辑。这个"
-"函数返回的å‘é‡ä½ç½®åº”该用作该代ç†çš„父节点的下一次移动ä½ç½®ã€‚"
+"函数返回的å‘é‡ä½ç½®åº”该用作该代ç†çš„父节点的下一次移动ä½ç½®ã€‚\n"
+"[b]注æ„:[/b]默认情况下,é¿éšœçš„大强度计算是在å•ç‹¬çš„线程中进行的。在ä¸æ”¯æŒå¤šçº¿"
+"程的 HTML5 导出中,则会在主线程中进行,å¯èƒ½å¯¼è‡´æ€§èƒ½é—®é¢˜ã€‚"
#: doc/classes/NavigationAgent2D.xml
msgid ""
@@ -46763,7 +46799,6 @@ msgid "Server interface for low-level 3D navigation access."
msgstr "访问底层 3D 导航的æœåŠ¡å™¨æŽ¥å£ã€‚"
#: doc/classes/NavigationServer.xml
-#, fuzzy
msgid ""
"NavigationServer is the server responsible for all 3D navigation. It handles "
"several objects, namely maps, regions and agents.\n"
@@ -46805,6 +46840,8 @@ msgstr ""
"的速度触å‘回调。\n"
"[b]注æ„:[/b]防撞系统会忽略地区。直接使用修正åŽçš„速度å¯èƒ½ä¼šå°†ä»£ç†æŽ¨åˆ°å¯å¯¼èˆªåŒº"
"域之外。这是防撞系统的缺陷,更å¤æ‚的情况å¯èƒ½éœ€è¦ç”¨åˆ°ç‰©ç†å¼•æ“Žã€‚\n"
+"[b]注æ„:[/b]默认情况下,é¿éšœçš„大强度计算是在å•ç‹¬çš„线程中进行的。在ä¸æ”¯æŒå¤šçº¿"
+"程的 HTML5 导出中,则会在主线程中进行,å¯èƒ½å¯¼è‡´æ€§èƒ½é—®é¢˜ã€‚\n"
"æœåŠ¡å™¨ä¼šè®°å½•æ‰€æœ‰çš„调用,在åŒæ­¥é˜¶æ®µç»Ÿä¸€æ‰§è¡Œã€‚è¿™æ„味ç€ä½ å¯ä»¥æ”¾å¿ƒå¤§èƒ†åœ°ä»Žä»»ä½•çº¿"
"程中请求对地图进行任何修改。"
@@ -50536,9 +50573,9 @@ msgstr ""
"[OccluderShape] 是 [Occluder] 节点所使用的资æºï¼Œç”¨äºŽå‡ ä½•é®æŒ¡å‰”除。\n"
"该多边形必须是凸多边形。多边形顶点的创建与删除å¯ä»¥åœ¨ç¼–辑器的检查器中进行,也"
"å¯ä»¥é€šè¿‡è°ƒç”¨ [code]set_polygon_points[/code] 实现。æ¯ä¸€æ¡è¾¹çš„顶点都å¯ä»¥é€šè¿‡åœ¨"
-"编辑器视窗中拖拽手柄设置。\n"
+"编辑器视å£ä¸­æ‹–拽手柄设置。\n"
"å¦å¤–,æ¯ä¸€ä¸ªå¤šè¾¹å½¢é®æŒ¡å™¨éƒ½å¯ä»¥æ”¯æŒå•ä¸ªç©ºæ´žã€‚如果你在编辑器的检查器中为空洞添"
-"加至少三个顶点,就å¯ä»¥åœ¨ç¼–辑器视窗中拖拽空洞边缘顶点的å¥æŸ„。\n"
+"加至少三个顶点,就å¯ä»¥åœ¨ç¼–辑器视å£ä¸­æ‹–拽空洞边缘顶点的å¥æŸ„。\n"
"一般而言,多边形以åŠç©ºæ´žçš„边数越少,è¿è¡Œæ—¶ç³»ç»Ÿçš„处ç†é€Ÿåº¦å°±è¶Šå¿«ï¼Œæ‰€ä»¥åœ¨å¤§å¤šæ•°"
"情况下你都åªä¼šè®¾ç½® 4 个顶点。"
@@ -50632,7 +50669,6 @@ msgstr ""
"光的衰å‡ï¼ˆä¸‹é™ï¼‰æ›²çº¿ã€‚在[b]检查器[/b]中,通过å³é”®ç‚¹å‡»æ›²çº¿ï¼Œå¯ä»¥èŽ·å¾—许多预设。"
#: doc/classes/OmniLight.xml
-#, fuzzy
msgid ""
"The light's radius. Note that the effectively lit area may appear to be "
"smaller depending on the [member omni_attenuation] in use. No matter the "
@@ -50641,9 +50677,11 @@ msgid ""
"[b]Note:[/b] [member omni_range] is not affected by [member Spatial.scale] "
"(the light's scale or its parent's scale)."
msgstr ""
-"光的åŠå¾„。请注æ„,有效的照明区域å¯èƒ½çœ‹èµ·æ¥æ›´å°ï¼Œè¿™å–决于使用的 [member "
-"omni_attenuation]ã€‚æ— è®ºä½¿ç”¨ä½•ç§ [member omni_attenuation],光线都ä¸ä¼šåˆ°è¾¾è¿™ä¸ª"
-"åŠå¾„以外的地方。"
+"该ç¯å…‰çš„åŠå¾„。请注æ„,根æ®ä½¿ç”¨çš„ [member omni_attenuation],有效照明区域å¯èƒ½"
+"看起æ¥æ›´å°ã€‚无论使用 [member omni_attenuation] 为何值,光都ä¸ä¼šåˆ°è¾¾æ­¤èŒƒå›´ä¹‹å¤–"
+"的任何东西。\n"
+"[b]注æ„:[/b][member omni_range] ä¸å— [member Spatial.scale] çš„å½±å“(无论是该"
+"ç¯å…‰çš„缩放还是其父节点的缩放)。"
#: doc/classes/OmniLight.xml
msgid "See [enum ShadowDetail]."
@@ -51297,7 +51335,6 @@ msgid "Returns the audio driver name for the given index."
msgstr "返回给定索引的音频驱动程åºå称。"
#: doc/classes/OS.xml
-#, fuzzy
msgid ""
"Returns the [i]global[/i] cache data directory according to the operating "
"system's standards. On Linux, this path can be overridden by setting the "
@@ -51308,7 +51345,7 @@ msgid ""
"Not to be confused with [method get_user_data_dir], which returns the "
"[i]project-specific[/i] user data path."
msgstr ""
-"æ ¹æ®æ“作系统的标准返回[i]全局[/i]缓存数æ®ç›®å½•ã€‚在桌é¢å¹³å°ä¸Šï¼Œå¯ä»¥é€šè¿‡åœ¨å¯åŠ¨é¡¹"
+"æ ¹æ®æ“作系统的标准返回[i]全局[/i]缓存数æ®ç›®å½•ã€‚在 Linux 上,å¯ä»¥é€šè¿‡åœ¨å¯åŠ¨é¡¹"
"目之å‰è®¾ç½® [code]XDG_CACHE_HOME[/code] 环境å˜é‡æ¥è¦†ç›–此路径。有关更多信æ¯ï¼Œè¯·"
"å‚阅文档中的 [url=$DOCS_URL/tutorials/io/data_paths.html]《Godot 项目中的文件"
"路径》[/url]。å¦è¯·å‚阅 [method get_config_dir] å’Œ [method get_data_dir]。\n"
@@ -51362,7 +51399,6 @@ msgstr ""
"[/codeblock]"
#: doc/classes/OS.xml
-#, fuzzy
msgid ""
"Returns the [i]global[/i] user configuration directory according to the "
"operating system's standards. On Linux, this path can be overridden by "
@@ -51373,7 +51409,7 @@ msgid ""
"Not to be confused with [method get_user_data_dir], which returns the "
"[i]project-specific[/i] user data path."
msgstr ""
-"æ ¹æ®æ“作系统的标准,返回[i]全局[/i]用户é…置目录。在桌é¢å¹³å°ä¸Šï¼Œè¿™ä¸ªè·¯å¾„å¯ä»¥åœ¨"
+"æ ¹æ®æ“作系统的标准,返回[i]全局[/i]用户é…置目录。在 Linux 上,这个路径å¯ä»¥åœ¨"
"å¯åŠ¨é¡¹ç›®å‰é€šè¿‡è®¾ç½®[code]XDG_CONFIG_HOME[/code]环境å˜é‡æ¥è¦†ç›–。更多信æ¯è¯·å‚è§"
"文档中[url=$DOCS_URL/tutorials/io/data_paths.html]《Godot 项目中的文件路径》"
"[/url]。å¦è¯·å‚阅 [method get_cache_dir] å’Œ [method get_data_dir]。\n"
@@ -51398,7 +51434,6 @@ msgid ""
msgstr "返回当å‰ä½¿ç”¨çš„视频驱动程åºï¼Œä½¿ç”¨[enum VideoDriver]中的一个值。"
#: doc/classes/OS.xml
-#, fuzzy
msgid ""
"Returns the [i]global[/i] user data directory according to the operating "
"system's standards. On Linux, this path can be overridden by setting the "
@@ -51409,7 +51444,7 @@ msgid ""
"Not to be confused with [method get_user_data_dir], which returns the "
"[i]project-specific[/i] user data path."
msgstr ""
-"æ ¹æ®æ“作系统的标准,返回[i]全局[/i]用户数æ®ç›®å½•ã€‚在桌é¢å¹³å°ä¸Šï¼Œè¿™ä¸ªè·¯å¾„å¯ä»¥åœ¨"
+"æ ¹æ®æ“作系统的标准,返回[i]全局[/i]用户数æ®ç›®å½•ã€‚在 Linux 上,这个路径å¯ä»¥åœ¨"
"å¯åŠ¨é¡¹ç›®å‰é€šè¿‡è®¾ç½®[code]XDG_DATA_HOME[/code]环境å˜é‡æ¥è¦†ç›–。更多信æ¯è¯·å‚è§æ–‡"
"档中[url=$DOCS_URL/tutorials/io/data_paths.html]《Godot 项目中的文件路径》[/"
"url]。å¦è¯·å‚阅 [method get_cache_dir] å’Œ [method get_config_dir]。\n"
@@ -53698,14 +53733,14 @@ msgstr ""
"使用 [code]process_material[/code] 属性添加 [ParticlesMaterial] æ¥é…置粒å­å¤–"
"观和行为。或者,您å¯ä»¥æ·»åŠ ä¸€ä¸ªå°†åº”用于所有粒å­çš„ [ShaderMaterial]。\n"
"[b]注æ„:[/b][Particles] 仅在使用 GLES3 渲染器时有效。如果使用 GLES2 渲染器,"
-"请改用 [CPUParticles]。您å¯ä»¥é€šè¿‡é€‰æ‹©èŠ‚点,å•å‡» 3D 编辑器视窗顶部的"
+"请改用 [CPUParticles]。您å¯ä»¥é€šè¿‡é€‰æ‹©èŠ‚点,å•å‡» 3D 编辑器视å£é¡¶éƒ¨çš„"
"[b]Particles[/b]èœå•ï¼Œç„¶åŽé€‰æ‹©[b]转æ¢ä¸º CPUParticles[/b],将 [Particles] 转æ¢"
"为 [CPUParticles]。\n"
"[b]注æ„:[/b]在 macOS 上,渲染 [Particles] 比 [CPUParticles] è¦æ…¢ä¸Šå¾ˆå¤šï¼Œå› ä¸º"
"å˜æ¢å馈是在 CPU 上实现的,而ä¸æ˜¯ GPU。以 macOS 为目标时,请考虑使用 "
"[CPUParticles]。\n"
"[b]注æ„:[/b]在处ç†ç²’å­èŠ‚点åŽï¼Œè®°å¾—通过选择它æ¥æ›´æ–°å…¶ [member "
-"visibility_aabb],å•å‡» 3D 编辑器视窗顶部的[b]Particles[/b]èœå•ï¼Œç„¶åŽé€‰æ‹©[b]生"
+"visibility_aabb],å•å‡» 3D 编辑器视å£é¡¶éƒ¨çš„[b]Particles[/b]èœå•ï¼Œç„¶åŽé€‰æ‹©[b]生"
"æˆå¯è§ AABB[/b]。å¦åˆ™ï¼Œç²’å­å¯èƒ½ä¼šç”±äºŽç›¸æœºä½ç½®å’Œè§’度的改å˜çªç„¶æ¶ˆå¤±ã€‚"
#: doc/classes/Particles.xml
@@ -53860,15 +53895,14 @@ msgid "Particle systems (2D)"
msgstr "ç²’å­ç³»ç»Ÿï¼ˆ2D)"
#: doc/classes/Particles2D.xml
-#, fuzzy
msgid "2D Particles Demo"
-msgstr "2D å¹³å°è·³è·ƒæ¼”示"
+msgstr "2D ç²’å­æ¼”示"
#: doc/classes/Particles2D.xml
msgid ""
"2D Dodge The Creeps Demo (uses GPUParticles2D for the trail behind the "
"player)"
-msgstr ""
+msgstr "2D Dodge The Creeps 演示(玩家身åŽçš„拖尾使用的是 GPUParticles2D)"
#: doc/classes/Particles2D.xml
msgid "Returns a rectangle containing the positions of all existing particles."
@@ -58119,7 +58153,7 @@ msgid ""
msgstr ""
"Popup 是基本的 [Control],用于显示对è¯æ¡†å’Œå¼¹å‡ºçª—å£ã€‚默认情况下,它是一个å­çª—"
"å£å’Œæ¨¡æ€ï¼Œå‚阅 [Control],并具有自定义弹出行为的辅助程åºã€‚所有弹出方法都确ä¿"
-"在视窗中正确放置。"
+"在视å£ä¸­æ­£ç¡®æ”¾ç½®ã€‚"
#: doc/classes/Popup.xml
msgid "Popup (show the control in modal form)."
@@ -60422,7 +60456,7 @@ msgid ""
"default window size. Stretch mode settings also use this as a reference when "
"enabled."
msgstr ""
-"设置游æˆçš„主视窗高度。在桌é¢å¹³å°ä¸Šï¼Œè¿™æ˜¯é»˜è®¤çš„窗å£å¤§å°ã€‚当å¯ç”¨æ‹‰ä¼¸æ¨¡å¼è®¾ç½®"
+"设置游æˆçš„主视å£é«˜åº¦ã€‚在桌é¢å¹³å°ä¸Šï¼Œè¿™æ˜¯é»˜è®¤çš„窗å£å¤§å°ã€‚当å¯ç”¨æ‹‰ä¼¸æ¨¡å¼è®¾ç½®"
"时,也使用此å‚数作为å‚考。"
#: doc/classes/ProjectSettings.xml
@@ -60451,7 +60485,7 @@ msgid ""
"default window size. Stretch mode settings also use this as a reference when "
"enabled."
msgstr ""
-"设置游æˆçš„主视窗宽度。在桌é¢å¹³å°ä¸Šï¼Œè¿™æ˜¯é»˜è®¤çš„窗å£å¤§å°ã€‚当å¯ç”¨æ‹‰ä¼¸æ¨¡å¼è®¾ç½®"
+"设置游æˆçš„主视å£å®½åº¦ã€‚在桌é¢å¹³å°ä¸Šï¼Œè¿™æ˜¯é»˜è®¤çš„窗å£å¤§å°ã€‚当å¯ç”¨æ‹‰ä¼¸æ¨¡å¼è®¾ç½®"
"时,也使用此å‚数作为å‚考。"
#: doc/classes/ProjectSettings.xml
@@ -60585,7 +60619,7 @@ msgid ""
"and is the recommended setting."
msgstr ""
"如果已å¯ç”¨ï¼Œåˆ™ä¼šåœ¨å°† [member Viewport.gui_disable_input] 设为 [code]false[/"
-"code] ç¦ç”¨è§†åŒºçš„ GUI 输入时,将当å‰çš„鼠标悬åœåŠèšç„¦ä¸¢å¼ƒã€‚\n"
+"code] ç¦ç”¨è§†å£çš„ GUI 输入时,将当å‰çš„鼠标悬åœåŠèšç„¦ä¸¢å¼ƒã€‚\n"
"这样的行为能够帮助ä¿æŒ GUI 状æ€çš„å¥å£®ï¼Œè¾“å…¥æ¢å¤æ—¶ï¼Œæ— è®ºå½“æ—¶å‘生了什么都ä¸ä¼šäº§"
"生æ„外的结果。\n"
"如果已ç¦ç”¨ï¼Œä¼šä½¿ç”¨æ—§æœ‰è¡Œä¸ºï¼Œé™¤äº†ç¦ç”¨ GUI 输入本身ä¸ä¼šè¿›è¡Œé¢å¤–æ“作。\n"
@@ -60596,8 +60630,8 @@ msgid ""
"If [code]true[/code], swaps OK and Cancel buttons in dialogs on Windows and "
"UWP to follow interface conventions."
msgstr ""
-"如果为 [code]true[/code],在Windowså’ŒUWP的对è¯æ¡†ä¸­äº¤æ¢ç¡®å®šå’Œå–消按钮,以éµå¾ª"
-"ç•Œé¢æƒ¯ä¾‹ã€‚"
+"如果为 [code]true[/code],在 Windows å’Œ UWP 的对è¯æ¡†ä¸­äº¤æ¢ç¡®å®šå’Œå–消按钮,以"
+"éµå¾ªç•Œé¢æƒ¯ä¾‹ã€‚"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60639,9 +60673,9 @@ msgid ""
"necessary for the internal logic of several [Control]s. The events assigned "
"to the action can however be modified."
msgstr ""
-"默认用于确认焦点按钮ã€èœå•æˆ–列表项,或验è¯è¾“入的[InputEventAction]。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"默认用于确认焦点按钮ã€èœå•æˆ–列表项,或验è¯è¾“入的 [InputEventAction]。\n"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60650,9 +60684,9 @@ msgid ""
"necessary for the internal logic of several [Control]s. The events assigned "
"to the action can however be modified."
msgstr ""
-"默认放弃一个模æ€æˆ–挂起的输入的[InputEventAction]。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"默认用于放弃模æ€æˆ–挂起的输入的 [InputEventAction]。\n"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60661,9 +60695,9 @@ msgid ""
"necessary for the internal logic of several [Control]s. The events assigned "
"to the action can however be modified."
msgstr ""
-"默认在UI中å‘下移动的[InputEventAction]。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"默认在 UI 中å‘下移动的 [InputEventAction]。\n"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60676,8 +60710,8 @@ msgid ""
msgstr ""
"默认[InputEventAction]去[Control]的结æŸä½ç½®(例如[ItemList]或[Tree]中的最åŽä¸€"
"项),匹é…典型桌é¢UI系统中[constant KEY_END]的行为。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60689,8 +60723,8 @@ msgid ""
msgstr ""
"默认èšç„¦åœºæ™¯ä¸­çš„下一个[Control]çš„[InputEventAction]。焦点行为å¯ä»¥é€šè¿‡[member "
"Control.focus_next]é…置。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60702,8 +60736,8 @@ msgid ""
msgstr ""
"默认èšç„¦åœºæ™¯ä¸­çš„å‰ä¸€ä¸ª[Control]çš„[InputEventAction]。焦点行为å¯ä»¥é€šè¿‡[member "
"Control.focus_previous]é…置。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60716,8 +60750,8 @@ msgid ""
msgstr ""
"默认的将进入[Control]的起始ä½ç½®ï¼ˆä¾‹å¦‚[ItemList]或[Tree]中的第一个项目)时的"
"[InputEventAction],与典型的桌é¢UI系统中[constant KEY_HOME]的行为相匹é…。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬å¯¹äºŽå‡ ä¸ª[Control]"
-"的内部逻辑是必è¦çš„。然而,分é…给动作的事件å¯ä»¥è¢«ä¿®æ”¹ã€‚"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª "
+"[Control] 的内部逻辑所必需的。然而,分é…给动作的事件å¯ä»¥è¢«ä¿®æ”¹ã€‚"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60726,9 +60760,9 @@ msgid ""
"necessary for the internal logic of several [Control]s. The events assigned "
"to the action can however be modified."
msgstr ""
-"默认在UI中å‘左移动的[InputEventAction]。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"默认在 UI 中å‘左移动的[InputEventAction]。\n"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60742,8 +60776,8 @@ msgstr ""
"默认的在 [Control](例如 [ItemList] 或 [Tree])中å‘下翻页的 "
"[InputEventAction]ï¼Œä¸Žå…¸åž‹æ¡Œé¢ UI 系统中 [constant KEY_PAGEDOWN] 的行为相匹"
"é…。\n"
-"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª "
-"[Control] 的内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60757,8 +60791,8 @@ msgstr ""
"默认的在 [Control](例如 [ItemList] 或 [Tree])中å‘上翻页的 "
"[InputEventAction]ï¼Œä¸Žå…¸åž‹æ¡Œé¢ UI 系统中 [constant KEY_PAGEUP] 的行为相匹"
"é…。\n"
-"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª "
-"[Control] 的内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60767,9 +60801,9 @@ msgid ""
"necessary for the internal logic of several [Control]s. The events assigned "
"to the action can however be modified."
msgstr ""
-"默认在UI中å³ç§»çš„[InputEventAction]。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"默认在 UI 中å³ç§»çš„[InputEventAction]。\n"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60780,8 +60814,8 @@ msgid ""
"to the action can however be modified."
msgstr ""
"默认选择[Control](例如[ItemList]或[Tree])中的一个项目[InputEventAction]。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -60790,9 +60824,9 @@ msgid ""
"necessary for the internal logic of several [Control]s. The events assigned "
"to the action can however be modified."
msgstr ""
-"默认在UI中å‘上移动[InputEventAction]。\n"
-"[b]注æ„:[/b]默认的[code]ui_*[/code]动作ä¸èƒ½è¢«åˆ é™¤ï¼Œå› ä¸ºå®ƒä»¬æ˜¯å‡ ä¸ª[Control]çš„"
-"内部逻辑所必需的。但是,å¯ä»¥ä¿®æ”¹åˆ†é…给该æ“作的事件。"
+"默认在 UI 中å‘上移动[InputEventAction]。\n"
+"[b]注æ„:[/b]默认的 [code]ui_*[/code] 动作是部分 [Control] 的内部逻辑所必需"
+"的,无法删除。但是å¯ä»¥ä¿®æ”¹åˆ†é…给该动作的事件。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -63204,7 +63238,6 @@ msgstr ""
"的值通常会给出最好的结果。å¦è§ [member rendering/quality/filters/use_fxaa]。"
#: doc/classes/ProjectSettings.xml
-#, fuzzy
msgid ""
"If [code]true[/code], uses a fast post-processing filter to make banding "
"significantly less visible in 3D. 2D rendering is [i]not[/i] affected by "
@@ -63224,13 +63257,18 @@ msgid ""
"debanding at run-time, set [member Viewport.debanding] on the root "
"[Viewport] instead."
msgstr ""
-"如果为 [code]true[/code],则使用快速åŽå¤„ç†è¿‡æ»¤å™¨ä½¿æ¡å¸¦æ˜Žæ˜¾ä¸é‚£ä¹ˆæ˜Žæ˜¾ã€‚在æŸäº›"
-"情况下,去带å¯èƒ½ä¼šå¼•å…¥ç¨å¾®æ˜Žæ˜¾çš„抖动模å¼ã€‚建议仅在实际需è¦æ—¶å¯ç”¨åŽ»æ¡å¸¦ï¼Œå› ä¸º"
-"抖动模å¼ä¼šä½¿æ— æŸåŽ‹ç¼©çš„å±å¹•æˆªå›¾æ›´å¤§ã€‚\n"
+"如果为 [code]true[/code],则使用一个快速的åŽæœŸå¤„ç†æ»¤æ³¢å™¨ï¼Œä½¿ 3D 的带状现象明"
+"显å‡å°‘。2D 渲染[i]ä¸å—[/i]去æ¡å¸¦çš„å½±å“ï¼Œé™¤éž [member Environment."
+"background_mode] 为 [constant Environment.BG_CANVAS]。此时 [member rendering/"
+"quality/intended_usage/framebuffer_allocation] 也必须设为 [b]3D[/b]。\n"
+"在æŸäº›æƒ…况下,去带å¯èƒ½ä¼šå¼•å…¥ç¨å¾®æ˜Žæ˜¾çš„抖动模å¼ã€‚建议仅在实际需è¦æ—¶å¯ç”¨åŽ»æ¡"
+"带,因为抖动模å¼ä¼šä½¿æ— æŸåŽ‹ç¼©çš„å±å¹•æˆªå›¾æ›´å¤§ã€‚\n"
"[b]注æ„:[/b]仅在 GLES3 åŽç«¯å¯ç”¨ã€‚[member rendering/quality/depth/hdr] 也必须"
"为 [code]true[/code] æ‰èƒ½ä½¿åŽ»è‰²å¸¦æœ‰æ•ˆã€‚\n"
"[b]注æ„:[/b]已知在移动平å°ä¸Šçš„去色带存在破å渲染的问题。因此,建议在用于移动"
-"å¹³å°æ—¶ç¦ç”¨æ­¤é€‰é¡¹ã€‚"
+"å¹³å°æ—¶ç¦ç”¨æ­¤é€‰é¡¹ã€‚\n"
+"[b]注æ„:[/b]这个属性在项目å¯åŠ¨æ—¶æ˜¯åªè¯»çš„。è¦åœ¨è¿è¡Œæ—¶è®¾ç½®åŽ»æ¡å¸¦ï¼Œè¯·åœ¨æ ¹ "
+"[Viewport] 上设置 [member Viewport.debanding]。"
#: doc/classes/ProjectSettings.xml
msgid ""
@@ -65372,6 +65410,13 @@ msgid ""
"[code]offset[/code], and the character before [code]offset[/code] will be "
"checked for the word boundary [code]\\b[/code]."
msgstr ""
+"在文本中æœç´¢ç¼–译åŽçš„模å¼ã€‚如果找到,则将首个匹é…结果放在 [RegExMatch] 容器中"
+"返回,å¦åˆ™è¿”回 [code]null[/code]。\n"
+"æœç´¢çš„范围å¯ä»¥ç”¨ [code]offset[/code] å’Œ [code]end[/code] 指定。å¯ç”¨äºŽåœ¨ä¸Šä¸€æ¬¡"
+"æˆåŠŸæ‰¾åˆ°åŽå†æ¬¡ä½¿ç”¨ç›¸åŒçš„ [code]subject[/code] 调用这个方法,继续寻找匹é…。设"
+"置这些å‚数和传入缩短åŽçš„字符串是ä¸åŒçš„。例如,起点 [code]^[/code] ä¸ä¼šå— "
+"[code]offset[/code] å½±å“,å•è¯è¾¹ç•Œ [code]\\b[/code] 会检查 [code]offset[/"
+"code] 之å‰çš„字符。"
#: modules/regex/doc_classes/RegEx.xml
msgid ""
@@ -65386,9 +65431,15 @@ msgid ""
"[code]offset[/code], and the character before [code]offset[/code] will be "
"checked for the word boundary [code]\\b[/code]."
msgstr ""
+"在文本中æœç´¢ç¼–译åŽçš„模å¼ã€‚返回 [RegExMatch] 容器的数组,其中包å«çš„是互ä¸é‡å "
+"的匹é…结果。如果没有找到匹é…,则返回空数组。\n"
+"æœç´¢çš„范围å¯ä»¥ç”¨ [code]offset[/code] å’Œ [code]end[/code] 指定。å¯ç”¨äºŽåœ¨ä¸Šä¸€æ¬¡"
+"æˆåŠŸæ‰¾åˆ°åŽå†æ¬¡ä½¿ç”¨ç›¸åŒçš„ [code]subject[/code] 调用这个方法,继续寻找匹é…。设"
+"置这些å‚数和传入缩短åŽçš„字符串是ä¸åŒçš„。例如,起点 [code]^[/code] ä¸ä¼šå— "
+"[code]offset[/code] å½±å“,å•è¯è¾¹ç•Œ [code]\\b[/code] 会检查 [code]offset[/"
+"code] 之å‰çš„字符。"
#: modules/regex/doc_classes/RegEx.xml
-#, fuzzy
msgid ""
"Searches the text for the compiled pattern and replaces it with the "
"specified string. Escapes and backreferences such as [code]$1[/code] and "
@@ -65403,10 +65454,14 @@ msgid ""
"[code]offset[/code], and the character before [code]offset[/code] will be "
"checked for the word boundary [code]\\b[/code]."
msgstr ""
-"æœç´¢æ–‡æœ¬ä¸­çš„编译模å¼ï¼Œå¹¶å°†å…¶æ›¿æ¢ä¸ºæŒ‡å®šçš„字符串。诸如 [code]$1[/code] å’Œ "
+"在文本中æœç´¢ç¼–译åŽçš„模å¼ï¼Œå¹¶å°†å…¶æ›¿æ¢ä¸ºæŒ‡å®šçš„字符串。诸如 [code]$1[/code] å’Œ "
"[code]$name[/code] 等转义和åå‘引用会被展开和解决。默认情况下,åªæœ‰ç¬¬ä¸€ä¸ªå®žä¾‹"
-"被替æ¢ï¼Œä½†å¯ä»¥å¯¹æ‰€æœ‰å®žä¾‹è¿›è¡Œä¿®æ”¹ï¼ˆå…¨å±€æ›¿æ¢ï¼‰ã€‚å¯ä»¥æŒ‡å®šè¦æœç´¢çš„区域,而ä¸éœ€è¦"
-"修改开始和结æŸé”šçš„ä½ç½®ã€‚"
+"被替æ¢ï¼Œä½†å¯ä»¥å¯¹æ‰€æœ‰å®žä¾‹è¿›è¡Œä¿®æ”¹ï¼ˆå…¨å±€æ›¿æ¢ï¼‰ã€‚\n"
+"æœç´¢çš„范围å¯ä»¥ç”¨ [code]offset[/code] å’Œ [code]end[/code] 指定。å¯ç”¨äºŽåœ¨ä¸Šä¸€æ¬¡"
+"æˆåŠŸæ‰¾åˆ°åŽå†æ¬¡ä½¿ç”¨ç›¸åŒçš„ [code]subject[/code] 调用这个方法,继续寻找匹é…。设"
+"置这些å‚数和传入缩短åŽçš„字符串是ä¸åŒçš„。例如,起点 [code]^[/code] ä¸ä¼šå— "
+"[code]offset[/code] å½±å“,å•è¯è¾¹ç•Œ [code]\\b[/code] 会检查 [code]offset[/"
+"code] 之å‰çš„字符。"
#: modules/regex/doc_classes/RegExMatch.xml
msgid "Contains the results of a [RegEx] search."
@@ -65687,7 +65742,7 @@ msgstr ""
"时,这个方法会被调用。它的行为å¯ä»¥é€šè¿‡è¦†ç›–脚本中的 [method "
"_setup_local_to_scene] 进行定制。\n"
"对于大多数资æºï¼Œè¯¥æ–¹æ³•ä¸æ‰§è¡Œä»»ä½•åŸºæœ¬é€»è¾‘。[ViewportTexture] 执行自定义逻辑以"
-"正确设置本地视窗中的代ç†çº¹ç†å’Œæ ‡å¿—。"
+"正确设置本地视å£ä¸­çš„代ç†çº¹ç†å’Œæ ‡å¿—。"
#: doc/classes/Resource.xml
msgid ""
@@ -68854,12 +68909,11 @@ msgid ""
"quality/dynamic_fonts/use_oversampling[/code] in [ProjectSettings]. The "
"property can however be overridden at runtime as needed."
msgstr ""
-"为 [code]true[/code] æ—¶å¯ç”¨å­—体过采样。这æ„味ç€æ ¹æ®è§†çª—的缩放比例ä¸åŒï¼Œ"
-"[DynamicFont] 渲染的大å°ä¼šæ¯”é…置大å°æ›´é«˜æˆ–更低。例如,如果视窗的缩放系数为 "
-"1.5,那么é…置为 14 å·å¤§å°çš„字体将会按照 21 å·å¤§å°æ¸²æŸ“([code]14 * 1.5[/"
-"code])。\n"
-"[b]注æ„:[/b]字体过采样仅在视窗拉伸模å¼ä¸º [constant STRETCH_MODE_VIEWPORT] 且"
-"拉伸比例模å¼ä¸æ˜¯ [constant STRETCH_ASPECT_IGNORE] 时有效。\n"
+"为 [code]true[/code] æ—¶å¯ç”¨å­—体过采样。这æ„味ç€æ ¹æ®è§†å£çš„缩放比例ä¸åŒï¼Œ"
+"[DynamicFont] 渲染的大å°ä¼šæ¯”é…置大å°æ›´é«˜æˆ–更低。例如,视å£çš„缩放系数为 1.5 "
+"时,é…置大å°ä¸º 14 的字体将会当作大å°ä¸º 21 渲染([code]14 * 1.5[/code])。\n"
+"[b]注æ„:[/b]åªæœ‰åœ¨è§†å£æ‹‰ä¼¸æ¨¡å¼ä¸º [constant STRETCH_MODE_VIEWPORT] 且拉伸比例"
+"模å¼ä¸æ˜¯ [constant STRETCH_ASPECT_IGNORE] 时,æ‰ä¼šä½¿ç”¨å­—体过采样。\n"
"[b]注æ„:[/b]项目å¯åŠ¨æ—¶ä¼šä¸ºæ´»åŠ¨çš„ [SceneTree] 自动设置该属性,å–值为 "
"[ProjectSettings] çš„ [code]rendering/quality/dynamic_fonts/use_oversampling[/"
"code]。ä¸è¿‡è¿è¡Œæ—¶å¯ä»¥æ ¹æ®éœ€è¦å¯¹è¯¥å±žæ€§è¿›è¡Œè¦†ç›–。"
@@ -68932,7 +68986,7 @@ msgstr "当节点的é…置更改时å‘出。仅在 [code]tool[/code] 模å¼ä¸‹å
#: doc/classes/SceneTree.xml
msgid "Emitted whenever a node is removed from the [SceneTree]."
-msgstr "当从 [SceneTree] 中删除节点时å‘出。"
+msgstr "当从 [SceneTree] 中移除节点时å‘出。"
#: doc/classes/SceneTree.xml
msgid "Emitted whenever a node is renamed."
@@ -68968,15 +69022,15 @@ msgstr "当 [SceneTree] 层次结构å‘生å˜åŒ–(移动或é‡å‘½åå­é¡¹ç­‰ï¼
#: doc/classes/SceneTree.xml
msgid "Call a group with no flags (default)."
-msgstr "对组进行调用时,ä¸ä½¿ç”¨æ ‡å¿—(默认)。"
+msgstr "对分组进行调用时,ä¸ä½¿ç”¨æ ‡å¿—(默认)。"
#: doc/classes/SceneTree.xml
msgid "Call a group in reverse scene order."
-msgstr "对组进行调用时,使用逆场景åºã€‚"
+msgstr "对分组进行调用时,使用逆场景åºã€‚"
#: doc/classes/SceneTree.xml
msgid "Call a group immediately (calls are normally made on idle)."
-msgstr "对组进行调用时,立å³æ‰§è¡Œï¼ˆæ­£å¸¸æƒ…况下是在空闲时调用的)。"
+msgstr "对分组进行调用时,立å³æ‰§è¡Œï¼ˆæ­£å¸¸æƒ…况下是在空闲时调用的)。"
#: doc/classes/SceneTree.xml
msgid ""
@@ -68985,6 +69039,9 @@ msgid ""
"call is unique or not. Therefore when the same method is called with "
"different arguments, only the first call will be performed."
msgstr ""
+"å³ä¾¿æ‰§è¡Œäº†å¤šæ¬¡è°ƒç”¨ï¼Œä¹Ÿåªå¯¹åˆ†ç»„进行一次调用。\n"
+"[b]注æ„:[/b]确定调用是å¦å”¯ä¸€æ—¶ä¸è€ƒè™‘å‚数。因此,如果使用ä¸åŒçš„å‚数调用了åŒä¸€"
+"个方法,那么åªä¼šæ‰§è¡Œç¬¬ä¸€ä¸ªè°ƒç”¨ã€‚"
#: doc/classes/SceneTree.xml
msgid "No stretching."
@@ -71377,10 +71434,10 @@ msgstr ""
msgid ""
"Rotation part of the local transformation in degrees, specified in terms of "
"YXZ-Euler angles in the format (X angle, Y angle, Z angle)."
-msgstr "旋转部分局部å˜æ¢ä¸ºåº¦ï¼ŒæŒ‰ YXZ-Euler 角格å¼æŒ‡å®šï¼ˆX 角ã€Y 角ã€Z 角)。"
+msgstr ""
+"局部å˜æ¢çš„旋转部分,å•ä½ä¸ºåº¦ï¼Œä»¥ YXZ 欧拉角的形å¼è¡¨ç¤ºï¼ˆX 角ã€Y 角ã€Z 角)。"
#: doc/classes/Spatial.xml
-#, fuzzy
msgid ""
"Scale part of the local transformation.\n"
"[b]Note:[/b] Mixed negative scales in 3D are not decomposable from the "
@@ -71392,7 +71449,9 @@ msgid ""
msgstr ""
"局部å˜æ¢çš„缩放部分。\n"
"[b]注æ„:[/b]3D 中,å˜æ¢çŸ©é˜µæ˜¯æ— æ³•åˆ†è§£å‡ºæ­£è´Ÿæ··åˆçš„缩放的。由于 Godot 中使用å˜"
-"æ¢çŸ©é˜µæ¥è¡¨ç¤ºç¼©æ”¾ï¼Œå¾—到的缩放值è¦ä¹ˆå…¨æ­£ã€è¦ä¹ˆå…¨è´Ÿã€‚"
+"æ¢çŸ©é˜µæ¥è¡¨ç¤ºç¼©æ”¾ï¼Œå¾—到的缩放值è¦ä¹ˆå…¨æ­£ã€è¦ä¹ˆå…¨è´Ÿã€‚\n"
+"[b]注æ„:[/b]并ä¸æ˜¯æ‰€æœ‰èŠ‚点的外观都会被 [member scale] 属性缩放。例如,"
+"[Light] 的外观就ä¸å— [member scale] å½±å“。"
#: doc/classes/Spatial.xml
msgid "Local space [Transform] of this node, with respect to the parent node."
@@ -73038,6 +73097,9 @@ msgid ""
"[b]Note:[/b] [member spot_angle] is not affected by [member Spatial.scale] "
"(the light's scale or its parent's scale)."
msgstr ""
+"èšå…‰ç¯çš„角度,å•ä½ä¸ºåº¦ã€‚\n"
+"[b]注æ„:[/b][member spot_angle] ä¸å— [member Spatial.scale] çš„å½±å“(无论是该"
+"ç¯å…‰çš„缩放还是其父节点的缩放)。"
#: doc/classes/SpotLight.xml
msgid "The spotlight's angular attenuation curve."
@@ -73048,7 +73110,6 @@ msgid "The spotlight's light energy attenuation curve."
msgstr "èšå…‰ç¯çš„å…‰é‡è¡°å‡æ›²çº¿ã€‚"
#: doc/classes/SpotLight.xml
-#, fuzzy
msgid ""
"The maximal range that can be reached by the spotlight. Note that the "
"effectively lit area may appear to be smaller depending on the [member "
@@ -73058,8 +73119,10 @@ msgid ""
"(the light's scale or its parent's scale)."
msgstr ""
"èšå…‰ç¯å¯ä»¥è¾¾åˆ°çš„最大范围。请注æ„,根æ®ä½¿ç”¨çš„ [member spot_attenuation],有效"
-"照明区域å¯èƒ½çœ‹èµ·æ¥æ›´å°ã€‚无论使用[member spot_attenuation],光都ä¸ä¼šåˆ°è¾¾æ­¤èŒƒå›´"
-"之外的任何东西。"
+"照明区域å¯èƒ½çœ‹èµ·æ¥æ›´å°ã€‚无论 [member spot_attenuation] 为何值,光都ä¸ä¼šåˆ°è¾¾æ­¤"
+"范围之外的任何东西。\n"
+"[b]注æ„:[/b][member spot_angle] ä¸å— [member Spatial.scale] çš„å½±å“(无论是该"
+"ç¯å…‰çš„缩放还是其父节点的缩放)。"
#: doc/classes/SpringArm.xml
msgid "A helper node, mostly used in 3rd person cameras."
@@ -76689,7 +76752,7 @@ msgid ""
"Centers the viewport on the line the editing cursor is at. This also resets "
"the [member scroll_horizontal] value to [code]0[/code]."
msgstr ""
-"将视区置于编辑光标所在的行上。这也会将 [member scroll_horizontal] 值é‡ç½®ä¸º "
+"将视å£ç½®äºŽç¼–辑光标所在的行上。这也会将 [member scroll_horizontal] 值é‡ç½®ä¸º "
"[code]0[/code]。"
#: doc/classes/TextEdit.xml
@@ -76723,7 +76786,7 @@ msgid ""
"will center at the cursor position after the move occurs."
msgstr ""
"将光标移动到指定的 [code]column[/code] 索引处。\n"
-"如果 [code]adjust_viewport[/code] 设置为 [code]true[/code],则移动å‘生åŽè§†çª—"
+"如果 [code]adjust_viewport[/code] 设置为 [code]true[/code],则移动å‘生åŽè§†å£"
"将以光标ä½ç½®ä¸ºä¸­å¿ƒã€‚"
#: doc/classes/TextEdit.xml
@@ -76735,7 +76798,7 @@ msgid ""
"[code]line[/code] can be hidden using [method set_line_as_hidden]."
msgstr ""
"在指定的 [code]line[/code] 索引处移动光标。\n"
-"如果 [code]adjust_viewport[/code] 设置为 [code]true[/code],则移动å‘生åŽè§†çª—"
+"如果 [code]adjust_viewport[/code] 设置为 [code]true[/code],则移动å‘生åŽè§†å£"
"将以光标ä½ç½®ä¸ºä¸­å¿ƒã€‚\n"
"如果 [code]can_be_hidden[/code] 设置为 [code]true[/code],则å¯ä»¥ä½¿ç”¨ [method "
"set_line_as_hidden] éšè—指定的 [code]line[/code]。"
@@ -84329,16 +84392,16 @@ msgid ""
"to be upside down. Enabling [member render_target_v_flip] will display the "
"Viewport with the correct orientation."
msgstr ""
-"Viewport 会在å±å¹•ä¸Šåˆ›å»ºä¸åŒçš„视图,或者是å¦ä¸€ä¸ªè§†çª—中的å­è§†å›¾ã€‚å­ä»£ 2D 节点会"
+"Viewport 会在å±å¹•ä¸Šåˆ›å»ºä¸åŒçš„视图,或者是å¦ä¸€ä¸ªè§†å£ä¸­çš„å­è§†å›¾ã€‚å­ä»£ 2D 节点会"
"在其上显示,å­ä»£ 3D æ‘„åƒæœºèŠ‚点也会在其上渲染。\n"
-"å¦å¤–,视窗å¯ä»¥æœ‰è‡ªå·±çš„ 2D 或 3D 世界,所以它们ä¸ä¼šä¸Žå…¶ä»–视窗共享其所绘制的内"
+"å¦å¤–,视å£å¯ä»¥æœ‰è‡ªå·±çš„ 2D 或 3D 世界,所以它们ä¸ä¼šä¸Žå…¶ä»–视å£å…±äº«å…¶æ‰€ç»˜åˆ¶çš„内"
"容。\n"
-"如果视窗是 [ViewportContainer] çš„å­èŠ‚点,它将自动å ç”¨å…¶å¤§å°ï¼Œå¦åˆ™å¿…须手动设"
+"如果视å£æ˜¯ [ViewportContainer] çš„å­èŠ‚点,它将自动å ç”¨å…¶å¤§å°ï¼Œå¦åˆ™å¿…须手动设"
"置。\n"
-"视窗也å¯ä»¥é€‰æ‹©æˆä¸ºéŸ³é¢‘监å¬è€…,会根æ®å®ƒçš„ 2D 或 3D æ‘„åƒæœºçš„å­èŠ‚点æ¥äº§ç”Ÿä½ç½®éŸ³"
+"视å£ä¹Ÿå¯ä»¥é€‰æ‹©æˆä¸ºéŸ³é¢‘监å¬è€…,会根æ®å®ƒçš„ 2D 或 3D æ‘„åƒæœºçš„å­èŠ‚点æ¥äº§ç”Ÿä½ç½®éŸ³"
"频。\n"
-"å¦å¤–,如果设备有多个å±å¹•ï¼Œè§†çª—å¯ä»¥è¢«åˆ†é…到ä¸åŒçš„å±å¹•ã€‚\n"
-"最åŽï¼Œè§†çª—也å¯ä»¥ä½œä¸ºæ¸²æŸ“目标,在这ç§æƒ…况下,除éžç›¸å…³çš„纹ç†è¢«ç”¨äºŽç»˜åˆ¶ï¼Œå¦åˆ™å®ƒ"
+"å¦å¤–,如果设备有多个å±å¹•ï¼Œè§†å£å¯ä»¥è¢«åˆ†é…到ä¸åŒçš„å±å¹•ã€‚\n"
+"最åŽï¼Œè§†å£ä¹Ÿå¯ä»¥ä½œä¸ºæ¸²æŸ“目标,在这ç§æƒ…况下,除éžç›¸å…³çš„纹ç†è¢«ç”¨äºŽç»˜åˆ¶ï¼Œå¦åˆ™å®ƒ"
"们将ä¸å¯è§ã€‚\n"
"[b]注æ„:[/b]默认情况下,Godot 3.x 中新创建的 Viewport 是上下颠倒的。å¯ç”¨ "
"[member render_target_v_flip] å¯ä»¥ä½¿è¯¥ Viewport 使用正确的æœå‘显示。"
@@ -84385,7 +84448,7 @@ msgstr "返回激活的 3D 相机。"
#: doc/classes/Viewport.xml
msgid "Returns the total transform of the viewport."
-msgstr "返回视窗的总的å˜æ¢ã€‚"
+msgstr "返回视å£çš„总的å˜æ¢ã€‚"
#: doc/classes/Viewport.xml
msgid "Returns the topmost modal in the stack."
@@ -84399,7 +84462,7 @@ msgstr "返回该 [Viewport] 中鼠标的ä½ç½®ï¼Œä½¿ç”¨è¯¥ [Viewport] çš„åæ ‡
#: doc/classes/Viewport.xml
msgid "Returns information about the viewport from the rendering pipeline."
-msgstr "返回渲染管é“中关于视窗的信æ¯ã€‚"
+msgstr "返回渲染管é“中关于视å£çš„ä¿¡æ¯ã€‚"
#: doc/classes/Viewport.xml
msgid "Returns the [enum ShadowAtlasQuadrantSubdiv] of the specified quadrant."
@@ -84420,7 +84483,7 @@ msgid ""
"img.flip_y()\n"
"[/codeblock]"
msgstr ""
-"返回该视窗的纹ç†ã€‚\n"
+"返回该视å£çš„纹ç†ã€‚\n"
"[b]注æ„:[/b]由于 OpenGL 的工作方å¼ï¼Œäº§ç”Ÿçš„ [ViewportTexture] 是垂直翻转的。"
"ä½ å¯ä»¥åœ¨ [method Texture.get_data] 的结果上使用 [method Image.flip_y] æ¥å°†å…¶"
"翻转回去,例如:\n"
@@ -84459,7 +84522,7 @@ msgid ""
"Alternative to [constant Node.NOTIFICATION_DRAG_BEGIN] and [constant Node."
"NOTIFICATION_DRAG_END] when you prefer polling the value."
msgstr ""
-"如果该视区目å‰æ­£åœ¨æ‰§è¡Œæ‹–拽æ“作,则返回 [code]true[/code]。\n"
+"如果该视å£ç›®å‰æ­£åœ¨æ‰§è¡Œæ‹–拽æ“作,则返回 [code]true[/code]。\n"
"如果你更倾å‘于对其进行轮询,那么就å¯ä»¥ä½œä¸º [constant Node."
"NOTIFICATION_DRAG_BEGIN] å’Œ [constant Node.NOTIFICATION_DRAG_END] 的替代å“。"
@@ -84540,7 +84603,6 @@ msgstr ""
"全局画布å˜æ¢ã€‚"
#: doc/classes/Viewport.xml
-#, fuzzy
msgid ""
"If [code]true[/code], uses a fast post-processing filter to make banding "
"significantly less visible in 3D. 2D rendering is [i]not[/i] affected by "
@@ -84555,9 +84617,13 @@ msgid ""
"[b]Note:[/b] Only available on the GLES3 backend. [member hdr] must also be "
"[code]true[/code] for debanding to be effective."
msgstr ""
-"如果为 [code]true[/code],则使用一个快速的åŽæœŸå¤„ç†æ»¤æ³¢å™¨ï¼Œä½¿å¸¦çŠ¶çŽ°è±¡æ˜Žæ˜¾å‡"
-"少。在æŸäº›æƒ…况下,去带å¯èƒ½ä¼šå¼•å…¥ç¨å¾®æ˜Žæ˜¾çš„抖动模å¼ã€‚建议åªæœ‰åœ¨å®žé™…需è¦æ—¶æ‰å¯"
-"用去带,因为抖动模å¼ä¼šä½¿æ— æŸåŽ‹ç¼©çš„å±å¹•æˆªå›¾å˜å¤§ã€‚\n"
+"如果为 [code]true[/code],则使用一个快速的åŽæœŸå¤„ç†æ»¤æ³¢å™¨ï¼Œä½¿ 3D 的带状现象明"
+"显å‡å°‘。2D 渲染[i]ä¸å—[/i]去æ¡å¸¦çš„å½±å“ï¼Œé™¤éž [member Environment."
+"background_mode] 为 [constant Environment.BG_CANVAS]。此时 [member usage] 也"
+"必须设为 [constant USAGE_3D]。å¦è¯·å‚阅 [member ProjectSettings.rendering/"
+"quality/filters/use_debanding]。\n"
+"在æŸäº›æƒ…况下,去æ¡å¸¦å¯èƒ½ä¼šå¼•å…¥ç¨å¾®æ˜Žæ˜¾çš„抖动图案。建议åªæœ‰åœ¨å®žé™…需è¦æ—¶æ‰å¯ç”¨"
+"去æ¡å¸¦ï¼Œå› ä¸ºæŠ–动图案会使无æŸåŽ‹ç¼©çš„å±å¹•æˆªå›¾å˜å¤§ã€‚\n"
"[b]注æ„:[/b]仅在 GLES3 åŽç«¯å¯ç”¨ã€‚[member hdr] 也必须是 [code]true[/code] æ‰"
"能使去色带生效。"
@@ -84566,13 +84632,12 @@ msgid "The overlay mode for test rendered geometry in debug purposes."
msgstr "在调试时,用于测试渲染的几何图形的å åŠ æ¨¡å¼ã€‚"
#: doc/classes/Viewport.xml
-#, fuzzy
msgid ""
"If [code]true[/code], the viewport will disable 3D rendering. To actually "
"disable allocation of 3D buffers, set [member usage] instead."
msgstr ""
-"如果为 [code]true[/code],该视å£å°†ç¦ç”¨ 3D 渲染。对于实际ç¦ç”¨ï¼Œä½¿ç”¨ "
-"[code]usage[/code]。"
+"如果为 [code]true[/code],该视å£å°†ç¦ç”¨ 3D 渲染。è¦å®žé™…ç¦ç”¨ 3D 缓冲区的分é…,"
+"请设置 [member usage]。"
#: doc/classes/Viewport.xml
msgid ""
@@ -84616,7 +84681,7 @@ msgid ""
"[b]Note:[/b] Only available on the GLES3 backend."
msgstr ""
"如果为 [code]true[/code],视å£çš„渲染将获益于高动æ€èŒƒå›´ç®—法。高动æ€èŒƒå›´å…许视"
-"窗接收 0-1 范围以外的数值。在 Godot 中 HDR 默认使用åŠç²¾åº¦æµ®ç‚¹æ•°ï¼ˆ16 ä½ï¼‰ã€‚è¦"
+"å£æŽ¥æ”¶ 0-1 范围以外的数值。在 Godot 中 HDR 默认使用åŠç²¾åº¦æµ®ç‚¹æ•°ï¼ˆ16 ä½ï¼‰ã€‚è¦"
"使用全精度浮点数(32 ä½ï¼‰ï¼Œè¯·å¯ç”¨ [member use_32_bpc_depth]。\n"
"[b]注æ„:[/b]需è¦å°† [member usage] 设置为 [constant USAGE_3D] 或 [constant "
"USAGE_3D_NO_EFFECTS],因为 HDR ä¸æ”¯æŒ 2D。\n"
@@ -84635,7 +84700,7 @@ msgid ""
"require input in linear color space!"
msgstr ""
"如果为 [code]true[/code],3D 渲染åŽçš„结果将ä¸ä¼šåº”用线性到 sRGB 的颜色转æ¢ã€‚当"
-"视å£è¢«ç”¨ä½œæ¸²æŸ“目标时,这点很é‡è¦ï¼Œå› ä¸ºæ¸²æŸ“结果会被用作å¦ä¸€ä¸ªè§†çª—中渲染的 3D "
+"视å£è¢«ç”¨ä½œæ¸²æŸ“目标时,这点很é‡è¦ï¼Œå› ä¸ºæ¸²æŸ“结果会被用作å¦ä¸€ä¸ªè§†å£ä¸­æ¸²æŸ“çš„ 3D "
"物体的纹ç†ã€‚如果视å£è¢«ç”¨æ¥åˆ›å»ºä¸åŸºäºŽé¢œè‰²çš„æ•°æ®ï¼Œå™ªå£°ã€é«˜åº¦å›¾ã€é‡‡å›¾ç­‰ï¼Œè¿™ä¹Ÿå¾ˆ"
"é‡è¦ã€‚当视å£è¢«ç”¨ä½œ 2D 对象的纹ç†æ—¶ï¼Œæˆ–者视å£æ˜¯ä½ çš„最终输出时,请ä¸è¦å¯ç”¨è¿™ä¸ª"
"功能。对于 GLES2 驱动æ¥è¯´ï¼Œè¿™å°†æŠŠ sRGB 输出转æ¢ä¸ºçº¿æ€§è¾“出,这应该åªç”¨äºŽéœ€è¦çº¿"
@@ -84725,7 +84790,7 @@ msgid ""
msgstr ""
"阴影图集的分辨率(用于全å‘光和èšå…‰ï¼‰ã€‚该值将四èˆäº”入到最接近的 2 的幂。\n"
"[b]注æ„:[/b]如果设置为 [code]0[/code],点阴影和方å‘阴影[i]都[/i]å°†ä¸å¯è§ã€‚ç”±"
-"于用户创建的视区默认值为 [code]0[/code],因此必须手动将此值设置为大于 "
+"于用户创建的视å£é»˜è®¤å€¼ä¸º [code]0[/code],因此必须手动将此值设置为大于 "
"[code]0[/code](一般至少是 [code]256[/code])。"
#: doc/classes/Viewport.xml
@@ -84736,7 +84801,7 @@ msgid ""
"Values around [code]0.5[/code] generally give the best results. See also "
"[member fxaa]."
msgstr ""
-"如果设置为大于 [code]0.0[/code] 的值,对比度适应性é”化将被应用到3D视窗中。这"
+"如果设置为大于 [code]0.0[/code] 的值,对比度适应性é”化将被应用到3D视å£ä¸­ã€‚è¿™"
"具有较低的性能æˆæœ¬ï¼Œå¯ä»¥ç”¨æ¥æ¢å¤ä½¿ç”¨ FXAA 所æŸå¤±çš„一些é”度。一般æ¥è¯´ï¼Œ"
"[code]0.5[/code] å·¦å³çš„数值å¯ä»¥å¾—到最好的效果。å¦è¯·å‚阅 [member fxaa]。"
@@ -84759,7 +84824,6 @@ msgid ""
msgstr "如果为 [code]true[/code],该视å£åº”使其背景渲染为é€æ˜Žã€‚"
#: doc/classes/Viewport.xml
-#, fuzzy
msgid ""
"The viewport's rendering mode. This controls which buffers are allocated for "
"the viewport (2D only, or 2D + 3D). 2D-only options can reduce memory usage "
@@ -84768,7 +84832,8 @@ msgid ""
"USAGE_2D_NO_SAMPLING], [member hdr] will have no effect when enabled since "
"HDR is not supported for 2D."
msgstr ""
-"视区的渲染模å¼ã€‚\n"
+"该视å£çš„渲染模å¼ã€‚控制的是为该视å£åˆ†é…哪些缓冲区(仅 2D 或者 2D + 3D)。仅 "
+"2D 的选项能够é™ä½Žå†…å­˜å ç”¨ã€ç•¥å¾®æå‡æ€§èƒ½ï¼Œå°¤å…¶æ˜¯åœ¨ä½Žç«¯è®¾å¤‡ä¸Šã€‚\n"
"[b]注æ„:[/b]如果设为 [constant USAGE_2D] 或 [constant "
"USAGE_2D_NO_SAMPLING],则å¯ç”¨ [member hdr] ä¸ä¼šç”Ÿæ•ˆï¼Œå› ä¸º 2D ä¸æ”¯æŒ HDR。"
@@ -84783,7 +84848,7 @@ msgid ""
"enable [member debanding] instead.\n"
"[b]Note:[/b] Only available on the GLES3 backend."
msgstr ""
-"如果为 [code]true[/code],分é…该视窗的帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ"
+"如果为 [code]true[/code],分é…该视å£çš„帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ"
"ä¸æ˜¯åŠæµ®ç‚¹æ•°ç²¾åº¦ï¼ˆ16 ä½ï¼‰ã€‚仅在åŒæ—¶å¯ç”¨ [member hdr] 时有效。\n"
"[b]注æ„:[/b]å¯ç”¨è¿™ä¸ªè®¾ç½®ä¸ä¼šæå‡æ¸²æŸ“è´¨é‡ã€‚使用完整浮点数精度较慢,一般åªæœ‰è¦"
"求更高精度的高级ç€è‰²å™¨éœ€è¦ä½¿ç”¨ã€‚如果是è¦å‡å°‘æ¡å¸¦æ•ˆåº”,请å¯ç”¨ [member "
@@ -85015,7 +85080,7 @@ msgstr ""
#: doc/classes/ViewportContainer.xml
msgid ""
"If [code]true[/code], the viewport will be scaled to the control's size."
-msgstr "为 [code]true[/code] 时视窗将被缩放到控件的大å°ã€‚"
+msgstr "为 [code]true[/code] 时视å£å°†è¢«ç¼©æ”¾åˆ°æŽ§ä»¶çš„大å°ã€‚"
#: doc/classes/ViewportContainer.xml
msgid ""
@@ -85046,7 +85111,7 @@ msgid ""
msgstr ""
"å°† [Viewport] 节点的内容显示为一个动æ€çš„ [Texture]。å¯ä»¥ç”¨æ¥åœ¨åŒä¸€ä¸ªåœºæ™¯ä¸­æ··"
"åˆæŽ§ä»¶ã€2D å’Œ 3D元素。\n"
-"è¦é€šè¿‡ä»£ç åˆ›å»º ViewportTexture,请使用目标视窗上的 [method Viewport."
+"è¦é€šè¿‡ä»£ç åˆ›å»º ViewportTexture,请使用目标视å£ä¸Šçš„ [method Viewport."
"get_texture] 方法。"
#: doc/classes/ViewportTexture.xml
@@ -85402,6 +85467,8 @@ msgid ""
"value will make the [VisualInstance] reliably draw on top of other "
"[VisualInstance]s that are otherwise positioned at the same spot."
msgstr ""
+"这个 [VisualInstance] 所使用的排åºå移é‡ã€‚调高åŽï¼Œè¯¥ [VisualInstance] 会稳定"
+"地绘制在åŒä¸€ä½ç½®çš„其他 [VisualInstance] 之上。"
#: doc/classes/VisualInstance.xml
msgid ""
@@ -85411,6 +85478,10 @@ msgid ""
"The position based sorting instead allows to better control the drawing "
"order when working with [Particles] and [CPUParticles]."
msgstr ""
+"如果为 [code]true[/code],则该对象会根æ®å…¶ [AABB] 中心点排åºã€‚å¦åˆ™ä¼šæ ¹æ®å…¶å…¨"
+"å±€ä½ç½®æŽ’åºã€‚\n"
+"对 3D æ¨¡åž‹è€Œè¨€ï¼Œæ ¹æ® [AABB] 的中心点排åºä¸€èˆ¬æ›´ä¸ºç²¾ç¡®ã€‚使用 [Particles] å’Œ "
+"[CPUParticles] 时,根æ®ä½ç½®æŽ’åºèƒ½å¤Ÿæ›´å¥½åœ°æŽ§åˆ¶ç»˜åˆ¶é¡ºåºã€‚"
#: modules/visual_script/doc_classes/VisualScript.xml
msgid "A script implemented in the Visual Script programming environment."
@@ -87417,10 +87488,10 @@ msgstr ""
"VisualServer 是完全ä¸é€æ˜Žçš„,它的内部结构的完全的具体实现ä¸èƒ½è¢«è®¿é—®ã€‚\n"
"VisualServer å¯ä»¥ç”¨æ¥å®Œå…¨ç»•è¿‡åœºæ™¯ç³»ç»Ÿã€‚\n"
"å¯ä½¿ç”¨ [code]*_create[/code] 函数创建资æºã€‚\n"
-"所有的对象都被绘制到视窗中。你å¯ä»¥ä½¿ç”¨é™„在 [SceneTree] 上的 [Viewport],或者"
+"所有的对象都被绘制到视å£ä¸­ã€‚ä½ å¯ä»¥ä½¿ç”¨é™„在 [SceneTree] 上的 [Viewport],或者"
"用 [method viewport_create] 自己创建一个。当使用自定义场景或画布时,需è¦ä½¿ç”¨ "
"[method viewport_set_scenario] 或 [method viewport_attach_canvas] 将场景或画"
-"布附加到视窗上。\n"
+"布附加到视å£ä¸Šã€‚\n"
"在 3D 中,所有的视觉对象都必须与一个场景相关è”。场景是世界的一个视觉表现。如"
"果从一个正在è¿è¡Œçš„游æˆä¸­è®¿é—®è§†è§‰æœåŠ¡ï¼Œåœºæ™¯å¯ä»¥é€šè¿‡ [method Spatial."
"get_world] 从场景树中的任何 [Spatial] 节点访问。å¦å¤–,å¯ä»¥ç”¨ [method "
@@ -87431,7 +87502,7 @@ msgstr ""
"一个实例。实例也必须使用 [method instance_set_scenario] 附加到场景中,以便å¯"
"è§ã€‚\n"
"在 2D 中,所有å¯è§å¯¹è±¡éƒ½æ˜¯æŸç§å½¢å¼çš„画布项目。为了å¯è§ï¼Œä¸€ä¸ªç”»å¸ƒé¡¹éœ€è¦æ˜¯è¿žæŽ¥"
-"到视窗的画布的å­é¡¹ï¼Œæˆ–者它需è¦æ˜¯æœ€ç»ˆè¿žæŽ¥åˆ°ç”»å¸ƒçš„å¦ä¸€ä¸ªç”»å¸ƒé¡¹çš„å­é¡¹ã€‚"
+"到视å£çš„画布的å­é¡¹ï¼Œæˆ–者它需è¦æ˜¯æœ€ç»ˆè¿žæŽ¥åˆ°ç”»å¸ƒçš„å¦ä¸€ä¸ªç”»å¸ƒé¡¹çš„å­é¡¹ã€‚"
#: doc/classes/VisualServer.xml
msgid "Sets images to be rendered in the window margin."
@@ -87660,7 +87731,7 @@ msgid ""
"Sets the parent for the [CanvasItem]. The parent can be another canvas item, "
"or it can be the root canvas that is attached to the viewport."
msgstr ""
-"设置[CanvasItem]的父级。父级å¯ä»¥æ˜¯å¦ä¸€ä¸ªç”»å¸ƒé¡¹ç›®ï¼Œä¹Ÿå¯ä»¥æ˜¯è¿žæŽ¥åˆ°è§†çª—的根画"
+"设置[CanvasItem]的父级。父级å¯ä»¥æ˜¯å¦ä¸€ä¸ªç”»å¸ƒé¡¹ç›®ï¼Œä¹Ÿå¯ä»¥æ˜¯è¿žæŽ¥åˆ°è§†å£çš„根画"
"布。"
#: doc/classes/VisualServer.xml
@@ -89743,7 +89814,7 @@ msgid ""
"[/codeblock]"
msgstr ""
"在两个纹ç†ä¹‹é—´åˆ›å»ºæ›´æ–°é“¾ï¼Œä¸Ž [ViewportTexture] 的原ç†ç±»ä¼¼ã€‚基础纹ç†ä¸º "
-"[Viewport] 的纹ç†æ—¶ï¼Œè§†åŒºæ¯æ–°æ¸²æŸ“一帧,代ç†çº¹ç†å°±ä¼šè‡ªåŠ¨æ”¶åˆ°æ›´æ–°ã€‚\n"
+"[Viewport] 的纹ç†æ—¶ï¼Œè§†å£æ¯æ–°æ¸²æŸ“一帧,代ç†çº¹ç†å°±ä¼šè‡ªåŠ¨æ”¶åˆ°æ›´æ–°ã€‚\n"
"例如,此处的代ç ä¼šåˆ©ç”¨ VisualServer API 将一张通用的 [ImageTexture] 链接到 "
"[Viewport] 的纹ç†è¾“出上:\n"
"[codeblock]\n"
@@ -89781,7 +89852,7 @@ msgstr "设置视图的相机。"
#: doc/classes/VisualServer.xml
msgid "Sets a viewport's canvas."
-msgstr "设置视窗的画布。"
+msgstr "设置视å£çš„画布。"
#: doc/classes/VisualServer.xml
msgid ""
@@ -89804,18 +89875,18 @@ msgid ""
"manually. For further optimization, see [method "
"viewport_set_render_direct_to_screen]."
msgstr ""
-"将视窗å¤åˆ¶åˆ°å±å¹•ä¸Šç”± [code]rect[/code] 指定的区域。如果 [member Viewport."
-"render_direct_to_screen] 为 [code]true[/code],那么视窗就ä¸ä¼šä½¿ç”¨å¸§ç¼“冲,视窗"
-"的内容会直接渲染到å±å¹•ä¸Šã€‚然而,请注æ„,根视窗是最åŽç»˜åˆ¶çš„,因此它将在å±å¹•ä¸Š"
-"绘制。相应地,你就必须将根视窗设置为一个ä¸è¦†ç›–你所附加的这个视窗的区域。\n"
-"例如,你å¯ä»¥ç”¨ä»¥ä¸‹ä»£ç å°†æ ¹è§†çª—设置为完全ä¸æ¸²æŸ“。\n"
+"将视å£å¤åˆ¶åˆ°å±å¹•ä¸Šç”± [code]rect[/code] 指定的区域。如果 [member Viewport."
+"render_direct_to_screen] 为 [code]true[/code],那么视å£å°±ä¸ä¼šä½¿ç”¨å¸§ç¼“冲,视å£"
+"的内容会直接渲染到å±å¹•ä¸Šã€‚然而,请注æ„,根视å£æ˜¯æœ€åŽç»˜åˆ¶çš„,因此它将在å±å¹•ä¸Š"
+"绘制。相应地,你就必须将根视å£è®¾ç½®ä¸ºä¸€ä¸ªä¸è¦†ç›–你所附加的这个视å£çš„区域。\n"
+"例如,你å¯ä»¥ç”¨ä»¥ä¸‹ä»£ç å°†æ ¹è§†å£è®¾ç½®ä¸ºå®Œå…¨ä¸æ¸²æŸ“。\n"
"[codeblock]\n"
"func _ready():\n"
" get_viewport().set_attach_to_screen_rect(Rect2())\n"
" $Viewport.set_attach_to_screen_rect(Rect2(0, 0, 600, 600))\n"
"[/codeblock]\n"
"使用这个方法å¯ä»¥å¸¦æ¥æ˜Žæ˜¾çš„优化,特别是在低端设备上。然而,它的代价是必须手动"
-"管ç†ä½ çš„视窗。进一步的优化请å‚阅 [method "
+"管ç†ä½ çš„视å£ã€‚进一步的优化请å‚阅 [method "
"viewport_set_render_direct_to_screen]。"
#: doc/classes/VisualServer.xml
@@ -89826,32 +89897,32 @@ msgid ""
"Once finished with your RID, you will want to free the RID using the "
"VisualServer's [method free_rid] static method."
msgstr ""
-"创建一个空视窗并将其添加到 VisualServer 中。å¯ä»¥ç”¨è¿”回的RIDæ¥è®¿é—®å®ƒã€‚这个RID"
+"创建一个空视å£å¹¶å°†å…¶æ·»åŠ åˆ° VisualServer 中。å¯ä»¥ç”¨è¿”回的RIDæ¥è®¿é—®å®ƒã€‚这个RID"
"将用于所有[code]viewport_*[/code] 的VisualServer函数。\n"
"一旦你用完了RID,你è¦ä½¿ç”¨VisualServerçš„[method free_rid]é™æ€æ–¹æ³•é‡Šæ”¾RID。"
#: doc/classes/VisualServer.xml
msgid "Detaches the viewport from the screen."
-msgstr "将视窗从å±å¹•ä¸Šåˆ†ç¦»ã€‚"
+msgstr "将视å£ä»Žå±å¹•ä¸Šåˆ†ç¦»ã€‚"
#: doc/classes/VisualServer.xml
msgid ""
"Returns a viewport's render information. For options, see the [enum "
"ViewportRenderInfo] constants."
-msgstr "返回视窗的渲染信æ¯ã€‚有关选项,请å‚阅 [enum ViewportRenderInfo] 常é‡ã€‚"
+msgstr "返回视å£çš„渲染信æ¯ã€‚有关选项,请å‚阅 [enum ViewportRenderInfo] 常é‡ã€‚"
#: doc/classes/VisualServer.xml
msgid "Returns the viewport's last rendered frame."
-msgstr "返回视窗的最åŽæ¸²æŸ“帧。"
+msgstr "返回视å£çš„最åŽæ¸²æŸ“帧。"
#: doc/classes/VisualServer.xml
msgid "Detaches a viewport from a canvas and vice versa."
-msgstr "从画布分离视窗,å之亦然。"
+msgstr "从画布分离视å£ï¼Œå之亦然。"
#: doc/classes/VisualServer.xml
msgid "If [code]true[/code], sets the viewport active, else sets it inactive."
msgstr ""
-"如果为 [code]true[/code],则将视窗设置为活动状æ€ï¼Œå¦åˆ™å°†å…¶è®¾ç½®ä¸ºéžæ´»åŠ¨çŠ¶æ€ã€‚"
+"如果为 [code]true[/code],则将视å£è®¾ç½®ä¸ºæ´»åŠ¨çŠ¶æ€ï¼Œå¦åˆ™å°†å…¶è®¾ç½®ä¸ºéžæ´»åŠ¨çŠ¶æ€ã€‚"
#: doc/classes/VisualServer.xml
msgid ""
@@ -89859,37 +89930,37 @@ msgid ""
"[code]layer[/code] is the actual canvas layer, while [code]sublayer[/code] "
"specifies the stacking order of the canvas among those in the same layer."
msgstr ""
-"设置视窗画布的堆å é¡ºåºã€‚\n"
+"设置视å£ç”»å¸ƒçš„å †å é¡ºåºã€‚\n"
"[code]layer[/code] 是实际的画布层,而 [code]sublayer[/code] 则指定画布在åŒä¸€"
"层中的堆å é¡ºåºã€‚"
#: doc/classes/VisualServer.xml
msgid "Sets the transformation of a viewport's canvas."
-msgstr "设置视窗画布的å˜æ¢ã€‚"
+msgstr "设置视å£ç”»å¸ƒçš„å˜æ¢ã€‚"
#: doc/classes/VisualServer.xml
msgid ""
"Sets the clear mode of a viewport. See [enum ViewportClearMode] for options."
-msgstr "设置视窗的清除模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportClearMode]。"
+msgstr "设置视å£çš„清除模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportClearMode]。"
#: doc/classes/VisualServer.xml
msgid ""
"Sets the debug draw mode of a viewport. See [enum ViewportDebugDraw] for "
"options."
-msgstr "设置视窗的调试绘图模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportDebugDraw]。"
+msgstr "设置视å£çš„调试绘图模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportDebugDraw]。"
#: doc/classes/VisualServer.xml
msgid "If [code]true[/code], a viewport's 3D rendering is disabled."
-msgstr "如果为 [code]true[/code],则视窗的 3D 渲染将ç¦ç”¨ã€‚"
+msgstr "如果为 [code]true[/code],则视å£çš„ 3D 渲染将ç¦ç”¨ã€‚"
#: doc/classes/VisualServer.xml
msgid ""
"If [code]true[/code], rendering of a viewport's environment is disabled."
-msgstr "如果为 [code]true[/code],则ç¦ç”¨è§†çª—环境的渲染。"
+msgstr "如果为 [code]true[/code],则ç¦ç”¨è§†å£çŽ¯å¢ƒçš„渲染。"
#: doc/classes/VisualServer.xml
msgid "Sets the viewport's global transformation matrix."
-msgstr "设置视窗的全局å˜æ¢çŸ©é˜µã€‚"
+msgstr "设置视å£çš„全局å˜æ¢çŸ©é˜µã€‚"
#: doc/classes/VisualServer.xml
msgid ""
@@ -89898,13 +89969,13 @@ msgid ""
"viewport_set_use_32_bpc_depth].\n"
"[b]Note:[/b] Only available on the GLES3 backend."
msgstr ""
-"如果为 [code]true[/code],该视区会渲染至高动æ€èŒƒå›´ï¼ˆHDR)而ä¸æ˜¯æ ‡å‡†åŠ¨æ€èŒƒå›´"
+"如果为 [code]true[/code],该视å£ä¼šæ¸²æŸ“至高动æ€èŒƒå›´ï¼ˆHDR)而ä¸æ˜¯æ ‡å‡†åŠ¨æ€èŒƒå›´"
"(SDR)。å¦è¯·å‚阅 [method viewport_set_use_32_bpc_depth]。\n"
"[b]注æ„:[/b]仅在 GLES3 åŽç«¯å¯ç”¨ã€‚"
#: doc/classes/VisualServer.xml
msgid "If [code]true[/code], the viewport's canvas is not rendered."
-msgstr "如果为 [code]true[/code],则ä¸æ¸²æŸ“视窗的画布。"
+msgstr "如果为 [code]true[/code],则ä¸æ¸²æŸ“视å£çš„画布。"
#: doc/classes/VisualServer.xml
msgid "Currently unimplemented in Godot 3.x."
@@ -89916,7 +89987,7 @@ msgstr "设置抗锯齿模å¼ã€‚å¯é€‰é¡¹è§ [enum ViewportMSAA]。"
#: doc/classes/VisualServer.xml
msgid "Sets the viewport's parent to another viewport."
-msgstr "设置视窗的父视窗到å¦ä¸€ä¸ªè§†çª—。"
+msgstr "设置视å£çš„父视å£åˆ°å¦ä¸€ä¸ªè§†å£ã€‚"
#: doc/classes/VisualServer.xml
msgid ""
@@ -89933,12 +90004,12 @@ msgid ""
"will be drawn, no automatic scaling is possible, even if your game scene is "
"significantly larger than the window size."
msgstr ""
-"如果为 [code]true[/code],直接将视窗的内容渲染到å±å¹•ä¸Šã€‚è¿™å…许一个低级别的优"
-"化,你å¯ä»¥è·³è¿‡ç»˜åˆ¶è§†çª—到根视窗。虽然这ç§ä¼˜åŒ–å¯ä»¥æ˜¾è‘—æ高速度(特别是在旧设备"
-"上),但它是以牺牲å¯ç”¨æ€§ä¸ºä»£ä»·çš„。当å¯ç”¨è¿™ä¸ªåŠŸèƒ½æ—¶ï¼Œä½ ä¸èƒ½ä»Žè§†çª—或"
+"如果为 [code]true[/code],直接将视å£çš„内容渲染到å±å¹•ä¸Šã€‚è¿™å…许一个低级别的优"
+"化,你å¯ä»¥è·³è¿‡ç»˜åˆ¶è§†å£åˆ°æ ¹è§†å£ã€‚虽然这ç§ä¼˜åŒ–å¯ä»¥æ˜¾è‘—æ高速度(特别是在旧设备"
+"上),但它是以牺牲å¯ç”¨æ€§ä¸ºä»£ä»·çš„。当å¯ç”¨è¿™ä¸ªåŠŸèƒ½æ—¶ï¼Œä½ ä¸èƒ½ä»Žè§†å£æˆ–"
"[code]SCREEN_TEXTURE[/code]中读å–。你也会失去æŸäº›çª—å£è®¾ç½®çš„好处,比如å„ç§æ‹‰ä¼¸"
"模å¼ã€‚å¦ä¸€ä¸ªéœ€è¦æ³¨æ„çš„åŽæžœæ˜¯ï¼Œåœ¨2D中,渲染是以窗å£å标进行的,所以如果你有一"
-"个两å€äºŽçª—å£å¤§å°çš„视窗,并且你设置了这个,那么åªæœ‰é€‚åˆçª—å£çš„部分æ‰ä¼šè¢«ç»˜åˆ¶ï¼Œ"
+"个两å€äºŽçª—å£å¤§å°çš„视å£ï¼Œå¹¶ä¸”你设置了这个,那么åªæœ‰é€‚åˆçª—å£çš„部分æ‰ä¼šè¢«ç»˜åˆ¶ï¼Œ"
"没有自动缩放的å¯èƒ½ï¼Œå³ä½¿ä½ çš„游æˆåœºæ™¯æ˜Žæ˜¾å¤§äºŽçª—å£å¤§å°ã€‚"
#: doc/classes/VisualServer.xml
@@ -89947,7 +90018,7 @@ msgid ""
"The scenario contains information about the [enum ScenarioDebugMode], "
"environment information, reflection atlas etc."
msgstr ""
-"设置一个视窗的场景。\n"
+"设置视å£çš„场景。\n"
"åœºæ™¯åŒ…å« [enum ScenarioDebugMode] çš„ä¿¡æ¯ã€çŽ¯å¢ƒä¿¡æ¯ã€å射图集等。"
#: doc/classes/VisualServer.xml
@@ -89971,31 +90042,31 @@ msgid ""
"[code]0.5[/code] generally give the best results. See also [method "
"viewport_set_use_fxaa]."
msgstr ""
-"为视窗[code]viewport[/code]设定é”化强度[code]intensity[/code]。如果设置为大于"
-"[code]0.0[/code]的值,对比度适应性é”化将被应用到3D视窗中。这具有较低的性能æˆ"
+"为视å£[code]viewport[/code]设定é”化强度[code]intensity[/code]。如果设置为大于"
+"[code]0.0[/code]的值,对比度适应性é”化将被应用到3D视å£ä¸­ã€‚这具有较低的性能æˆ"
"本,å¯ä»¥ç”¨æ¥æ¢å¤ä½¿ç”¨FXAAæ—¶æŸå¤±çš„一些é”度。一般æ¥è¯´ï¼Œ[code]0.5[/code]å·¦å³çš„值"
"å¯ä»¥å¾—到最好的效果。å‚阅[method viewport_set_use_fxaa]。"
#: doc/classes/VisualServer.xml
msgid "Sets the viewport's width and height."
-msgstr "设置视窗的宽度和高度。"
+msgstr "设置视å£çš„宽度和高度。"
#: doc/classes/VisualServer.xml
msgid ""
"If [code]true[/code], the viewport renders its background as transparent."
-msgstr "如果为 [code]true[/code],视窗将其背景渲染为é€æ˜Žã€‚"
+msgstr "如果为 [code]true[/code],视å£å°†å…¶èƒŒæ™¯æ¸²æŸ“为é€æ˜Žã€‚"
#: doc/classes/VisualServer.xml
msgid ""
"Sets when the viewport should be updated. See [enum ViewportUpdateMode] "
"constants for options."
-msgstr "设置应更新视窗的时间。å¯é€‰é¡¹è¯·å‚阅 [enum ViewportUpdateMode] 。"
+msgstr "设置应更新视å£çš„时间。å¯é€‰é¡¹è¯·å‚阅 [enum ViewportUpdateMode] 。"
#: doc/classes/VisualServer.xml
msgid ""
"Sets the viewport's 2D/3D mode. See [enum ViewportUsage] constants for "
"options."
-msgstr "设置视窗的 2D/3D 模å¼ã€‚é€‰é¡¹è§ [enum ViewportUsage] 常é‡ã€‚"
+msgstr "设置视å£çš„ 2D/3D 模å¼ã€‚é€‰é¡¹è§ [enum ViewportUsage] 常é‡ã€‚"
#: doc/classes/VisualServer.xml
msgid ""
@@ -90005,7 +90076,7 @@ msgid ""
"on the same [Viewport] to set HDR to [code]true[/code].\n"
"[b]Note:[/b] Only available on the GLES3 backend."
msgstr ""
-"如果为 [code]true[/code],分é…该视区的帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ"
+"如果为 [code]true[/code],分é…该视å£çš„帧缓冲时将使用完整浮点数精度(32 ä½ï¼‰è€Œ"
"ä¸æ˜¯åŠæµ®ç‚¹æ•°ç²¾åº¦ï¼ˆ16 ä½ï¼‰ã€‚åªæœ‰åœ¨åŒä¸€ä¸ª [Viewport] 上通过 [method "
"viewport_set_use_32_bpc_depth] 将 HDR 设为 [code]true[/code] 时有效。\n"
"[b]注æ„:[/b]仅在 GLES3 åŽç«¯ä¸­å¯ç”¨ã€‚"
@@ -90015,7 +90086,7 @@ msgid ""
"If [code]true[/code], the viewport uses augmented or virtual reality "
"technologies. See [ARVRInterface]."
msgstr ""
-"如果为 [code]true[/code]ï¼Œåˆ™è§†çª—ä½¿ç”¨å¢žå¼ºæˆ–è™šæ‹ŸçŽ°å®žæŠ€æœ¯ã€‚è§ [ARVRInterface]。"
+"如果为 [code]true[/code],则视å£ä½¿ç”¨å¢žå¼ºæˆ–è™šæ‹ŸçŽ°å®žæŠ€æœ¯ã€‚è§ [ARVRInterface]。"
#: doc/classes/VisualServer.xml
msgid ""
@@ -90042,14 +90113,14 @@ msgid ""
"recovered by enabling contrast-adaptive sharpening (see [method "
"viewport_set_sharpen_intensity])."
msgstr ""
-"å¯ç”¨è¯¥è§†çª—的快速近似抗锯齿。FXAA 是一ç§æµè¡Œçš„å±å¹•ç©ºé—´æŠ—锯齿方法,它速度快,但"
+"å¯ç”¨è¯¥è§†å£çš„快速近似抗锯齿。FXAA 是一ç§æµè¡Œçš„å±å¹•ç©ºé—´æŠ—锯齿方法,它速度快,但"
"会使图åƒçœ‹èµ·æ¥å¾ˆæ¨¡ç³Šï¼Œç‰¹åˆ«æ˜¯åœ¨ä½Žåˆ†è¾¨çŽ‡ä¸‹ã€‚在 1440p å’Œ 4K 等高分辨率下,它ä»ç„¶"
"å¯ä»¥å·¥ä½œå¾—比较好。一些æŸå¤±çš„é”度å¯ä»¥é€šè¿‡å¯ç”¨å¯¹æ¯”度适应性é”化æ¥æ¢å¤ï¼ˆè§ "
"[method viewport_set_sharpen_intensity])。"
#: doc/classes/VisualServer.xml
msgid "If [code]true[/code], the viewport's rendering is flipped vertically."
-msgstr "如果为 [code]true[/code],则视窗的渲染垂直翻转。"
+msgstr "如果为 [code]true[/code],则视å£çš„渲染垂直翻转。"
#: doc/classes/VisualServer.xml
msgid ""
@@ -90440,33 +90511,33 @@ msgstr "优化阴影贴图的使用,æ高有效分辨率。但å¯èƒ½ä¼šå¯¼è‡´
#: doc/classes/VisualServer.xml
msgid "Do not update the viewport."
-msgstr "ä¸è¦æ›´æ–°è§†çª—。"
+msgstr "ä¸è¦æ›´æ–°è§†å£ã€‚"
#: doc/classes/VisualServer.xml
msgid "Update the viewport once then set to disabled."
-msgstr "更新一次视窗,然åŽè®¾ç½®ä¸ºç¦ç”¨ã€‚"
+msgstr "更新一次视å£ï¼Œç„¶åŽè®¾ç½®ä¸ºç¦ç”¨ã€‚"
#: doc/classes/VisualServer.xml
msgid "Update the viewport whenever it is visible."
-msgstr "åªè¦è§†çª—是å¯è§çš„,就更新视窗。"
+msgstr "åªè¦è§†å£æ˜¯å¯è§çš„,就更新视å£ã€‚"
#: doc/classes/VisualServer.xml
msgid "Always update the viewport."
-msgstr "始终更新视窗。"
+msgstr "始终更新视å£ã€‚"
#: doc/classes/VisualServer.xml
msgid "The viewport is always cleared before drawing."
-msgstr "在绘图之å‰ï¼Œè§†çª—总是被清空。"
+msgstr "在绘图之å‰ï¼Œè§†å£æ€»æ˜¯è¢«æ¸…空。"
#: doc/classes/VisualServer.xml
msgid "The viewport is never cleared before drawing."
-msgstr "在绘图之å‰ï¼Œè§†çª—永远ä¸ä¼šè¢«æ¸…空。"
+msgstr "在绘图之å‰ï¼Œè§†å£æ°¸è¿œä¸ä¼šè¢«æ¸…空。"
#: doc/classes/VisualServer.xml
msgid ""
"The viewport is cleared once, then the clear mode is set to [constant "
"VIEWPORT_CLEAR_NEVER]."
-msgstr "视窗被清除一次,然åŽæ¸…除模å¼è®¾ç½®ä¸º [constant VIEWPORT_CLEAR_NEVER]。"
+msgstr "视å£è¢«æ¸…除一次,然åŽæ¸…除模å¼è®¾ç½®ä¸º [constant VIEWPORT_CLEAR_NEVER]。"
#: doc/classes/VisualServer.xml
msgid "Multisample antialiasing is disabled."
@@ -92375,7 +92446,7 @@ msgstr "使用给定的纹ç†ä½œä¸ºæ­¤å‡½æ•°çš„å‚数。"
#: doc/classes/VisualShaderNodeTexture.xml
msgid "Use the current viewport's texture as the source."
-msgstr "使用当å‰è§†çª—的纹ç†ä½œä¸ºæºã€‚"
+msgstr "使用当å‰è§†å£çš„纹ç†ä½œä¸ºæºã€‚"
#: doc/classes/VisualShaderNodeTexture.xml
msgid ""
diff --git a/doc/translations/zh_TW.po b/doc/translations/zh_TW.po
index a64bd25054..a21d110c05 100644
--- a/doc/translations/zh_TW.po
+++ b/doc/translations/zh_TW.po
@@ -15,12 +15,14 @@
# Otis Kao <momoslim@gmail.com>, 2022.
# YuChiang Chang <chiang.c.tw@gmail.com>, 2022.
# Hugel <qihu@nfschina.com>, 2022.
+# Chih Wei Chien <dppss92132@gmail.com>, 2022.
+# Edison Lee <edisonlee@edisonlee55.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine class reference\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-10-12 06:50+0000\n"
-"Last-Translator: BinotaLIU <me@binota.org>\n"
+"PO-Revision-Date: 2023-01-15 03:49+0000\n"
+"Last-Translator: Edison Lee <edisonlee@edisonlee55.com>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot-class-reference/zh_Hant/>\n"
"Language: zh_TW\n"
@@ -28,7 +30,7 @@ msgstr ""
"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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: doc/tools/make_rst.py
msgid "Description"
@@ -84,7 +86,7 @@ msgstr "繼承自:"
#: doc/tools/make_rst.py
msgid "(overrides %s)"
-msgstr ""
+msgstr "(覆寫 %s)"
#: doc/tools/make_rst.py
msgid "Default"
@@ -126,13 +128,13 @@ msgstr "此方法用於建構型別。"
msgid ""
"This method doesn't need an instance to be called, so it can be called "
"directly using the class name."
-msgstr ""
+msgstr "該方法ä¸éœ€è¦ä½¿ç”¨ä¸€å€‹å¯¦é«”來呼å«ï¼Œæ‰€ä»¥ä»–å¯ä»¥ç›´æŽ¥ä½¿ç”¨ class name 呼å«ã€‚"
#: doc/tools/make_rst.py
msgid ""
"This method describes a valid operator to use with this type as left-hand "
"operand."
-msgstr ""
+msgstr "該方法æ述一個有效的é‹ç®—å­ä½¿ç”¨æ­¤åž‹åˆ¥ä½œç‚ºå·¦é‹ç®—值。"
#: modules/gdscript/doc_classes/@GDScript.xml
msgid "Built-in GDScript functions."
@@ -148,7 +150,6 @@ msgstr ""
"供。 (é—œéµå­—:內建ã€å…¨åŸŸå‡½å¼ã€buildinã€build inã€global functions)"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns a color constructed from integer red, green, blue, and alpha "
"channels. Each channel should have 8 bits of information ranging from 0 to "
@@ -161,12 +162,12 @@ msgid ""
"red = Color8(255, 0, 0)\n"
"[/codeblock]"
msgstr ""
-"回傳以整數紅色ã€ç¶ è‰²ã€è—色與 Alpha 通é“構æˆçš„色彩。æ¯å€‹é€šé“éƒ½æ‡‰åŒ…å« 0 至 255 "
-"çš„ 8 ä½å…ƒè³‡è¨Šã€‚\n"
+"回傳以整數紅色ã€ç¶ è‰²ã€è—色與é€æ˜Žé€šé“構æˆçš„色彩。æ¯å€‹é€šé“éƒ½æ‡‰åŒ…å« 0 至 255 çš„ "
+"8 ä½å…ƒè³‡è¨Šã€‚\n"
"[code]r8[/code] 紅色通é“\n"
"[code]g8[/code] 綠色通é“\n"
"[code]b8[/code] è—色通é“\n"
-"[code]a8[/code] Alpha 通é“\n"
+"[code]a8[/code] é€æ˜Žé€šé“\n"
"[codeblock]\n"
"red = Color8(255, 0, 0)\n"
"[/codeblock]"
@@ -201,7 +202,6 @@ msgstr ""
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns the arc cosine of [code]s[/code] in radians. Use to get the angle of "
"cosine [code]s[/code]. [code]s[/code] must be between [code]-1.0[/code] and "
@@ -212,15 +212,15 @@ msgid ""
"c = acos(0.866025)\n"
"[/codeblock]"
msgstr ""
-"回傳以弧度表示的[code]s[/code]çš„å餘弦(cos)值。用於求餘弦(sin)值[code]s[/"
-"code]的夾角。\n"
+"回傳以弧度表示的[code]s[/code]çš„å餘弦(arc cos)值。用於求餘弦(cos)值[code]s[/"
+"code]的夾角。[code]s[/code]必須介於[code]-1.0[/code]與[code]1.0[/code]之間 "
+"(包å«),å¦å‰‡ [method acos] 會回傳 [constant NAN]。\n"
"[codeblock]\n"
-"# c 為0.523599,若以rad2deg(s)æ›ç®—,則為30度\n"
+"# c 為 0.523599,若以 rad2deg(s) æ›ç®—,則為30度\n"
"c = acos(0.866025)\n"
"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
-#, fuzzy
msgid ""
"Returns the arc sine of [code]s[/code] in radians. Use to get the angle of "
"sine [code]s[/code]. [code]s[/code] must be between [code]-1.0[/code] and "
@@ -230,7 +230,14 @@ msgid ""
"# s is 0.523599 or 30 degrees if converted with rad2deg(s)\n"
"s = asin(0.5)\n"
"[/codeblock]"
-msgstr "testing"
+msgstr ""
+"回傳以弧度表示的[code]s[/code]çš„å正弦(arc sin)值。用於求正弦 (sin) 值"
+"[code]s[/code]的夾角。[code]s[/code]必須介於[code]-1.0[/code]與[code]1.0[/"
+"code]之間 (包å«),å¦å‰‡ [method asin] 會回傳 [constant NAN]。\n"
+"[codeblock]\n"
+"# c 為 0.523599,若以 rad2deg(s) æ›ç®—,則為 30 度\n"
+"c = asin(0.5)\n"
+"[/codeblock]"
#: modules/gdscript/doc_classes/@GDScript.xml
#, fuzzy
@@ -30066,7 +30073,11 @@ msgid ""
"using an [AnimatedTexture], only the first frame will be displayed.\n"
"[b]Note:[/b] Only images imported with the [b]Lossless[/b], [b]Lossy[/b] or "
"[b]Uncompressed[/b] compression modes are supported. The [b]Video RAM[/b] "
-"compression mode can't be used for custom cursors."
+"compression mode can't be used for custom cursors.\n"
+"[b]Note:[/b] On the web platform, the maximum allowed cursor image size is "
+"128×128. Cursor images larger than 32×32 will also only be displayed if the "
+"mouse cursor image is entirely located within the page for [url=https://"
+"chromestatus.com/feature/5825971391299584]security reasons[/url]."
msgstr ""
#: doc/classes/Input.xml
@@ -41853,7 +41864,7 @@ msgstr ""
#: doc/classes/OS.xml
msgid "Desktop directory path."
-msgstr ""
+msgstr "æ¡Œé¢è³‡æ–™å¤¾è·¯å¾‘。"
#: doc/classes/OS.xml
msgid "DCIM (Digital Camera Images) directory path."
@@ -41861,27 +41872,27 @@ msgstr ""
#: doc/classes/OS.xml
msgid "Documents directory path."
-msgstr ""
+msgstr "檔案資料夾路徑。"
#: doc/classes/OS.xml
msgid "Downloads directory path."
-msgstr ""
+msgstr "下載資料夾路徑。"
#: doc/classes/OS.xml
msgid "Movies directory path."
-msgstr ""
+msgstr "影片資料夾路徑。"
#: doc/classes/OS.xml
msgid "Music directory path."
-msgstr ""
+msgstr "音樂資料夾路徑。"
#: doc/classes/OS.xml
msgid "Pictures directory path."
-msgstr ""
+msgstr "圖片資料夾路徑。"
#: doc/classes/OS.xml
msgid "Ringtones directory path."
-msgstr ""
+msgstr "鈴è²è³‡æ–™å¤¾è·¯å¾‘。"
#: doc/classes/OS.xml
msgid "Unknown powerstate."
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 2887b6b44f..89b1c1889e 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -803,7 +803,7 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
light_count++;
- if (light_count == data.max_lights_per_item) {
+ if (light_count == data.max_lights_per_item - 1) {
break;
}
}
@@ -905,10 +905,12 @@ void RasterizerCanvasGLES3::_record_item_commands(const Item *p_item, RID p_rend
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
+ state.instance_data_array[r_index].flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
+ state.instance_data_array[r_index].flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
@@ -2652,8 +2654,10 @@ RasterizerCanvasGLES3::RasterizerCanvasGLES3() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a > 0.0001) {
c.rgb /= c.a;
@@ -2677,8 +2681,10 @@ void fragment() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
COLOR.rgb = c.rgb;
}
)");
diff --git a/drivers/gles3/rasterizer_canvas_gles3.h b/drivers/gles3/rasterizer_canvas_gles3.h
index db9203b249..916e12057c 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.h
+++ b/drivers/gles3/rasterizer_canvas_gles3.h
@@ -75,6 +75,9 @@ class RasterizerCanvasGLES3 : public RendererCanvasRender {
FLAGS_USE_MSDF = (1 << 28),
FLAGS_USE_LCD = (1 << 29),
+
+ FLAGS_FLIP_H = (1 << 30),
+ FLAGS_FLIP_V = (1 << 31),
};
enum {
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index e4bcc424b3..9547435607 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -1535,8 +1535,6 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
}
}
- li->gl_id = r_omni_light_count;
-
scene_state.omni_light_sort[r_omni_light_count].instance = li;
scene_state.omni_light_sort[r_omni_light_count].depth = distance;
r_omni_light_count++;
@@ -1560,8 +1558,6 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
}
}
- li->gl_id = r_spot_light_count;
-
scene_state.spot_light_sort[r_spot_light_count].instance = li;
scene_state.spot_light_sort[r_spot_light_count].depth = distance;
r_spot_light_count++;
@@ -1584,8 +1580,11 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
LightData &light_data = (i < r_omni_light_count) ? scene_state.omni_lights[index] : scene_state.spot_lights[index];
RS::LightType type = (i < r_omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
GLES3::LightInstance *li = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].instance : scene_state.spot_light_sort[index].instance;
+ real_t distance = (i < r_omni_light_count) ? scene_state.omni_light_sort[index].depth : scene_state.spot_light_sort[index].depth;
RID base = li->light;
+ li->gl_id = index;
+
Transform3D light_transform = li->transform;
Vector3 pos = inverse_transform.xform(light_transform.origin);
@@ -1612,13 +1611,11 @@ void RasterizerSceneGLES3::_setup_lights(const RenderDataGLES3 *p_render_data, b
// Reuse fade begin, fade length and distance for shadow LOD determination later.
float fade_begin = 0.0;
float fade_length = 0.0;
- real_t distance = 0.0;
float fade = 1.0;
if (light_storage->light_is_distance_fade_enabled(li->light)) {
fade_begin = light_storage->light_get_distance_fade_begin(li->light);
fade_length = light_storage->light_get_distance_fade_length(li->light);
- distance = p_render_data->cam_transform.origin.distance_to(li->transform.origin);
if (distance > fade_begin) {
// Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index 9a90f33674..1631c65385 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -277,7 +277,7 @@ flat in uvec4 varying_G;
uniform sampler2D atlas_texture; //texunit:-2
uniform sampler2D shadow_atlas_texture; //texunit:-3
#endif // DISABLE_LIGHTING
-uniform sampler2D screen_texture; //texunit:-4
+uniform sampler2D color_buffer; //texunit:-4
uniform sampler2D sdf_texture; //texunit:-5
uniform sampler2D normal_texture; //texunit:-6
uniform sampler2D specular_texture; //texunit:-7
@@ -579,6 +579,12 @@ void main() {
if (normal_used || (using_light && bool(read_draw_data_flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(normal_texture, uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
+ if (bool(read_draw_data_flags & FLAGS_FLIP_H)) {
+ normal.x = -normal.x;
+ }
+ if (bool(read_draw_data_flags & FLAGS_FLIP_V)) {
+ normal.y = -normal.y;
+ }
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
} else {
diff --git a/drivers/gles3/shaders/canvas_uniforms_inc.glsl b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
index f65558f042..d53c0fcb26 100644
--- a/drivers/gles3/shaders/canvas_uniforms_inc.glsl
+++ b/drivers/gles3/shaders/canvas_uniforms_inc.glsl
@@ -27,6 +27,9 @@
#define FLAGS_USE_MSDF uint(1 << 28)
#define FLAGS_USE_LCD uint(1 << 29)
+#define FLAGS_FLIP_H uint(1 << 30)
+#define FLAGS_FLIP_V uint(1 << 31)
+
layout(std140) uniform GlobalShaderUniformData { //ubo:1
vec4 global_shader_uniforms[MAX_GLOBAL_SHADER_UNIFORMS];
};
diff --git a/drivers/gles3/shaders/scene.glsl b/drivers/gles3/shaders/scene.glsl
index 1b922fa726..951155e287 100644
--- a/drivers/gles3/shaders/scene.glsl
+++ b/drivers/gles3/shaders/scene.glsl
@@ -564,10 +564,10 @@ uniform highp samplerCubeShadow positional_shadow; // texunit:-4
#ifdef USE_MULTIVIEW
uniform highp sampler2DArray depth_buffer; // texunit:-6
-uniform highp sampler2DArray screen_texture; // texunit:-5
+uniform highp sampler2DArray color_buffer; // texunit:-5
#else
uniform highp sampler2D depth_buffer; // texunit:-6
-uniform highp sampler2D screen_texture; // texunit:-5
+uniform highp sampler2D color_buffer; // texunit:-5
#endif
uniform highp mat4 world_transform;
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index e54fad1551..50e5c868d3 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1515,7 +1515,6 @@ MaterialStorage::MaterialStorage() {
actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "screen_texture";
actions.renames["SCREEN_PIXEL_SIZE"] = "screen_pixel_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["POINT_COORD"] = "gl_PointCoord";
@@ -1536,7 +1535,6 @@ MaterialStorage::MaterialStorage() {
actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf";
actions.usage_defines["COLOR"] = "#define COLOR_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["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
@@ -1617,9 +1615,6 @@ MaterialStorage::MaterialStorage() {
actions.renames["POINT_COORD"] = "gl_PointCoord";
actions.renames["INSTANCE_CUSTOM"] = "instance_custom";
actions.renames["SCREEN_UV"] = "screen_uv";
- //actions.renames["SCREEN_TEXTURE"] = "color_buffer"; //Not implemented in 3D yet.
- //actions.renames["DEPTH_TEXTURE"] = "depth_buffer"; // Not implemented in 3D yet.
- //actions.renames["NORMAL_ROUGHNESS_TEXTURE"] = "normal_roughness_buffer"; // Not implemented in 3D yet
actions.renames["DEPTH"] = "gl_FragDepth";
actions.renames["OUTPUT_IS_SRGB"] = "true";
actions.renames["FOG"] = "fog";
@@ -1684,7 +1679,6 @@ MaterialStorage::MaterialStorage() {
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";
@@ -2765,6 +2759,14 @@ void MaterialStorage::material_free(RID p_rid) {
Material *material = material_owner.get_or_null(p_rid);
ERR_FAIL_COND(!material);
+ // Need to clear texture arrays to prevent spin locking of their RID's.
+ // This happens when the app is being closed.
+ for (KeyValue<StringName, Variant> &E : material->params) {
+ if (E.value.get_type() == Variant::ARRAY) {
+ Array(E.value).clear();
+ }
+ }
+
material_set_shader(p_rid, RID()); //clean up shader
material->dependency.deleted_notify(p_rid);
@@ -2952,7 +2954,6 @@ void CanvasShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_modei, BLEND_MODE_PMALPHA);
actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_modei, BLEND_MODE_DISABLED);
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
actions.usage_flag_pointers["TIME"] = &uses_time;
@@ -2966,6 +2967,7 @@ void CanvasShaderData::set_code(const String &p_code) {
blend_mode = BlendMode(blend_modei);
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
#if 0
print_line("**compiling shader:");
@@ -3301,9 +3303,6 @@ void SceneShaderData::set_code(const String &p_code) {
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;
@@ -3356,6 +3355,9 @@ void SceneShaderData::set_code(const String &p_code) {
vertex_input_mask |= uses_bones << 9;
vertex_input_mask |= uses_weights << 10;
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
+ uses_depth_texture = gen_code.uses_depth_texture;
+ uses_normal_texture = gen_code.uses_normal_roughness_texture;
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.cpp b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
index 65c4ca6131..19bf57df94 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.cpp
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.cpp
@@ -37,13 +37,14 @@ RenderSceneBuffersGLES3::~RenderSceneBuffersGLES3() {
free_render_buffer_data();
}
-void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+void RenderSceneBuffersGLES3::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
//internal_size.x = p_internal_size.x; // ignore for now
//internal_size.y = p_internal_size.y;
width = p_target_size.x;
height = p_target_size.y;
+ //scaling_3d_mode = p_scaling_3d_mode
//fsr_sharpness = p_fsr_sharpness;
//texture_mipmap_bias = p_texture_mipmap_bias;
render_target = p_render_target;
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index 52a7737910..d07a0812f6 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -81,7 +81,7 @@ public:
private:
public:
virtual ~RenderSceneBuffersGLES3();
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
virtual void set_fsr_sharpness(float p_fsr_sharpness) override{};
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override{};
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index 489c328f64..12def52d50 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -567,23 +567,29 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
}
} break;
case Image::FORMAT_ETC2_RA_AS_RG: {
+#ifndef WEB_ENABLED
if (config->etc2_supported) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA8_ETC2_EAC;
r_gl_format = GL_RGBA;
r_gl_type = GL_UNSIGNED_BYTE;
r_compressed = true;
- } else {
+ } else
+#endif
+ {
need_decompress = true;
}
decompress_ra_to_rg = true;
} break;
case Image::FORMAT_DXT5_RA_AS_RG: {
+#ifndef WEB_ENABLED
if (config->s3tc_supported) {
r_gl_internal_format = _EXT_COMPRESSED_RGBA_S3TC_DXT5_EXT;
r_gl_format = GL_RGBA;
r_gl_type = GL_UNSIGNED_BYTE;
r_compressed = true;
- } else {
+ } else
+#endif
+ {
need_decompress = true;
}
decompress_ra_to_rg = true;
@@ -1137,6 +1143,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
texture->gl_set_filter(RS::CANVAS_ITEM_TEXTURE_FILTER_NEAREST);
texture->gl_set_repeat(RS::CANVAS_ITEM_TEXTURE_REPEAT_ENABLED);
+#ifndef WEB_ENABLED
switch (texture->format) {
#ifdef GLES_OVER_GL
case Image::FORMAT_L8: {
@@ -1151,7 +1158,8 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
} break;
-#endif
+#endif // GLES3_OVER_GL
+
case Image::FORMAT_ETC2_RA_AS_RG:
case Image::FORMAT_DXT5_RA_AS_RG: {
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
@@ -1172,6 +1180,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
} break;
}
+#endif // WEB_ENABLED
int mipmaps = img->has_mipmaps() ? img->get_mipmap_count() + 1 : 1;
@@ -1525,18 +1534,6 @@ AABB TextureStorage::decal_get_aabb(RID p_decal) const {
return AABB();
}
-/* DECAL INSTANCE API */
-
-RID TextureStorage::decal_instance_create(RID p_decal) {
- return RID();
-}
-
-void TextureStorage::decal_instance_free(RID p_decal_instance) {
-}
-
-void TextureStorage::decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) {
-}
-
/* RENDER TARGET API */
GLuint TextureStorage::system_fbo = 0;
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index 9ffe16fd16..9d3f407226 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -561,9 +561,10 @@ public:
/* DECAL INSTANCE */
- virtual RID decal_instance_create(RID p_decal) override;
- virtual void decal_instance_free(RID p_decal_instance) override;
- virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override;
+ virtual RID decal_instance_create(RID p_decal) override { return RID(); }
+ virtual void decal_instance_free(RID p_decal_instance) override {}
+ virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
+ virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override {}
/* RENDER TARGET API */
diff --git a/drivers/unix/dir_access_unix.cpp b/drivers/unix/dir_access_unix.cpp
index 557060c907..a162f46103 100644
--- a/drivers/unix/dir_access_unix.cpp
+++ b/drivers/unix/dir_access_unix.cpp
@@ -189,7 +189,7 @@ void DirAccessUnix::list_dir_end() {
_cisdir = false;
}
-#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
+#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED)
static bool _filter_drive(struct mntent *mnt) {
// Ignore devices that don't point to /dev
if (strncmp(mnt->mnt_fsname, "/dev", 4) != 0) {
@@ -213,7 +213,7 @@ static void _get_drives(List<String> *list) {
// Add root.
list->push_back("/");
-#if defined(HAVE_MNTENT) && defined(X11_ENABLED)
+#if defined(HAVE_MNTENT) && defined(LINUXBSD_ENABLED)
// Check /etc/mtab for the list of mounted partitions.
FILE *mtab = setmntent("/etc/mtab", "r");
if (mtab) {
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index c37b3d9c87..178f01b185 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -411,10 +411,6 @@ bool OS_Unix::is_process_running(const ProcessID &p_pid) const {
return true;
}
-bool OS_Unix::has_environment(const String &p_var) const {
- return getenv(p_var.utf8().get_data()) != nullptr;
-}
-
String OS_Unix::get_locale() const {
if (!has_environment("LANG")) {
return "en";
@@ -487,6 +483,10 @@ Error OS_Unix::set_cwd(const String &p_cwd) {
return OK;
}
+bool OS_Unix::has_environment(const String &p_var) const {
+ return getenv(p_var.utf8().get_data()) != nullptr;
+}
+
String OS_Unix::get_environment(const String &p_var) const {
if (getenv(p_var.utf8().get_data())) {
return getenv(p_var.utf8().get_data());
@@ -494,8 +494,15 @@ String OS_Unix::get_environment(const String &p_var) const {
return "";
}
-bool OS_Unix::set_environment(const String &p_var, const String &p_value) const {
- return setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ true) == 0;
+void OS_Unix::set_environment(const String &p_var, const String &p_value) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ int err = setenv(p_var.utf8().get_data(), p_value.utf8().get_data(), /* overwrite: */ 1);
+ ERR_FAIL_COND_MSG(err != 0, vformat("Failed setting environment variable '%s', the system is out of memory.", p_var));
+}
+
+void OS_Unix::unset_environment(const String &p_var) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ unsetenv(p_var.utf8().get_data());
}
String OS_Unix::get_user_data_dir() const {
diff --git a/drivers/unix/os_unix.h b/drivers/unix/os_unix.h
index 416311307c..03429622ae 100644
--- a/drivers/unix/os_unix.h
+++ b/drivers/unix/os_unix.h
@@ -81,7 +81,9 @@ public:
virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
- virtual bool set_environment(const String &p_var, const String &p_value) const override;
+ virtual void set_environment(const String &p_var, const String &p_value) const override;
+ virtual void unset_environment(const String &p_var) const override;
+
virtual String get_locale() const override;
virtual void initialize_debugging() override;
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index 37a94ce4cc..ea40622afc 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -34,7 +34,6 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-
#include <share.h> // _SH_DENYNO
#include <shlwapi.h>
#define WIN32_LEAN_AND_MEAN
@@ -58,7 +57,27 @@ void FileAccessWindows::check_errors() const {
}
}
+bool FileAccessWindows::is_path_invalid(const String &p_path) {
+ // Check for invalid operating system file.
+ String fname = p_path;
+ int dot = fname.find(".");
+ if (dot != -1) {
+ fname = fname.substr(0, dot);
+ }
+ fname = fname.to_lower();
+ return invalid_files.has(fname);
+}
+
Error FileAccessWindows::open_internal(const String &p_path, int p_mode_flags) {
+ if (is_path_invalid(p_path)) {
+#ifdef DEBUG_ENABLED
+ if (p_mode_flags != READ) {
+ WARN_PRINT("The path :" + p_path + " is a reserved Windows system pipe, so it can't be used for creating files.");
+ }
+#endif
+ return ERR_INVALID_PARAMETER;
+ }
+
_close();
path_src = p_path;
@@ -313,6 +332,10 @@ void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) {
}
bool FileAccessWindows::file_exists(const String &p_name) {
+ if (is_path_invalid(p_name)) {
+ return false;
+ }
+
String filename = fix_path(p_name);
FILE *g = _wfsopen((LPCWSTR)(filename.utf16().get_data()), L"rb", _SH_DENYNO);
if (g == nullptr) {
@@ -324,6 +347,10 @@ bool FileAccessWindows::file_exists(const String &p_name) {
}
uint64_t FileAccessWindows::_get_modified_time(const String &p_file) {
+ if (is_path_invalid(p_file)) {
+ return 0;
+ }
+
String file = fix_path(p_file);
if (file.ends_with("/") && file != "/") {
file = file.substr(0, file.length() - 1);
@@ -352,4 +379,20 @@ FileAccessWindows::~FileAccessWindows() {
_close();
}
+HashSet<String> FileAccessWindows::invalid_files;
+
+void FileAccessWindows::initialize() {
+ static const char *reserved_files[]{
+ "con", "prn", "aux", "nul", "com0", "com1", "com2", "com3", "com4", "com5", "com6", "com7", "com8", "com9", "lpt0", "lpt1", "lpt2", "lpt3", "lpt4", "lpt5", "lpt6", "lpt7", "lpt8", "lpt9", nullptr
+ };
+ int reserved_file_index = 0;
+ while (reserved_files[reserved_file_index] != nullptr) {
+ invalid_files.insert(reserved_files[reserved_file_index]);
+ reserved_file_index++;
+ }
+}
+void FileAccessWindows::finalize() {
+ invalid_files.clear();
+}
+
#endif // WINDOWS_ENABLED
diff --git a/drivers/windows/file_access_windows.h b/drivers/windows/file_access_windows.h
index 832cef3363..2b9960d494 100644
--- a/drivers/windows/file_access_windows.h
+++ b/drivers/windows/file_access_windows.h
@@ -50,6 +50,9 @@ class FileAccessWindows : public FileAccess {
void _close();
+ static bool is_path_invalid(const String &p_path);
+ static HashSet<String> invalid_files;
+
public:
virtual Error open_internal(const String &p_path, int p_mode_flags) override; ///< open a file
virtual bool is_open() const override; ///< true when file is open
@@ -79,6 +82,9 @@ public:
virtual uint32_t _get_unix_permissions(const String &p_file) override;
virtual Error _set_unix_permissions(const String &p_file, uint32_t p_permissions) override;
+ static void initialize();
+ static void finalize();
+
FileAccessWindows() {}
virtual ~FileAccessWindows();
};
diff --git a/editor/action_map_editor.cpp b/editor/action_map_editor.cpp
index 712b11d7d7..cb8d98932d 100644
--- a/editor/action_map_editor.cpp
+++ b/editor/action_map_editor.cpp
@@ -354,10 +354,6 @@ void ActionMapEditor::_notification(int p_what) {
}
void ActionMapEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ActionMapEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ActionMapEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ActionMapEditor::drop_data_fw);
-
ADD_SIGNAL(MethodInfo("action_added", PropertyInfo(Variant::STRING, "name")));
ADD_SIGNAL(MethodInfo("action_edited", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::DICTIONARY, "new_action")));
ADD_SIGNAL(MethodInfo("action_removed", PropertyInfo(Variant::STRING, "name")));
@@ -578,7 +574,7 @@ ActionMapEditor::ActionMapEditor() {
action_tree->connect("button_clicked", callable_mp(this, &ActionMapEditor::_tree_button_pressed));
main_vbox->add_child(action_tree);
- action_tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(action_tree, ActionMapEditor);
// Adding event dialog
event_config_dialog = memnew(InputEventConfigurationDialog);
diff --git a/editor/animation_bezier_editor.cpp b/editor/animation_bezier_editor.cpp
index d4ab907e78..639f5e6de5 100644
--- a/editor/animation_bezier_editor.cpp
+++ b/editor/animation_bezier_editor.cpp
@@ -788,7 +788,7 @@ void AnimationBezierTrackEdit::_clear_selection() {
}
void AnimationBezierTrackEdit::_change_selected_keys_handle_mode(Animation::HandleMode p_mode, bool p_auto) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Update Selected Key Handles"));
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
const IntPair track_key_pair = E->get();
@@ -985,7 +985,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (I.value.has_point(mb->get_position())) {
if (I.key == REMOVE_ICON) {
if (!read_only) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action("Remove Bezier Track");
undo_redo->add_do_method(this, "_update_locked_tracks_after", track);
@@ -1172,7 +1172,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
time += 0.0001;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "bezier_track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
@@ -1270,7 +1270,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (moving_selection) {
//combit it
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Bezier Points"));
List<AnimMoveRestore> to_restore;
@@ -1471,7 +1471,7 @@ void AnimationBezierTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if ((moving_handle == -1 || moving_handle == 1) && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
if (!read_only) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Bezier Points"));
if (moving_handle == -1) {
real_t ratio = timeline->get_zoom_scale() * v_zoom;
@@ -1543,7 +1543,7 @@ void AnimationBezierTrackEdit::_menu_selected(int p_index) {
time += 0.001;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Bezier Point"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", selected_track, time, new_point);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", selected_track, time);
@@ -1591,7 +1591,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Duplicate Keys"));
List<Pair<int, real_t>> new_selection_values;
@@ -1637,7 +1637,7 @@ void AnimationBezierTrackEdit::duplicate_selection() {
void AnimationBezierTrackEdit::delete_selection() {
if (selection.size()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Delete Keys"));
for (SelectionSet::Element *E = selection.back(); E; E = E->prev()) {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 89bb1f5ae6..857a9a664a 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -107,7 +107,7 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
float val = p_value;
float prev_val = animation->track_get_key_transition(track, key);
setting = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Change Transition"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(animation.ptr(), "track_set_key_transition", track, key, val);
undo_redo->add_undo_method(animation.ptr(), "track_set_key_transition", track, key, prev_val);
@@ -119,7 +119,7 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
return true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
@@ -704,7 +704,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p
float val = p_value;
float prev_val = animation->track_get_key_transition(track, key);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (!setting) {
setting = true;
undo_redo->create_action(TTR("Animation Multi Change Transition"), UndoRedo::MERGE_ENDS);
@@ -714,7 +714,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p
update_obj = true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D:
case Animation::TYPE_ROTATION_3D:
@@ -925,7 +925,7 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (setting) {
if (update_obj) {
undo_redo->add_do_method(this, "_update_obj", animation);
@@ -1252,7 +1252,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
}
editing = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Length"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(animation.ptr(), "set_length", p_new_len);
undo_redo->add_undo_method(animation.ptr(), "set_length", animation->get_length());
@@ -1265,7 +1265,7 @@ void AnimationTimelineEdit::_anim_length_changed(double p_new_len) {
void AnimationTimelineEdit::_anim_loop_pressed() {
if (!read_only) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Loop"));
switch (animation->get_loop_mode()) {
case Animation::LOOP_NONE: {
@@ -2392,7 +2392,7 @@ void AnimationTrackEdit::_zoom_changed() {
}
void AnimationTrackEdit::_path_submitted(const String &p_text) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Track Path"));
undo_redo->add_do_method(animation.ptr(), "track_set_path", track, p_text);
undo_redo->add_undo_method(animation.ptr(), "track_set_path", track, animation->track_get_path(track));
@@ -2630,7 +2630,7 @@ void AnimationTrackEdit::gui_input(const Ref<InputEvent> &p_event) {
if (!read_only) {
if (check_rect.has_point(pos)) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Toggle Track Enabled"));
undo_redo->add_do_method(animation.ptr(), "track_set_enabled", track, !animation->track_is_enabled(track));
undo_redo->add_undo_method(animation.ptr(), "track_set_enabled", track, animation->track_is_enabled(track));
@@ -3020,7 +3020,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
case MENU_CALL_MODE_DISCRETE:
case MENU_CALL_MODE_CAPTURE: {
Animation::UpdateMode update_mode = Animation::UpdateMode(p_index);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Update Mode"));
undo_redo->add_do_method(animation.ptr(), "value_track_set_update_mode", track, update_mode);
undo_redo->add_undo_method(animation.ptr(), "value_track_set_update_mode", track, animation->value_track_get_update_mode(track));
@@ -3034,7 +3034,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
case MENU_INTERPOLATION_LINEAR_ANGLE:
case MENU_INTERPOLATION_CUBIC_ANGLE: {
Animation::InterpolationType interp_mode = Animation::InterpolationType(p_index - MENU_INTERPOLATION_NEAREST);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Interpolation Mode"));
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_type", track, interp_mode);
undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_type", track, animation->track_get_interpolation_type(track));
@@ -3044,7 +3044,7 @@ void AnimationTrackEdit::_menu_selected(int p_index) {
case MENU_LOOP_WRAP:
case MENU_LOOP_CLAMP: {
bool loop_wrap = p_index == MENU_LOOP_WRAP;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Loop Mode"));
undo_redo->add_do_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, loop_wrap);
undo_redo->add_undo_method(animation.ptr(), "track_set_interpolation_loop_wrap", track, animation->track_get_interpolation_loop_wrap(track));
@@ -3438,7 +3438,7 @@ void AnimationTrackEditor::_animation_track_remove_request(int p_track, Ref<Anim
}
int idx = p_track;
if (idx >= 0 && idx < p_from_animation->get_track_count()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Anim Track"), UndoRedo::MERGE_DISABLE, p_from_animation.ptr());
// Remove corresponding reset tracks if they are no longer needed.
@@ -3639,7 +3639,7 @@ void AnimationTrackEditor::_query_insert(const InsertData &p_id) {
}
void AnimationTrackEditor::_insert_track(bool p_reset_wanted, bool p_create_beziers) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Insert Key"));
Ref<Animation> reset_anim;
@@ -3968,7 +3968,7 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
Ref<Animation> reset_anim;
reset_anim.instantiate();
reset_anim->set_length(ANIM_MIN_LENGTH);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(al.ptr(), "add_animation", SceneStringNames::get_singleton()->RESET, reset_anim);
undo_redo->add_do_method(AnimationPlayerEditor::get_singleton(), "_animation_player_changed", player);
undo_redo->add_undo_method(al.ptr(), "remove_animation", SceneStringNames::get_singleton()->RESET);
@@ -3978,7 +3978,7 @@ Ref<Animation> AnimationTrackEditor::_create_and_get_reset_animation() {
}
void AnimationTrackEditor::_confirm_insert_list() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Insert Key"));
bool create_reset = insert_confirm_reset->is_visible() && insert_confirm_reset->is_pressed();
@@ -4148,7 +4148,7 @@ AnimationTrackEditor::TrackIndices AnimationTrackEditor::_confirm_insert(InsertD
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (create_normal_track) {
if (p_create_beziers) {
bool valid;
@@ -4600,7 +4600,7 @@ void AnimationTrackEditor::_update_scroll(double) {
}
void AnimationTrackEditor::_update_step(double p_new_step) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Step"));
float step_value = p_new_step;
if (timeline->is_using_fps()) {
@@ -4627,7 +4627,7 @@ void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) {
}
_clear_selection(true);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rearrange Tracks"));
undo_redo->add_do_method(animation.ptr(), "track_move_to", p_from_track, p_to_track);
// Take into account that the position of the tracks that come after the one removed will change.
@@ -4671,7 +4671,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
case Animation::TYPE_ROTATION_3D:
case Animation::TYPE_SCALE_3D:
case Animation::TYPE_METHOD: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
@@ -4700,7 +4700,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
@@ -4719,7 +4719,7 @@ void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Track"));
undo_redo->add_do_method(animation.ptr(), "add_track", adding_track_type);
undo_redo->add_do_method(animation.ptr(), "track_set_path", animation->get_track_count(), path_to);
@@ -4744,7 +4744,7 @@ void AnimationTrackEditor::_add_track(int p_type) {
void AnimationTrackEditor::_new_track_property_selected(String p_name) {
String full_path = String(adding_track_path) + ":" + p_name;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (adding_track_type == Animation::TYPE_VALUE) {
Animation::UpdateMode update_mode = Animation::UPDATE_DISCRETE;
{
@@ -4835,7 +4835,7 @@ void AnimationTrackEditor::_insert_key_from_track(float p_ofs, int p_track) {
p_ofs += 0.0001;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (animation->track_get_type(p_track)) {
case Animation::TYPE_POSITION_3D: {
if (!root->has_node(animation->track_get_path(p_track))) {
@@ -4991,7 +4991,7 @@ void AnimationTrackEditor::_add_method_key(const String &p_method) {
}
d["args"] = params;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Method Track Key"));
undo_redo->add_do_method(animation.ptr(), "track_insert_key", insert_key_from_track_call_track, insert_key_from_track_call_ofs, d);
undo_redo->add_undo_method(animation.ptr(), "track_remove_key_at_time", insert_key_from_track_call_track, insert_key_from_track_call_ofs);
@@ -5178,7 +5178,7 @@ void AnimationTrackEditor::_select_at_anim(const Ref<Animation> &p_anim, int p_t
}
void AnimationTrackEditor::_move_selection_commit() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Move Keys"));
List<_AnimMoveRestore> to_restore;
@@ -5430,7 +5430,7 @@ void AnimationTrackEditor::_anim_duplicate_keys(bool transpose) {
int start_track = transpose ? _get_track_selected() : top_track;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Duplicate Keys"));
List<Pair<int, float>> new_selection_values;
@@ -5660,7 +5660,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
int base_track = animation->get_track_count();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Paste Tracks"));
for (int i = 0; i < track_clipboard.size(); i++) {
undo_redo->add_do_method(animation.ptr(), "add_track", track_clipboard[i].track_type);
@@ -5730,7 +5730,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
float s = scale->get_value();
ERR_FAIL_COND_MSG(s == 0, "Can't scale to 0.");
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Scale Keys"));
List<_AnimMoveRestore> to_restore;
@@ -5810,7 +5810,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
ease_dialog->popup_centered(Size2(200, 100) * EDSCALE);
} break;
case EDIT_EASE_CONFIRM: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Make Easing Keys"));
Tween::TransitionType transition_type = static_cast<Tween::TransitionType>(transition_selection->get_selected_id());
@@ -5917,7 +5917,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
_anim_duplicate_keys(true);
} break;
case EDIT_ADD_RESET_KEY: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Add RESET Keys"));
Ref<Animation> reset = _create_and_get_reset_animation();
@@ -5978,7 +5978,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
}
if (selection.size()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Delete Keys"));
for (RBMap<SelectedKey, KeyInfo>::Element *E = selection.back(); E; E = E->prev()) {
@@ -6009,7 +6009,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
bake_dialog->popup_centered(Size2(200, 100) * EDSCALE);
} break;
case EDIT_BAKE_ANIMATION_CONFIRM: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Bake Animation as Linear keys."));
int track_len = animation->get_track_count();
@@ -6130,7 +6130,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
animation->optimize(optimize_velocity_error->get_value(), optimize_angular_error->get_value(), optimize_precision_error->get_value());
_redraw_tracks();
_update_key_edit();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr()));
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this));
@@ -6200,7 +6200,7 @@ void AnimationTrackEditor::_cleanup_animation(Ref<Animation> p_animation) {
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(animation.ptr()));
undo_redo->clear_history(true, undo_redo->get_history_id_for_object(this));
_update_tracks();
@@ -6801,7 +6801,7 @@ void AnimationTrackKeyEditEditor::_time_edit_exited() {
}
int existing = animation->track_find_key(track, new_time, Animation::FIND_MODE_APPROX);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Animation Change Keyframe Time"), UndoRedo::MERGE_ENDS);
if (existing != -1) {
diff --git a/editor/animation_track_editor_plugins.cpp b/editor/animation_track_editor_plugins.cpp
index 0926a63f88..ba73a63245 100644
--- a/editor/animation_track_editor_plugins.cpp
+++ b/editor/animation_track_editor_plugins.cpp
@@ -31,7 +31,6 @@
#include "animation_track_editor_plugins.h"
#include "editor/audio_stream_preview.h"
-#include "editor/editor_node.h"
#include "editor/editor_resource_preview.h"
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
@@ -1018,7 +1017,7 @@ void AnimationTrackEditTypeAudio::drop_data(const Point2 &p_point, const Variant
ofs += 0.0001;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Audio Track Clip"));
undo_redo->add_do_method(get_animation().ptr(), "audio_track_insert_key", get_track(), ofs, stream);
undo_redo->add_undo_method(get_animation().ptr(), "track_remove_key_at_time", get_track(), ofs);
@@ -1125,7 +1124,7 @@ void AnimationTrackEditTypeAudio::gui_input(const Ref<InputEvent> &p_event) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (len_resizing && mb.is_valid() && !mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
if (len_resizing_rel == 0 || len_resizing_index < 0) {
len_resizing = false;
diff --git a/editor/array_property_edit.cpp b/editor/array_property_edit.cpp
deleted file mode 100644
index b2e12e2409..0000000000
--- a/editor/array_property_edit.cpp
+++ /dev/null
@@ -1,301 +0,0 @@
-/**************************************************************************/
-/* array_property_edit.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 "array_property_edit.h"
-
-#include "core/io/marshalls.h"
-#include "editor/editor_node.h"
-#include "editor/editor_undo_redo_manager.h"
-
-#define ITEMS_PER_PAGE 100
-
-Variant ArrayPropertyEdit::get_array() const {
- Object *o = ObjectDB::get_instance(obj);
- if (!o) {
- return Array();
- }
- Variant arr = o->get(property);
- if (!arr.is_array()) {
- Callable::CallError ce;
- Variant::construct(default_type, arr, nullptr, 0, ce);
- }
- return arr;
-}
-
-void ArrayPropertyEdit::_notif_change() {
- notify_property_list_changed();
-}
-
-void ArrayPropertyEdit::_set_size(int p_size) {
- Variant arr = get_array();
- arr.call("resize", p_size);
- Object *o = ObjectDB::get_instance(obj);
- if (!o) {
- return;
- }
-
- o->set(property, arr);
-}
-
-void ArrayPropertyEdit::_set_value(int p_idx, const Variant &p_value) {
- Variant arr = get_array();
- arr.set(p_idx, p_value);
- Object *o = ObjectDB::get_instance(obj);
- if (!o) {
- return;
- }
-
- o->set(property, arr);
-}
-
-bool ArrayPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
- String pn = p_name;
-
- if (pn.begins_with("array/")) {
- if (pn == "array/size") {
- Variant arr = get_array();
- int size = arr.call("size");
-
- int newsize = p_value;
- if (newsize == size) {
- return true;
- }
-
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
- ur->create_action(TTR("Resize Array"));
- ur->add_do_method(this, "_set_size", newsize);
- ur->add_undo_method(this, "_set_size", size);
- if (newsize < size) {
- for (int i = newsize; i < size; i++) {
- ur->add_undo_method(this, "_set_value", i, arr.get(i));
- }
- } else if (newsize > size) {
- Variant init;
- Callable::CallError ce;
- Variant::Type new_type = subtype;
- if (new_type == Variant::NIL && size) {
- new_type = arr.get(size - 1).get_type();
- }
- if (new_type != Variant::NIL) {
- Variant::construct(new_type, init, nullptr, 0, ce);
- for (int i = size; i < newsize; i++) {
- ur->add_do_method(this, "_set_value", i, init);
- }
- }
- }
- ur->add_do_method(this, "_notif_change");
- ur->add_undo_method(this, "_notif_change");
- ur->commit_action();
- return true;
- }
- if (pn == "array/page") {
- page = p_value;
- notify_property_list_changed();
- return true;
- }
-
- } else if (pn.begins_with("indices")) {
- if (pn.contains("_")) {
- //type
- int idx = pn.get_slicec('/', 1).get_slicec('_', 0).to_int();
-
- int type = p_value;
-
- Variant arr = get_array();
-
- Variant value = arr.get(idx);
- if (value.get_type() != type && type >= 0 && type < Variant::VARIANT_MAX) {
- Callable::CallError ce;
- Variant new_value;
- Variant::construct(Variant::Type(type), new_value, nullptr, 0, ce);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
-
- ur->create_action(TTR("Change Array Value Type"));
- ur->add_do_method(this, "_set_value", idx, new_value);
- ur->add_undo_method(this, "_set_value", idx, value);
- ur->add_do_method(this, "_notif_change");
- ur->add_undo_method(this, "_notif_change");
- ur->commit_action();
- }
- return true;
-
- } else {
- int idx = pn.get_slicec('/', 1).to_int();
- Variant arr = get_array();
-
- Variant value = arr.get(idx);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
-
- ur->create_action(TTR("Change Array Value"));
- ur->add_do_method(this, "_set_value", idx, p_value);
- ur->add_undo_method(this, "_set_value", idx, value);
- ur->commit_action();
- return true;
- }
- }
-
- return false;
-}
-
-bool ArrayPropertyEdit::_get(const StringName &p_name, Variant &r_ret) const {
- Variant arr = get_array();
- //int size = arr.call("size");
-
- String pn = p_name;
- if (pn.begins_with("array/")) {
- if (pn == "array/size") {
- r_ret = arr.call("size");
- return true;
- }
- if (pn == "array/page") {
- r_ret = page;
- return true;
- }
- } else if (pn.begins_with("indices")) {
- if (pn.contains("_")) {
- //type
- int idx = pn.get_slicec('/', 1).get_slicec('_', 0).to_int();
- bool valid;
- r_ret = arr.get(idx, &valid);
- if (valid) {
- r_ret = r_ret.get_type();
- }
- return valid;
-
- } else {
- int idx = pn.get_slicec('/', 1).to_int();
- bool valid;
- r_ret = arr.get(idx, &valid);
-
- if (r_ret.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(r_ret)) {
- r_ret = Object::cast_to<EncodedObjectAsID>(r_ret)->get_object_id();
- }
-
- return valid;
- }
- }
-
- return false;
-}
-
-void ArrayPropertyEdit::_get_property_list(List<PropertyInfo> *p_list) const {
- Variant arr = get_array();
- int size = arr.call("size");
-
- p_list->push_back(PropertyInfo(Variant::INT, "array/size", PROPERTY_HINT_RANGE, "0,100000,1"));
- int pages = size / ITEMS_PER_PAGE;
- if (pages > 0) {
- p_list->push_back(PropertyInfo(Variant::INT, "array/page", PROPERTY_HINT_RANGE, "0," + itos(pages) + ",1"));
- }
-
- int offset = page * ITEMS_PER_PAGE;
-
- int items = MIN(size - offset, ITEMS_PER_PAGE);
-
- for (int i = 0; i < items; i++) {
- Variant v = arr.get(i + offset);
- bool is_typed = arr.get_type() != Variant::ARRAY || subtype != Variant::NIL;
-
- if (!is_typed) {
- p_list->push_back(PropertyInfo(Variant::INT, "indices/" + itos(i + offset) + "_type", PROPERTY_HINT_ENUM, vtypes));
- }
-
- if (v.get_type() == Variant::OBJECT && Object::cast_to<EncodedObjectAsID>(v)) {
- p_list->push_back(PropertyInfo(Variant::INT, "indices/" + itos(i + offset), PROPERTY_HINT_OBJECT_ID, "Object"));
- continue;
- }
-
- if (is_typed || v.get_type() != Variant::NIL) {
- PropertyInfo pi(v.get_type(), "indices/" + itos(i + offset));
- if (subtype != Variant::NIL) {
- pi.type = Variant::Type(subtype);
- pi.hint = PropertyHint(subtype_hint);
- pi.hint_string = subtype_hint_string;
- } else if (v.get_type() == Variant::OBJECT) {
- pi.hint = PROPERTY_HINT_RESOURCE_TYPE;
- pi.hint_string = "Resource";
- }
-
- p_list->push_back(pi);
- }
- }
-}
-
-void ArrayPropertyEdit::edit(Object *p_obj, const StringName &p_prop, const String &p_hint_string, Variant::Type p_deftype) {
- page = 0;
- property = p_prop;
- obj = p_obj->get_instance_id();
- default_type = p_deftype;
-
- if (!p_hint_string.is_empty()) {
- int hint_subtype_separator = p_hint_string.find(":");
- if (hint_subtype_separator >= 0) {
- String subtype_string = p_hint_string.substr(0, hint_subtype_separator);
-
- int slash_pos = subtype_string.find("/");
- if (slash_pos >= 0) {
- subtype_hint = PropertyHint(subtype_string.substr(slash_pos + 1, subtype_string.size() - slash_pos - 1).to_int());
- subtype_string = subtype_string.substr(0, slash_pos);
- }
-
- subtype_hint_string = p_hint_string.substr(hint_subtype_separator + 1, p_hint_string.size() - hint_subtype_separator - 1);
- subtype = Variant::Type(subtype_string.to_int());
- }
- }
-}
-
-Node *ArrayPropertyEdit::get_node() {
- return Object::cast_to<Node>(ObjectDB::get_instance(obj));
-}
-
-bool ArrayPropertyEdit::_dont_undo_redo() {
- return true;
-}
-
-void ArrayPropertyEdit::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_set_size"), &ArrayPropertyEdit::_set_size);
- ClassDB::bind_method(D_METHOD("_set_value"), &ArrayPropertyEdit::_set_value);
- ClassDB::bind_method(D_METHOD("_notif_change"), &ArrayPropertyEdit::_notif_change);
- ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &ArrayPropertyEdit::_dont_undo_redo);
-}
-
-ArrayPropertyEdit::ArrayPropertyEdit() {
- page = 0;
- for (int i = 0; i < Variant::VARIANT_MAX; i++) {
- if (i > 0) {
- vtypes += ",";
- }
- vtypes += Variant::get_type_name(Variant::Type(i));
- }
- default_type = Variant::NIL;
- subtype = Variant::NIL;
- subtype_hint = PROPERTY_HINT_NONE;
- subtype_hint_string = "";
-}
diff --git a/editor/code_editor.cpp b/editor/code_editor.cpp
index ba7e7f2877..644735a4d8 100644
--- a/editor/code_editor.cpp
+++ b/editor/code_editor.cpp
@@ -143,6 +143,7 @@ void FindReplaceBar::unhandled_input(const Ref<InputEvent> &p_event) {
}
bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col) {
+ text_editor->remove_secondary_carets();
String text = get_search_text();
Point2i pos = text_editor->search(text, p_flags, p_from_line, p_from_col);
@@ -178,6 +179,7 @@ bool FindReplaceBar::_search(uint32_t p_flags, int p_from_line, int p_from_col)
}
void FindReplaceBar::_replace() {
+ text_editor->remove_secondary_carets();
bool selection_enabled = text_editor->has_selection(0);
Point2i selection_begin, selection_end;
if (selection_enabled) {
@@ -225,6 +227,7 @@ void FindReplaceBar::_replace() {
}
void FindReplaceBar::_replace_all() {
+ text_editor->remove_secondary_carets();
text_editor->disconnect("text_changed", callable_mp(this, &FindReplaceBar::_editor_text_changed));
// Line as x so it gets priority in comparison, column as y.
Point2i orig_cursor(text_editor->get_caret_line(0), text_editor->get_caret_column(0));
@@ -2083,6 +2086,7 @@ CodeTextEditor::CodeTextEditor() {
text_editor = memnew(CodeEdit);
add_child(text_editor);
text_editor->set_v_size_flags(SIZE_EXPAND_FILL);
+ text_editor->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_GDSCRIPT);
int ot_mode = EDITOR_GET("interface/editor/code_font_contextual_ligatures");
Ref<FontVariation> fc = text_editor->get_theme_font(SNAME("font"));
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 78987ee6ef..6f4736dca7 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -685,7 +685,7 @@ void ConnectionsDock::_connect(ConnectDialog::ConnectionData p_cd) {
}
Callable callable = p_cd.get_callable();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Connect '%s' to '%s'"), String(p_cd.signal), String(p_cd.method)));
undo_redo->add_do_method(source, "connect", p_cd.signal, callable, p_cd.flags);
undo_redo->add_undo_method(source, "disconnect", p_cd.signal, callable);
@@ -706,7 +706,7 @@ void ConnectionsDock::_disconnect(TreeItem &p_item) {
ERR_FAIL_COND(cd.source != selected_node); // Shouldn't happen but... Bugcheck.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Disconnect '%s' from '%s'"), cd.signal, cd.method));
Callable callable = cd.get_callable();
@@ -733,7 +733,7 @@ void ConnectionsDock::_disconnect_all() {
TreeItem *child = item->get_first_child();
String signal_name = item->get_metadata(0).operator Dictionary()["name"];
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Disconnect all from signal: '%s'"), signal_name));
while (child) {
@@ -1196,6 +1196,7 @@ ConnectionsDock::ConnectionsDock() {
tree->set_columns(1);
tree->set_select_mode(Tree::SELECT_ROW);
tree->set_hide_root(true);
+ tree->set_column_clip_content(0, true);
vbc->add_child(tree);
tree->set_v_size_flags(Control::SIZE_EXPAND_FILL);
tree->set_allow_rmb_select(true);
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index 98fcde17c4..0814d5b5ca 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -724,12 +724,6 @@ void CreateDialog::_load_favorites_and_history() {
}
void CreateDialog::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_save_and_update_favorite_list"), &CreateDialog::_save_and_update_favorite_list);
-
- ClassDB::bind_method("_get_drag_data_fw", &CreateDialog::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &CreateDialog::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &CreateDialog::drop_data_fw);
-
ADD_SIGNAL(MethodInfo("create"));
ADD_SIGNAL(MethodInfo("favorites_updated"));
}
@@ -759,7 +753,7 @@ CreateDialog::CreateDialog() {
favorites->connect("cell_selected", callable_mp(this, &CreateDialog::_favorite_selected));
favorites->connect("item_activated", callable_mp(this, &CreateDialog::_favorite_activated));
favorites->add_theme_constant_override("draw_guides", 1);
- favorites->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(favorites, CreateDialog);
fav_vb->add_margin_child(TTR("Favorites:"), favorites, true);
VBoxContainer *rec_vb = memnew(VBoxContainer);
diff --git a/editor/debugger/debug_adapter/debug_adapter_parser.cpp b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
index d685db40d9..fc806ded5e 100644
--- a/editor/debugger/debug_adapter/debug_adapter_parser.cpp
+++ b/editor/debugger/debug_adapter/debug_adapter_parser.cpp
@@ -213,7 +213,7 @@ Dictionary DebugAdapterParser::req_launch(const Dictionary &p_params) const {
}
EditorNode *editor = EditorNode::get_singleton();
- Error err = platform_string == "android" ? editor->run_play_native(device, idx) : editor->run_play_native(-1, idx);
+ Error err = platform_string == "android" ? editor->run_play_native(device * 10000 + idx) : editor->run_play_native(idx);
if (err) {
if (err == ERR_INVALID_PARAMETER && platform_string == "android") {
return prepare_error_response(p_params, DAP::ErrorType::MISSING_DEVICE);
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index e4afbde89f..a368cacf56 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -275,7 +275,7 @@ void EditorDebuggerNode::stop(bool p_force) {
});
_break_state_changed();
breakpoints.clear();
- EditorNode::get_undo_redo()->clear_history(false, EditorUndoRedoManager::REMOTE_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(false, EditorUndoRedoManager::REMOTE_HISTORY);
set_process(false);
}
diff --git a/editor/dictionary_property_edit.cpp b/editor/dictionary_property_edit.cpp
deleted file mode 100644
index 0d191cabe8..0000000000
--- a/editor/dictionary_property_edit.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
-/**************************************************************************/
-/* dictionary_property_edit.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 "dictionary_property_edit.h"
-#include "editor/editor_node.h"
-#include "editor/editor_undo_redo_manager.h"
-
-void DictionaryPropertyEdit::_notif_change() {
- notify_property_list_changed();
-}
-
-void DictionaryPropertyEdit::_set_key(const Variant &p_old_key, const Variant &p_new_key) {
- // TODO: Set key of a dictionary is not allowed yet
-}
-
-void DictionaryPropertyEdit::_set_value(const Variant &p_key, const Variant &p_value) {
- Dictionary dict = get_dictionary();
- dict[p_key] = p_value;
- Object *o = ObjectDB::get_instance(obj);
- if (!o) {
- return;
- }
-
- o->set(property, dict);
-}
-
-Variant DictionaryPropertyEdit::get_dictionary() const {
- Object *o = ObjectDB::get_instance(obj);
- if (!o) {
- return Dictionary();
- }
- Variant dict = o->get(property);
- if (dict.get_type() != Variant::DICTIONARY) {
- return Dictionary();
- }
- return dict;
-}
-
-void DictionaryPropertyEdit::_get_property_list(List<PropertyInfo> *p_list) const {
- Dictionary dict = get_dictionary();
-
- Array keys = dict.keys();
- keys.sort();
-
- for (int i = 0; i < keys.size(); i++) {
- String index = itos(i);
-
- const Variant &key = keys[i];
- PropertyInfo pi(key.get_type(), index + ": key");
- p_list->push_back(pi);
-
- const Variant &value = dict[key];
- pi = PropertyInfo(value.get_type(), index + ": value");
- p_list->push_back(pi);
- }
-}
-
-void DictionaryPropertyEdit::edit(Object *p_obj, const StringName &p_prop) {
- property = p_prop;
- obj = p_obj->get_instance_id();
-}
-
-Node *DictionaryPropertyEdit::get_node() {
- Object *o = ObjectDB::get_instance(obj);
- if (!o) {
- return nullptr;
- }
-
- return cast_to<Node>(o);
-}
-
-bool DictionaryPropertyEdit::_dont_undo_redo() {
- return true;
-}
-
-void DictionaryPropertyEdit::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_set_key"), &DictionaryPropertyEdit::_set_key);
- ClassDB::bind_method(D_METHOD("_set_value"), &DictionaryPropertyEdit::_set_value);
- ClassDB::bind_method(D_METHOD("_notif_change"), &DictionaryPropertyEdit::_notif_change);
- ClassDB::bind_method(D_METHOD("_dont_undo_redo"), &DictionaryPropertyEdit::_dont_undo_redo);
-}
-
-bool DictionaryPropertyEdit::_set(const StringName &p_name, const Variant &p_value) {
- Dictionary dict = get_dictionary();
- Array keys = dict.keys();
- keys.sort();
-
- String pn = p_name;
- int slash = pn.find(": ");
- if (slash != -1 && pn.length() > slash) {
- String type = pn.substr(slash + 2, pn.length());
- int index = pn.substr(0, slash).to_int();
- if (type == "key" && index < keys.size()) {
- const Variant &key = keys[index];
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
-
- ur->create_action(TTR("Change Dictionary Key"));
- ur->add_do_method(this, "_set_key", key, p_value);
- ur->add_undo_method(this, "_set_key", p_value, key);
- ur->commit_action();
-
- return true;
- } else if (type == "value" && index < keys.size()) {
- const Variant &key = keys[index];
- if (dict.has(key)) {
- Variant value = dict[key];
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
-
- ur->create_action(TTR("Change Dictionary Value"));
- ur->add_do_method(this, "_set_value", key, p_value);
- ur->add_undo_method(this, "_set_value", key, value);
- ur->commit_action();
-
- return true;
- }
- }
- }
-
- return false;
-}
-
-bool DictionaryPropertyEdit::_get(const StringName &p_name, Variant &r_ret) const {
- Dictionary dict = get_dictionary();
- Array keys = dict.keys();
- keys.sort();
-
- String pn = p_name;
- int slash = pn.find(": ");
-
- if (slash != -1 && pn.length() > slash) {
- String type = pn.substr(slash + 2, pn.length());
- int index = pn.substr(0, slash).to_int();
-
- if (type == "key" && index < keys.size()) {
- r_ret = keys[index];
- return true;
- } else if (type == "value" && index < keys.size()) {
- const Variant &key = keys[index];
- if (dict.has(key)) {
- r_ret = dict[key];
- return true;
- }
- }
- }
-
- return false;
-}
-
-DictionaryPropertyEdit::DictionaryPropertyEdit() {
-}
diff --git a/editor/doc_tools.cpp b/editor/doc_tools.cpp
index 85adc312f2..5bdef32c60 100644
--- a/editor/doc_tools.cpp
+++ b/editor/doc_tools.cpp
@@ -750,6 +750,7 @@ void DocTools::generate(bool p_basic_types) {
MethodInfo mi;
mi.name = "operator []";
mi.return_val.type = Variant::get_indexed_element_type(Variant::Type(i));
+ mi.return_val.usage = Variant::get_indexed_element_usage(Variant::Type(i));
PropertyInfo arg;
arg.name = "index";
arg.type = Variant::INT;
@@ -1021,15 +1022,15 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
if (parser->get_node_name() == element) {
DocData::MethodDoc method;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- method.name = parser->get_attribute_value("name");
+ method.name = parser->get_named_attribute_value("name");
if (parser->has_attribute("qualifiers")) {
- method.qualifiers = parser->get_attribute_value("qualifiers");
+ method.qualifiers = parser->get_named_attribute_value("qualifiers");
}
if (parser->has_attribute("is_deprecated")) {
- method.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ method.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- method.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ method.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
while (parser->read() == OK) {
@@ -1037,21 +1038,21 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
String name = parser->get_node_name();
if (name == "return") {
ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- method.return_type = parser->get_attribute_value("type");
+ method.return_type = parser->get_named_attribute_value("type");
if (parser->has_attribute("enum")) {
- method.return_enum = parser->get_attribute_value("enum");
+ method.return_enum = parser->get_named_attribute_value("enum");
}
} else if (name == "returns_error") {
ERR_FAIL_COND_V(!parser->has_attribute("number"), ERR_FILE_CORRUPT);
- method.errors_returned.push_back(parser->get_attribute_value("number").to_int());
+ method.errors_returned.push_back(parser->get_named_attribute_value("number").to_int());
} else if (name == "param") {
DocData::ArgumentDoc argument;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- argument.name = parser->get_attribute_value("name");
+ argument.name = parser->get_named_attribute_value("name");
ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- argument.type = parser->get_attribute_value("type");
+ argument.type = parser->get_named_attribute_value("type");
if (parser->has_attribute("enum")) {
- argument.enumeration = parser->get_attribute_value("enum");
+ argument.enumeration = parser->get_named_attribute_value("enum");
}
method.arguments.push_back(argument);
@@ -1153,21 +1154,21 @@ Error DocTools::_load(Ref<XMLParser> parser) {
ERR_FAIL_COND_V(parser->get_node_name() != "class", ERR_FILE_CORRUPT);
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- String name = parser->get_attribute_value("name");
+ String name = parser->get_named_attribute_value("name");
class_list[name] = DocData::ClassDoc();
DocData::ClassDoc &c = class_list[name];
c.name = name;
if (parser->has_attribute("inherits")) {
- c.inherits = parser->get_attribute_value("inherits");
+ c.inherits = parser->get_named_attribute_value("inherits");
}
if (parser->has_attribute("is_deprecated")) {
- c.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ c.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- c.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ c.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
while (parser->read() == OK) {
@@ -1193,7 +1194,7 @@ Error DocTools::_load(Ref<XMLParser> parser) {
if (name3 == "link") {
DocData::TutorialDoc tutorial;
if (parser->has_attribute("title")) {
- tutorial.title = parser->get_attribute_value("title");
+ tutorial.title = parser->get_named_attribute_value("title");
}
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@@ -1231,23 +1232,23 @@ Error DocTools::_load(Ref<XMLParser> parser) {
DocData::PropertyDoc prop2;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- prop2.name = parser->get_attribute_value("name");
+ prop2.name = parser->get_named_attribute_value("name");
ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- prop2.type = parser->get_attribute_value("type");
+ prop2.type = parser->get_named_attribute_value("type");
if (parser->has_attribute("setter")) {
- prop2.setter = parser->get_attribute_value("setter");
+ prop2.setter = parser->get_named_attribute_value("setter");
}
if (parser->has_attribute("getter")) {
- prop2.getter = parser->get_attribute_value("getter");
+ prop2.getter = parser->get_named_attribute_value("getter");
}
if (parser->has_attribute("enum")) {
- prop2.enumeration = parser->get_attribute_value("enum");
+ prop2.enumeration = parser->get_named_attribute_value("enum");
}
if (parser->has_attribute("is_deprecated")) {
- prop2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ prop2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- prop2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ prop2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
if (!parser->is_empty()) {
parser->read();
@@ -1274,11 +1275,11 @@ Error DocTools::_load(Ref<XMLParser> parser) {
DocData::ThemeItemDoc prop2;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- prop2.name = parser->get_attribute_value("name");
+ prop2.name = parser->get_named_attribute_value("name");
ERR_FAIL_COND_V(!parser->has_attribute("type"), ERR_FILE_CORRUPT);
- prop2.type = parser->get_attribute_value("type");
+ prop2.type = parser->get_named_attribute_value("type");
ERR_FAIL_COND_V(!parser->has_attribute("data_type"), ERR_FILE_CORRUPT);
- prop2.data_type = parser->get_attribute_value("data_type");
+ prop2.data_type = parser->get_named_attribute_value("data_type");
if (!parser->is_empty()) {
parser->read();
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
@@ -1303,21 +1304,21 @@ Error DocTools::_load(Ref<XMLParser> parser) {
if (name3 == "constant") {
DocData::ConstantDoc constant2;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
- constant2.name = parser->get_attribute_value("name");
+ constant2.name = parser->get_named_attribute_value("name");
ERR_FAIL_COND_V(!parser->has_attribute("value"), ERR_FILE_CORRUPT);
- constant2.value = parser->get_attribute_value("value");
+ constant2.value = parser->get_named_attribute_value("value");
constant2.is_value_valid = true;
if (parser->has_attribute("enum")) {
- constant2.enumeration = parser->get_attribute_value("enum");
+ constant2.enumeration = parser->get_named_attribute_value("enum");
}
if (parser->has_attribute("is_bitfield")) {
- constant2.is_bitfield = parser->get_attribute_value("is_bitfield").to_lower() == "true";
+ constant2.is_bitfield = parser->get_named_attribute_value("is_bitfield").to_lower() == "true";
}
if (parser->has_attribute("is_deprecated")) {
- constant2.is_deprecated = parser->get_attribute_value("is_deprecated").to_lower() == "true";
+ constant2.is_deprecated = parser->get_named_attribute_value("is_deprecated").to_lower() == "true";
}
if (parser->has_attribute("is_experimental")) {
- constant2.is_experimental = parser->get_attribute_value("is_experimental").to_lower() == "true";
+ constant2.is_experimental = parser->get_named_attribute_value("is_experimental").to_lower() == "true";
}
if (!parser->is_empty()) {
parser->read();
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 7ef99d56ab..f4cefc606b 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -282,7 +282,7 @@ void EditorAudioBus::_name_changed(const String &p_new_name) {
}
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
StringName current = AudioServer::get_singleton()->get_bus_name(get_index());
ur->create_action(TTR("Rename Audio Bus"));
@@ -323,7 +323,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) {
slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Audio Bus Volume"), UndoRedo::MERGE_ENDS);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), p_db);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", get_index(), AudioServer::get_singleton()->get_bus_volume_db(get_index()));
@@ -417,7 +417,7 @@ void EditorAudioBus::_hide_value_preview() {
void EditorAudioBus::_solo_toggled() {
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Toggle Audio Bus Solo"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), solo->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_solo", get_index(), AudioServer::get_singleton()->is_bus_solo(get_index()));
@@ -431,7 +431,7 @@ void EditorAudioBus::_solo_toggled() {
void EditorAudioBus::_mute_toggled() {
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Toggle Audio Bus Mute"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), mute->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_mute", get_index(), AudioServer::get_singleton()->is_bus_mute(get_index()));
@@ -445,7 +445,7 @@ void EditorAudioBus::_mute_toggled() {
void EditorAudioBus::_bypass_toggled() {
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Toggle Audio Bus Bypass Effects"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), bypass->is_pressed());
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_bypass_effects", get_index(), AudioServer::get_singleton()->is_bus_bypassing_effects(get_index()));
@@ -459,7 +459,7 @@ void EditorAudioBus::_bypass_toggled() {
void EditorAudioBus::_send_selected(int p_which) {
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Select Audio Bus Send"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_send", get_index(), send->get_item_text(p_which));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_send", get_index(), AudioServer::get_singleton()->get_bus_send(get_index()));
@@ -509,7 +509,7 @@ void EditorAudioBus::_effect_edited() {
int index = effect->get_metadata(0);
updating_bus = true;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Select Audio Bus Send"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, effect->is_checked(0));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", get_index(), index, AudioServer::get_singleton()->is_bus_effect_enabled(get_index(), index));
@@ -536,7 +536,7 @@ void EditorAudioBus::_effect_add(int p_which) {
afxr->set_name(effect_options->get_item_text(p_which));
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Add Audio Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), afxr, -1);
ur->add_undo_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect_count(get_index()));
@@ -690,7 +690,7 @@ void EditorAudioBus::drop_data_fw(const Point2 &p_point, const Variant &p_data,
bool enabled = AudioServer::get_singleton()->is_bus_effect_enabled(bus, effect);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Move Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", bus, effect);
ur->add_do_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(bus, effect), paste_at);
@@ -732,7 +732,7 @@ void EditorAudioBus::_delete_effect_pressed(int p_option) {
int index = item->get_metadata(0);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Delete Bus Effect"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus_effect", get_index(), index);
ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", get_index(), AudioServer::get_singleton()->get_bus_effect(get_index(), index), index);
@@ -765,10 +765,6 @@ void EditorAudioBus::_bind_methods() {
ClassDB::bind_method("update_bus", &EditorAudioBus::update_bus);
ClassDB::bind_method("update_send", &EditorAudioBus::update_send);
- ClassDB::bind_method("_get_drag_data_fw", &EditorAudioBus::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &EditorAudioBus::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &EditorAudioBus::drop_data_fw);
-
ADD_SIGNAL(MethodInfo("duplicate_request"));
ADD_SIGNAL(MethodInfo("delete_request"));
ADD_SIGNAL(MethodInfo("vol_reset_request"));
@@ -903,7 +899,7 @@ EditorAudioBus::EditorAudioBus(EditorAudioBuses *p_buses, bool p_is_master) {
effects->connect("item_edited", callable_mp(this, &EditorAudioBus::_effect_edited));
effects->connect("cell_selected", callable_mp(this, &EditorAudioBus::_effect_selected));
effects->set_edit_checkbox_cell_only_when_checkbox_is_pressed(true);
- effects->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(effects, EditorAudioBus);
effects->connect("item_mouse_selected", callable_mp(this, &EditorAudioBus::_effect_rmb));
effects->set_allow_rmb_select(true);
effects->set_focus_mode(FOCUS_CLICK);
@@ -1065,7 +1061,7 @@ void EditorAudioBuses::_notification(int p_what) {
}
void EditorAudioBuses::_add_bus() {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Add Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1);
@@ -1097,7 +1093,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Delete Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "remove_bus", index);
@@ -1119,7 +1115,7 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
void EditorAudioBuses::_duplicate_bus(int p_which) {
int add_at_pos = p_which + 1;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Duplicate Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "add_bus", add_at_pos);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", add_at_pos, AudioServer::get_singleton()->get_bus_name(p_which) + " Copy");
@@ -1142,7 +1138,7 @@ void EditorAudioBuses::_reset_bus_volume(Object *p_which) {
EditorAudioBus *bus = Object::cast_to<EditorAudioBus>(p_which);
int index = bus->get_index();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Reset Bus Volume"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_volume_db", index, 0.f);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_volume_db", index, AudioServer::get_singleton()->get_bus_volume_db(index));
@@ -1162,7 +1158,7 @@ void EditorAudioBuses::_request_drop_end() {
}
void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Move Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "move_bus", p_bus, p_index);
@@ -1221,7 +1217,7 @@ void EditorAudioBuses::_load_default_layout() {
file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
@@ -1237,7 +1233,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
} else if (file_dialog->get_file_mode() == EditorFileDialog::FILE_MODE_SAVE_FILE) {
@@ -1257,7 +1253,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
edited_path = p_string;
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
_update_buses();
- EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
}
@@ -1356,7 +1352,7 @@ void EditorAudioBuses::open_layout(const String &p_path) {
file->set_text(p_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
_update_buses();
- EditorNode::get_undo_redo()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 4001b849ff..f843733f2c 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -194,7 +194,7 @@ void EditorAutoloadSettings::_autoload_edited() {
TreeItem *ti = tree->get_edited();
int column = tree->get_edited_column();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (column == 0) {
String name = ti->get_text(0);
@@ -289,7 +289,7 @@ void EditorAutoloadSettings::_autoload_button_pressed(Object *p_item, int p_colu
String name = "autoload/" + ti->get_text(0);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_button) {
case BUTTON_OPEN: {
@@ -717,7 +717,7 @@ void EditorAutoloadSettings::drop_data_fw(const Point2 &p_point, const Variant &
orders.sort();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rearrange Autoloads"));
@@ -760,7 +760,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
name = "autoload/" + name;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Autoload"));
// Singleton autoloads are represented with a leading "*" in their path.
@@ -786,7 +786,7 @@ bool EditorAutoloadSettings::autoload_add(const String &p_name, const String &p_
void EditorAutoloadSettings::autoload_remove(const String &p_name) {
String name = "autoload/" + p_name;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
int order = ProjectSettings::get_singleton()->get_order(name);
@@ -808,12 +808,6 @@ void EditorAutoloadSettings::autoload_remove(const String &p_name) {
}
void EditorAutoloadSettings::_bind_methods() {
- ClassDB::bind_method("_autoload_open", &EditorAutoloadSettings::_autoload_open);
-
- ClassDB::bind_method("_get_drag_data_fw", &EditorAutoloadSettings::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &EditorAutoloadSettings::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &EditorAutoloadSettings::drop_data_fw);
-
ClassDB::bind_method("update_autoload", &EditorAutoloadSettings::update_autoload);
ClassDB::bind_method("autoload_add", &EditorAutoloadSettings::autoload_add);
ClassDB::bind_method("autoload_remove", &EditorAutoloadSettings::autoload_remove);
@@ -935,7 +929,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
tree->set_select_mode(Tree::SELECT_MULTI);
tree->set_allow_reselect(true);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(tree, EditorAutoloadSettings);
tree->set_columns(4);
tree->set_column_titles_visible(true);
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index c5fe89e35d..3059ce445c 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -122,12 +122,6 @@ int EditorSelectionHistory::get_history_pos() {
return current_elem_idx;
}
-bool EditorSelectionHistory::is_history_obj_inspector_only(int p_obj) const {
- ERR_FAIL_INDEX_V(p_obj, history.size(), false);
- ERR_FAIL_INDEX_V(history[p_obj].level, history[p_obj].path.size(), false);
- return history[p_obj].path[history[p_obj].level].inspector_only;
-}
-
ObjectID EditorSelectionHistory::get_history_obj(int p_obj) const {
ERR_FAIL_INDEX_V(p_obj, history.size(), ObjectID());
ERR_FAIL_INDEX_V(history[p_obj].level, history[p_obj].path.size(), ObjectID());
@@ -351,18 +345,6 @@ void EditorData::apply_changes_in_editors() {
}
}
-void EditorData::save_editor_global_states() {
- for (int i = 0; i < editor_plugins.size(); i++) {
- editor_plugins[i]->save_global_state();
- }
-}
-
-void EditorData::restore_editor_global_states() {
- for (int i = 0; i < editor_plugins.size(); i++) {
- editor_plugins[i]->restore_global_state();
- }
-}
-
void EditorData::paste_object_params(Object *p_object) {
ERR_FAIL_NULL(p_object);
undo_redo_manager->create_action(TTR("Paste Params"));
@@ -390,7 +372,7 @@ void EditorData::set_scene_as_saved(int p_idx) {
}
ERR_FAIL_INDEX(p_idx, edited_scene.size());
- get_undo_redo()->set_history_as_saved(edited_scene[p_idx].history_id);
+ undo_redo_manager->set_history_as_saved(edited_scene[p_idx].history_id);
}
bool EditorData::is_scene_changed(int p_idx) {
@@ -399,7 +381,7 @@ bool EditorData::is_scene_changed(int p_idx) {
}
ERR_FAIL_INDEX_V(p_idx, edited_scene.size(), false);
- uint64_t current_scene_version = get_undo_redo()->get_or_create_history(edited_scene[p_idx].history_id).undo_redo->get_version();
+ uint64_t current_scene_version = undo_redo_manager->get_or_create_history(edited_scene[p_idx].history_id).undo_redo->get_version();
bool is_changed = edited_scene[p_idx].last_checked_version != current_scene_version;
edited_scene.write[p_idx].last_checked_version = current_scene_version;
return is_changed;
@@ -425,10 +407,6 @@ int EditorData::get_scene_history_id(int p_idx) const {
return edited_scene[p_idx].history_id;
}
-Ref<EditorUndoRedoManager> &EditorData::get_undo_redo() {
- return undo_redo_manager;
-}
-
void EditorData::add_undo_redo_inspector_hook_callback(Callable p_callable) {
undo_redo_callbacks.push_back(p_callable);
}
@@ -998,6 +976,8 @@ void EditorData::script_class_set_name(const String &p_path, const StringName &p
}
void EditorData::script_class_save_icon_paths() {
+ Array script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+
Dictionary d;
for (const KeyValue<StringName, String> &E : _script_class_icon_paths) {
if (ScriptServer::is_global_class(E.key)) {
@@ -1005,27 +985,20 @@ void EditorData::script_class_save_icon_paths() {
}
}
- Dictionary old;
- if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
- old = GLOBAL_GET("_global_script_class_icons");
- }
- if ((!old.is_empty() || d.is_empty()) && d.hash() == old.hash()) {
- return;
- }
-
- if (d.is_empty()) {
- if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
- ProjectSettings::get_singleton()->clear("_global_script_class_icons");
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary d2 = script_classes[i];
+ if (!d2.has("class")) {
+ continue;
}
- } else {
- ProjectSettings::get_singleton()->set("_global_script_class_icons", d);
+ d2["icon"] = d.get(d2["class"], "");
}
- ProjectSettings::get_singleton()->save();
+ ProjectSettings::get_singleton()->store_global_class_list(script_classes);
}
void EditorData::script_class_load_icon_paths() {
script_class_clear_icon_paths();
+#ifndef DISABLE_DEPRECATED
if (ProjectSettings::get_singleton()->has_setting("_global_script_class_icons")) {
Dictionary d = GLOBAL_GET("_global_script_class_icons");
List<Variant> keys;
@@ -1038,15 +1011,33 @@ void EditorData::script_class_load_icon_paths() {
String path = ScriptServer::get_global_class_path(name);
script_class_set_name(path, name);
}
+ ProjectSettings::get_singleton()->clear("_global_script_class_icons");
+ }
+#endif
+
+ Array script_classes = ProjectSettings::get_singleton()->get_global_class_list();
+ for (int i = 0; i < script_classes.size(); i++) {
+ Dictionary d = script_classes[i];
+ if (!d.has("class") || !d.has("path") || !d.has("icon")) {
+ continue;
+ }
+
+ String name = d["class"];
+ _script_class_icon_paths[name] = d["icon"];
+ script_class_set_name(d["path"], name);
}
}
EditorData::EditorData() {
current_edited_scene = -1;
- undo_redo_manager.instantiate();
+ undo_redo_manager = memnew(EditorUndoRedoManager);
script_class_load_icon_paths();
}
+EditorData::~EditorData() {
+ memdelete(undo_redo_manager);
+}
+
///////////////////////////////////////////////////////////////////////////////
void EditorSelection::_node_removed(Node *p_node) {
diff --git a/editor/editor_data.h b/editor/editor_data.h
index 385bcad1f9..6a89b3572c 100644
--- a/editor/editor_data.h
+++ b/editor/editor_data.h
@@ -80,7 +80,6 @@ public:
// Gets an object from the history. The most recent object would be the object with p_obj = get_history_len() - 1.
ObjectID get_history_obj(int p_obj) const;
- bool is_history_obj_inspector_only(int p_obj) const;
bool next();
bool previous();
@@ -133,7 +132,7 @@ private:
HashMap<String, Vector<CustomType>> custom_types;
List<PropertyData> clipboard;
- Ref<EditorUndoRedoManager> undo_redo_manager;
+ EditorUndoRedoManager *undo_redo_manager;
Vector<Callable> undo_redo_callbacks;
HashMap<StringName, Callable> move_element_functions;
@@ -168,7 +167,6 @@ public:
int get_editor_plugin_count() const;
EditorPlugin *get_editor_plugin(int p_idx);
- Ref<EditorUndoRedoManager> &get_undo_redo();
void add_undo_redo_inspector_hook_callback(Callable p_callable); // Callbacks should have this signature: void (Object* undo_redo, Object *modified_object, String property, Variant new_value)
void remove_undo_redo_inspector_hook_callback(Callable p_callable);
const Vector<Callable> get_undo_redo_inspector_hook_callback();
@@ -178,7 +176,6 @@ public:
Callable get_move_array_element_function(const StringName &p_class) const;
void save_editor_global_states();
- void restore_editor_global_states();
void add_custom_type(const String &p_type, const String &p_inherits, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon);
Variant instantiate_custom_type(const String &p_type, const String &p_inherits);
@@ -245,6 +242,7 @@ public:
void script_class_load_icon_paths();
EditorData();
+ ~EditorData();
};
/**
diff --git a/editor/editor_file_system.cpp b/editor/editor_file_system.cpp
index 4efc7c3055..a9b4c08698 100644
--- a/editor/editor_file_system.cpp
+++ b/editor/editor_file_system.cpp
@@ -602,10 +602,19 @@ bool EditorFileSystem::_update_scan_actions() {
fs_changed = true;
+ if (ClassDB::is_parent_class(ia.new_file->type, SNAME("Script"))) {
+ _queue_update_script_class(ia.dir->get_file_path(idx));
+ }
+
} break;
case ItemAction::ACTION_FILE_REMOVE: {
int idx = ia.dir->find_file_index(ia.file);
ERR_CONTINUE(idx == -1);
+
+ if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
+ _queue_update_script_class(ia.dir->get_file_path(idx));
+ }
+
_delete_internal_files(ia.dir->files[idx]->file);
memdelete(ia.dir->files[idx]);
ia.dir->files.remove_at(idx);
@@ -640,6 +649,10 @@ bool EditorFileSystem::_update_scan_actions() {
ERR_CONTINUE(idx == -1);
String full_path = ia.dir->get_file_path(idx);
+ if (ClassDB::is_parent_class(ia.dir->files[idx]->type, SNAME("Script"))) {
+ _queue_update_script_class(full_path);
+ }
+
reloads.push_back(full_path);
} break;
@@ -708,9 +721,9 @@ void EditorFileSystem::scan() {
new_filesystem = nullptr;
_update_scan_actions();
scanning = false;
+ _update_pending_script_classes();
emit_signal(SNAME("filesystem_changed"));
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
- _queue_update_script_classes();
first_scan = false;
} else {
ERR_FAIL_COND(thread.is_started());
@@ -911,6 +924,10 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
fi->modified_time = mt;
fi->import_modified_time = 0;
fi->import_valid = true;
+
+ if (ClassDB::is_parent_class(fi->type, SNAME("Script"))) {
+ _queue_update_script_class(path);
+ }
}
}
@@ -922,20 +939,6 @@ void EditorFileSystem::_scan_new_dir(EditorFileSystemDirectory *p_dir, Ref<DirAc
}
}
- for (int i = 0; i < ScriptServer::get_language_count(); i++) {
- ScriptLanguage *lang = ScriptServer::get_language(i);
- if (lang->supports_documentation() && fi->type == lang->get_type()) {
- Ref<Script> scr = ResourceLoader::load(path);
- if (scr == nullptr) {
- continue;
- }
- Vector<DocData::ClassDoc> docs = scr->get_documentation();
- for (int j = 0; j < docs.size(); j++) {
- EditorHelp::get_doc_data()->add_doc(docs[j]);
- }
- }
- }
-
p_dir->files.push_back(fi);
p_progress.update(idx, total);
}
@@ -1176,7 +1179,9 @@ void EditorFileSystem::scan_changes() {
sp.low = 0;
scan_total = 0;
_scan_fs_changes(filesystem, sp);
- if (_update_scan_actions()) {
+ bool changed = _update_scan_actions();
+ _update_pending_script_classes();
+ if (changed) {
emit_signal(SNAME("filesystem_changed"));
}
}
@@ -1225,11 +1230,12 @@ void EditorFileSystem::_notification(int p_what) {
set_process(false);
thread_sources.wait_to_finish();
- if (_update_scan_actions()) {
+ bool changed = _update_scan_actions();
+ _update_pending_script_classes();
+ if (changed) {
emit_signal(SNAME("filesystem_changed"));
}
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
- _queue_update_script_classes();
first_scan = false;
}
} else if (!scanning && thread.is_started()) {
@@ -1242,9 +1248,9 @@ void EditorFileSystem::_notification(int p_what) {
new_filesystem = nullptr;
thread.wait_to_finish();
_update_scan_actions();
+ _update_pending_script_classes();
emit_signal(SNAME("filesystem_changed"));
emit_signal(SNAME("sources_changed"), sources_changed.size() > 0);
- _queue_update_script_classes();
first_scan = false;
}
@@ -1491,42 +1497,63 @@ String EditorFileSystem::_get_global_script_class(const String &p_type, const St
return String();
}
-void EditorFileSystem::_scan_script_classes(EditorFileSystemDirectory *p_dir) {
- int filecount = p_dir->files.size();
- const EditorFileSystemDirectory::FileInfo *const *files = p_dir->files.ptr();
- for (int i = 0; i < filecount; i++) {
- if (files[i]->script_class_name.is_empty()) {
+void EditorFileSystem::_update_script_classes() {
+ update_script_mutex.lock();
+
+ for (const String &path : update_script_paths) {
+ ScriptServer::remove_global_class_by_path(path); // First remove, just in case it changed
+
+ int index = -1;
+ EditorFileSystemDirectory *efd = find_file(path, &index);
+
+ if (!efd || index < 0) {
+ // The file was removed
continue;
}
- String lang;
- for (int j = 0; j < ScriptServer::get_language_count(); j++) {
- if (ScriptServer::get_language(j)->handles_global_class_type(files[i]->type)) {
- lang = ScriptServer::get_language(j)->get_name();
+ if (!efd->files[index]->script_class_name.is_empty()) {
+ String lang;
+ for (int j = 0; j < ScriptServer::get_language_count(); j++) {
+ if (ScriptServer::get_language(j)->handles_global_class_type(efd->files[index]->type)) {
+ lang = ScriptServer::get_language(j)->get_name();
+ }
}
+ if (lang.is_empty()) {
+ continue; // No lang found that can handle this global class
+ }
+
+ ScriptServer::add_global_class(efd->files[index]->script_class_name, efd->files[index]->script_class_extends, lang, path);
+ EditorNode::get_editor_data().script_class_set_icon_path(efd->files[index]->script_class_name, efd->files[index]->script_class_icon_path);
+ EditorNode::get_editor_data().script_class_set_name(efd->files[index]->file, efd->files[index]->script_class_name);
}
- ScriptServer::add_global_class(files[i]->script_class_name, files[i]->script_class_extends, lang, p_dir->get_file_path(i));
- EditorNode::get_editor_data().script_class_set_icon_path(files[i]->script_class_name, files[i]->script_class_icon_path);
- EditorNode::get_editor_data().script_class_set_name(files[i]->file, files[i]->script_class_name);
}
- for (int i = 0; i < p_dir->get_subdir_count(); i++) {
- _scan_script_classes(p_dir->get_subdir(i));
- }
-}
-void EditorFileSystem::update_script_classes() {
- if (!update_script_classes_queued.is_set()) {
- return;
- }
+ // Parse documentation second, as it requires the class names to be correct and registered
+ for (const String &path : update_script_paths) {
+ int index = -1;
+ EditorFileSystemDirectory *efd = find_file(path, &index);
- update_script_classes_queued.clear();
- ScriptServer::global_classes_clear();
- if (get_filesystem()) {
- _scan_script_classes(get_filesystem());
+ for (int i = 0; i < ScriptServer::get_language_count(); i++) {
+ ScriptLanguage *lang = ScriptServer::get_language(i);
+ if (lang->supports_documentation() && efd->files[index]->type == lang->get_type()) {
+ Ref<Script> scr = ResourceLoader::load(path);
+ if (scr.is_null()) {
+ continue;
+ }
+ Vector<DocData::ClassDoc> docs = scr->get_documentation();
+ for (int j = 0; j < docs.size(); j++) {
+ EditorHelp::get_doc_data()->add_doc(docs[j]);
+ }
+ }
+ }
}
+ update_script_paths.clear();
+ update_script_mutex.unlock();
+
ScriptServer::save_global_classes();
EditorNode::get_editor_data().script_class_save_icon_paths();
+ emit_signal("script_classes_updated");
// Rescan custom loaders and savers.
// Doing the following here because the `filesystem_changed` signal fires multiple times and isn't always followed by script classes update.
@@ -1537,13 +1564,16 @@ void EditorFileSystem::update_script_classes() {
ResourceSaver::add_custom_savers();
}
-void EditorFileSystem::_queue_update_script_classes() {
- if (update_script_classes_queued.is_set()) {
- return;
+void EditorFileSystem::_update_pending_script_classes() {
+ if (!update_script_paths.is_empty()) {
+ _update_script_classes();
}
+}
- update_script_classes_queued.set();
- call_deferred(SNAME("update_script_classes"));
+void EditorFileSystem::_queue_update_script_class(const String &p_path) {
+ update_script_mutex.lock();
+ update_script_paths.insert(p_path);
+ update_script_mutex.unlock();
}
void EditorFileSystem::update_file(const String &p_file) {
@@ -1565,12 +1595,16 @@ void EditorFileSystem::update_file(const String &p_file) {
ResourceUID::get_singleton()->remove_id(fs->files[cpos]->uid);
}
}
+ if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
+ _queue_update_script_class(p_file);
+ }
+
memdelete(fs->files[cpos]);
fs->files.remove_at(cpos);
}
+ _update_pending_script_classes();
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later
- _queue_update_script_classes();
return;
}
@@ -1630,8 +1664,12 @@ void EditorFileSystem::update_file(const String &p_file) {
// Update preview
EditorResourcePreview::get_singleton()->check_for_invalidation(p_file);
+ if (ClassDB::is_parent_class(fs->files[cpos]->type, SNAME("Script"))) {
+ _queue_update_script_class(p_file);
+ }
+
+ _update_pending_script_classes();
call_deferred(SNAME("emit_signal"), "filesystem_changed"); //update later
- _queue_update_script_classes();
}
HashSet<String> EditorFileSystem::get_valid_extensions() const {
@@ -2413,10 +2451,10 @@ void EditorFileSystem::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_file", "path"), &EditorFileSystem::update_file);
ClassDB::bind_method(D_METHOD("get_filesystem_path", "path"), &EditorFileSystem::get_filesystem_path);
ClassDB::bind_method(D_METHOD("get_file_type", "path"), &EditorFileSystem::get_file_type);
- ClassDB::bind_method(D_METHOD("update_script_classes"), &EditorFileSystem::update_script_classes);
ClassDB::bind_method(D_METHOD("reimport_files", "files"), &EditorFileSystem::reimport_files);
ADD_SIGNAL(MethodInfo("filesystem_changed"));
+ ADD_SIGNAL(MethodInfo("script_classes_updated"));
ADD_SIGNAL(MethodInfo("sources_changed", PropertyInfo(Variant::BOOL, "exist")));
ADD_SIGNAL(MethodInfo("resources_reimported", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources")));
ADD_SIGNAL(MethodInfo("resources_reload", PropertyInfo(Variant::PACKED_STRING_ARRAY, "resources")));
@@ -2472,7 +2510,6 @@ EditorFileSystem::EditorFileSystem() {
using_fat32_or_exfat = (da->get_filesystem_type() == "FAT32" || da->get_filesystem_type() == "exFAT");
scan_total = 0;
- update_script_classes_queued.clear();
MessageQueue::get_singleton()->push_callable(callable_mp(ResourceUID::get_singleton(), &ResourceUID::clear)); // Will be updated on scan.
ResourceSaver::set_get_resource_id_for_path(_resource_saver_get_resource_id_for_path);
}
diff --git a/editor/editor_file_system.h b/editor/editor_file_system.h
index 2985134093..03b1fb4a49 100644
--- a/editor/editor_file_system.h
+++ b/editor/editor_file_system.h
@@ -257,9 +257,11 @@ class EditorFileSystem : public Node {
}
};
- void _scan_script_classes(EditorFileSystemDirectory *p_dir);
- SafeFlag update_script_classes_queued;
- void _queue_update_script_classes();
+ Mutex update_script_mutex;
+ HashSet<String> update_script_paths;
+ void _queue_update_script_class(const String &p_path);
+ void _update_script_classes();
+ void _update_pending_script_classes();
String _get_global_script_class(const String &p_type, const String &p_path, String *r_extends, String *r_icon_path) const;
@@ -312,8 +314,6 @@ public:
void reimport_file_with_custom_parameters(const String &p_file, const String &p_importer, const HashMap<StringName, Variant> &p_custom_params);
- void update_script_classes();
-
bool is_group_file(const String &p_path) const;
void move_group_file(const String &p_path, const String &p_new_path);
diff --git a/editor/editor_help.cpp b/editor/editor_help.cpp
index 5baa58873e..9b1a5e028b 100644
--- a/editor/editor_help.cpp
+++ b/editor/editor_help.cpp
@@ -41,7 +41,7 @@
#include "editor/plugins/script_editor_plugin.h"
#include "scene/gui/line_edit.h"
-#define CONTRIBUTE_URL vformat("%s/community/contributing/updating_the_class_reference.html", VERSION_DOCS_URL)
+#define CONTRIBUTE_URL vformat("%s/contributing/documentation/updating_the_class_reference.html", VERSION_DOCS_URL)
DocTools *EditorHelp::doc = nullptr;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 8723354e84..035bd96f4d 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1680,13 +1680,13 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
} else {
action_name = vformat("Move element %d to position %d in property array with prefix %s.", p_element_index, p_to_pos, array_element_prefix);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(action_name);
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { undo_redo.ptr(), object, array_element_prefix, p_element_index, p_to_pos };
+ Variant args[] = { undo_redo, object, array_element_prefix, p_element_index, p_to_pos };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1824,14 +1824,14 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
}
void EditorInspectorArray::_clear_array() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat("Clear property array with prefix %s.", array_element_prefix));
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
for (int i = count - 1; i >= 0; i--) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 };
+ Variant args[] = { undo_redo, object, array_element_prefix, i, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1877,7 +1877,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat("Resize property array with prefix %s.", array_element_prefix));
if (p_size > count) {
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
@@ -1885,7 +1885,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { undo_redo.ptr(), object, array_element_prefix, -1, -1 };
+ Variant args[] = { undo_redo, object, array_element_prefix, -1, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -1904,7 +1904,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
// Call the function.
Callable move_function = EditorNode::get_singleton()->get_editor_data().get_move_array_element_function(object->get_class_name());
if (move_function.is_valid()) {
- Variant args[] = { undo_redo.ptr(), object, array_element_prefix, i, -1 };
+ Variant args[] = { undo_redo, object, array_element_prefix, i, -1 };
const Variant *args_p[] = { &args[0], &args[1], &args[2], &args[3], &args[4] };
Variant return_value;
Callable::CallError call_error;
@@ -2049,7 +2049,7 @@ void EditorInspectorArray::_setup() {
ae.panel = memnew(PanelContainer);
ae.panel->set_focus_mode(FOCUS_ALL);
ae.panel->set_mouse_filter(MOUSE_FILTER_PASS);
- ae.panel->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(ae.panel, EditorInspectorArray);
ae.panel->set_meta("index", begin_array_index + i);
ae.panel->set_tooltip_text(vformat(TTR("Element %d: %s%d*"), i, array_element_prefix, i));
ae.panel->connect("focus_entered", callable_mp((CanvasItem *)ae.panel, &PanelContainer::queue_redraw));
@@ -2220,10 +2220,6 @@ void EditorInspectorArray::_notification(int p_what) {
}
void EditorInspectorArray::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &EditorInspectorArray::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorInspectorArray::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorInspectorArray::drop_data_fw);
-
ADD_SIGNAL(MethodInfo("page_change_request"));
}
@@ -3552,8 +3548,8 @@ void EditorInspector::_edit_set(const String &p_name, const Variant &p_value, bo
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- if (!undo_redo.is_valid() || bool(object->call("_dont_undo_redo"))) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ if (bool(object->call("_dont_undo_redo"))) {
object->set(p_name, p_value);
if (p_refresh_all) {
_edit_request_change(object, "");
@@ -3673,7 +3669,7 @@ void EditorInspector::_multiple_properties_changed(Vector<String> p_paths, Array
}
names += p_paths[i];
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Multiple:") + " " + names, UndoRedo::MERGE_ENDS);
for (int i = 0; i < p_paths.size(); i++) {
_edit_set(p_paths[i], p_values[i], false, "");
@@ -3708,7 +3704,7 @@ void EditorInspector::_property_deleted(const String &p_path) {
if (p_path.begins_with("metadata/")) {
String name = p_path.replace_first("metadata/", "");
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove metadata %s"), name));
undo_redo->add_do_method(object, "remove_meta", name);
undo_redo->add_undo_method(object, "set_meta", name, object->get_meta(name));
@@ -3774,26 +3770,17 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
Node *node = Object::cast_to<Node>(object);
ERR_FAIL_COND(!node);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
- if (undo_redo.is_valid()) {
- undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path));
- undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned);
- undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
- if (editor_property_map.has(p_path)) {
- for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- undo_redo->add_do_method(E->get(), "_update_editor_property_status");
- undo_redo->add_undo_method(E->get(), "_update_editor_property_status");
- }
- }
- undo_redo->commit_action();
- } else {
- node->set_property_pinned(p_path, p_pinned);
- if (editor_property_map.has(p_path)) {
- for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
- E->get()->update_editor_property_status();
- }
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path));
+ undo_redo->add_do_method(node, "_set_property_pinned", p_path, p_pinned);
+ undo_redo->add_undo_method(node, "_set_property_pinned", p_path, !p_pinned);
+ if (editor_property_map.has(p_path)) {
+ for (List<EditorProperty *>::Element *E = editor_property_map[p_path].front(); E; E = E->next()) {
+ undo_redo->add_do_method(E->get(), "_update_editor_property_status");
+ undo_redo->add_undo_method(E->get(), "_update_editor_property_status");
}
}
+ undo_redo->commit_action();
}
void EditorInspector::_property_selected(const String &p_path, int p_focusable) {
@@ -3972,7 +3959,7 @@ void EditorInspector::_add_meta_confirm() {
Variant defval;
Callable::CallError ce;
Variant::construct(Variant::Type(add_meta_type->get_selected_id()), defval, nullptr, 0, ce);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add metadata %s"), name));
undo_redo->add_do_method(object, "set_meta", name, defval);
undo_redo->add_undo_method(object, "remove_meta", name);
diff --git a/editor/editor_locale_dialog.cpp b/editor/editor_locale_dialog.cpp
index d57b3b66cc..5a372412fa 100644
--- a/editor/editor_locale_dialog.cpp
+++ b/editor/editor_locale_dialog.cpp
@@ -31,7 +31,6 @@
#include "editor_locale_dialog.h"
#include "core/config/project_settings.h"
-#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
#include "scene/gui/check_button.h"
@@ -141,7 +140,7 @@ void EditorLocaleDialog::_filter_lang_option_changed() {
f_lang_all.sort();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Changed Locale Language Filter"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/language_filter", f_lang_all);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/language_filter", prev);
@@ -175,7 +174,7 @@ void EditorLocaleDialog::_filter_script_option_changed() {
f_script_all.sort();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Changed Locale Script Filter"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/script_filter", f_script_all);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/script_filter", prev);
@@ -209,7 +208,7 @@ void EditorLocaleDialog::_filter_cnt_option_changed() {
f_cnt_all.sort();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Changed Locale Country Filter"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/country_filter", f_cnt_all);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/country_filter", prev);
@@ -224,7 +223,7 @@ void EditorLocaleDialog::_filter_mode_changed(int p_mode) {
prev = GLOBAL_GET("internationalization/locale/locale_filter_mode");
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Changed Locale Filter Mode"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter_mode", f_mode);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/locale_filter_mode", prev);
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index ae9261864f..b0278030f9 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -288,7 +288,7 @@ void EditorNode::_update_scene_tabs() {
icon = EditorNode::get_singleton()->get_object_icon(type_node, "Node");
}
- bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
+ bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(i));
scene_tabs->add_tab(disambiguated_scene_names[i] + (unsaved ? "(*)" : ""), icon);
if (DisplayServer::get_singleton()->has_feature(DisplayServer::FEATURE_GLOBAL_MENU)) {
@@ -533,8 +533,8 @@ void EditorNode::_notification(int p_what) {
opening_prev = false;
}
- bool global_unsaved = get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY);
- bool scene_or_global_unsaved = global_unsaved || get_undo_redo()->is_history_unsaved(editor_data.get_current_edited_scene_history_id());
+ bool global_unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY);
+ bool scene_or_global_unsaved = global_unsaved || EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_current_edited_scene_history_id());
if (unsaved_cache != scene_or_global_unsaved) {
unsaved_cache = scene_or_global_unsaved;
_update_title();
@@ -584,10 +584,11 @@ void EditorNode::_notification(int p_what) {
case NOTIFICATION_ENTER_TREE: {
Engine::get_singleton()->set_editor_hint(true);
- Window *window = static_cast<Window *>(get_tree()->get_root());
+ Window *window = get_window();
if (window) {
// Handle macOS fullscreen and extend-to-title changes.
window->connect("titlebar_changed", callable_mp(this, &EditorNode::_titlebar_resized));
+ window->set_theme(theme);
}
OS::get_singleton()->set_low_processor_usage_mode_sleep_usec(int(EDITOR_GET("interface/editor/low_processor_mode_sleep_usec")));
@@ -633,6 +634,10 @@ void EditorNode::_notification(int p_what) {
set_addon_plugin_enabled(addons[i], true);
}
_initializing_plugins = false;
+
+ if (!pending_addons.is_empty()) {
+ EditorFileSystem::get_singleton()->connect("script_classes_updated", callable_mp(this, &EditorNode::_enable_pending_addons));
+ }
}
RenderingServer::get_singleton()->viewport_set_disable_2d(get_scene_root()->get_viewport_rid(), true);
@@ -695,6 +700,7 @@ void EditorNode::_notification(int p_what) {
theme_base->set_theme(theme);
gui_base->set_theme(theme);
+ get_window()->set_theme(theme);
gui_base->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Background"), SNAME("EditorStyles")));
scene_root_parent->add_theme_style_override("panel", gui_base->get_theme_stylebox(SNAME("Content"), SNAME("EditorStyles")));
@@ -1128,7 +1134,7 @@ void EditorNode::_version_button_pressed() {
}
void EditorNode::_update_undo_redo_allowed() {
- Ref<EditorUndoRedoManager> undo_redo = get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
file_menu->set_item_disabled(file_menu->get_item_index(EDIT_UNDO), !undo_redo->has_undo());
file_menu->set_item_disabled(file_menu->get_item_index(EDIT_REDO), !undo_redo->has_redo());
}
@@ -1680,7 +1686,7 @@ int EditorNode::_save_external_resources() {
saved++;
}
- get_undo_redo()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY);
+ EditorUndoRedoManager::get_singleton()->set_history_as_saved(EditorUndoRedoManager::GLOBAL_HISTORY);
return saved;
}
@@ -1857,7 +1863,7 @@ void EditorNode::_mark_unsaved_scenes() {
String path = node->get_scene_file_path();
if (!path.is_empty() && !FileAccess::exists(path)) {
// Mark scene tab as unsaved if the file is gone.
- get_undo_redo()->set_history_as_unsaved(editor_data.get_scene_history_id(i));
+ EditorUndoRedoManager::get_singleton()->set_history_as_unsaved(editor_data.get_scene_history_id(i));
}
}
@@ -2744,9 +2750,10 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message(TTR("Can't undo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
} else {
- String action = editor_data.get_undo_redo()->get_current_action_name();
- int id = editor_data.get_undo_redo()->get_current_action_history_id();
- if (!editor_data.get_undo_redo()->undo()) {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
+ String action = undo_redo->get_current_action_name();
+ int id = undo_redo->get_current_action_history_id();
+ if (!undo_redo->undo()) {
log->add_message(TTR("Nothing to undo."), EditorLog::MSG_TYPE_EDITOR);
} else if (!action.is_empty()) {
switch (id) {
@@ -2763,18 +2770,19 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
}
} break;
case EDIT_REDO: {
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if ((int)Input::get_singleton()->get_mouse_button_mask() & 0x7) {
log->add_message(TTR("Can't redo while mouse buttons are pressed."), EditorLog::MSG_TYPE_EDITOR);
} else {
- if (!editor_data.get_undo_redo()->redo()) {
+ if (!undo_redo->redo()) {
log->add_message(TTR("Nothing to redo."), EditorLog::MSG_TYPE_EDITOR);
} else {
- String action = editor_data.get_undo_redo()->get_current_action_name();
+ String action = undo_redo->get_current_action_name();
if (action.is_empty()) {
break;
}
- switch (editor_data.get_undo_redo()->get_current_action_history_id()) {
+ switch (undo_redo->get_current_action_history_id()) {
case EditorUndoRedoManager::GLOBAL_HISTORY:
log->add_message(vformat(TTR("Global Redo: %s"), action), EditorLog::MSG_TYPE_EDITOR);
break;
@@ -2817,7 +2825,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
ERR_PRINT("Failed to load scene");
}
editor_data.move_edited_scene_to_index(cur_idx);
- get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id());
+ EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id());
scene_tabs->set_current_tab(cur_idx);
} break;
@@ -2909,7 +2917,7 @@ void EditorNode::_menu_option_confirm(int p_option, bool p_confirmed) {
case RELOAD_CURRENT_PROJECT: {
if (!p_confirmed) {
bool save_each = EDITOR_GET("interface/editor/save_each_scene_on_quit");
- if (_next_unsaved_scene(!save_each) == -1 && !get_undo_redo()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY)) {
+ if (_next_unsaved_scene(!save_each) == -1 && !EditorUndoRedoManager::get_singleton()->is_history_unsaved(EditorUndoRedoManager::GLOBAL_HISTORY)) {
_discard_changes();
break;
} else {
@@ -3148,7 +3156,7 @@ int EditorNode::_next_unsaved_scene(bool p_valid_filename, int p_start) {
if (!editor_data.get_edited_scene_root(i)) {
continue;
}
- bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
+ bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(i));
if (unsaved) {
String scene_filename = editor_data.get_edited_scene_root(i)->get_scene_file_path();
if (p_valid_filename && scene_filename.length() == 0) {
@@ -3469,6 +3477,12 @@ void EditorNode::set_addon_plugin_enabled(const String &p_addon, bool p_enabled,
// Errors in the script cause the base_type to be an empty StringName.
if (scr->get_instance_base_type() == StringName()) {
+ if (_initializing_plugins) {
+ // However, if it happens during initialization, waiting for file scan might help.
+ pending_addons.push_back(p_addon);
+ return;
+ }
+
show_warning(vformat(TTR("Unable to load addon script from path: '%s'. This might be due to a code error in that script.\nDisabling the addon at '%s' to prevent further errors."), script_path, addon_path));
_remove_plugin_from_enabled(addon_path);
return;
@@ -3657,7 +3671,7 @@ void EditorNode::set_current_scene(int p_idx) {
editor_folding.load_scene_folding(editor_data.get_edited_scene_root(p_idx), editor_data.get_scene_path(p_idx));
}
- get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(p_idx));
+ EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_scene_history_id(p_idx));
}
changing_scene = true;
@@ -3724,7 +3738,7 @@ int EditorNode::new_scene() {
// Remove placeholder empty scene.
if (editor_data.get_edited_scene_count() > 1) {
for (int i = 0; i < editor_data.get_edited_scene_count() - 1; i++) {
- bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(i));
+ bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(i));
if (!unsaved && editor_data.get_scene_path(i).is_empty() && editor_data.get_edited_scene_root(i) == nullptr) {
editor_data.remove_scene(i);
idx--;
@@ -3949,10 +3963,6 @@ void EditorNode::request_instantiate_scenes(const Vector<String> &p_files) {
SceneTreeDock::get_singleton()->instantiate_scenes(p_files);
}
-Ref<EditorUndoRedoManager> &EditorNode::get_undo_redo() {
- return singleton->editor_data.get_undo_redo();
-}
-
void EditorNode::_inherit_request(String p_file) {
current_menu_option = FILE_NEW_INHERITED_SCENE;
_dialog_action(p_file);
@@ -4378,6 +4388,13 @@ void EditorNode::_build_icon_type_cache() {
}
}
+void EditorNode::_enable_pending_addons() {
+ for (uint32_t i = 0; i < pending_addons.size(); i++) {
+ set_addon_plugin_enabled(pending_addons[i], true);
+ }
+ pending_addons.clear();
+}
+
void EditorNode::_file_dialog_register(FileDialog *p_dialog) {
singleton->file_dialogs.insert(p_dialog);
}
@@ -5065,8 +5082,8 @@ bool EditorNode::ensure_main_scene(bool p_from_native) {
return true;
}
-Error EditorNode::run_play_native(int p_idx, int p_platform) {
- return run_native->run_native(p_idx, p_platform);
+Error EditorNode::run_play_native(int p_id) {
+ return run_native->run_native(p_id);
}
void EditorNode::run_play() {
@@ -5222,7 +5239,7 @@ void EditorNode::_scene_tab_closed(int p_tab, int option) {
return;
}
- bool unsaved = get_undo_redo()->is_history_unsaved(editor_data.get_scene_history_id(p_tab));
+ bool unsaved = EditorUndoRedoManager::get_singleton()->is_history_unsaved(editor_data.get_scene_history_id(p_tab));
if (unsaved) {
save_confirmation->set_ok_button_text(TTR("Save & Close"));
save_confirmation->set_text(vformat(TTR("Save changes to '%s' before closing?"), !scene->get_scene_file_path().is_empty() ? scene->get_scene_file_path() : "unsaved scene"));
@@ -5721,7 +5738,7 @@ void EditorNode::reload_scene(const String &p_path) {
if (scene_idx == -1) {
if (get_edited_scene()) {
// Scene is not open, so at it might be instantiated. We'll refresh the whole scene later.
- editor_data.get_undo_redo()->clear_history(false, editor_data.get_current_edited_scene_history_id());
+ EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_current_edited_scene_history_id());
}
return;
}
@@ -5737,7 +5754,7 @@ void EditorNode::reload_scene(const String &p_path) {
// Adjust index so tab is back a the previous position.
editor_data.move_edited_scene_to_index(scene_idx);
- get_undo_redo()->clear_history(false, editor_data.get_scene_history_id(scene_idx));
+ EditorUndoRedoManager::get_singleton()->clear_history(false, editor_data.get_scene_history_id(scene_idx));
// Recover the tab.
scene_tabs->set_current_tab(current_tab);
@@ -6055,8 +6072,8 @@ EditorNode::EditorNode() {
singleton = this;
- get_undo_redo()->connect("version_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed));
- get_undo_redo()->connect("history_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed));
+ EditorUndoRedoManager::get_singleton()->connect("version_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed));
+ EditorUndoRedoManager::get_singleton()->connect("history_changed", callable_mp(this, &EditorNode::_update_undo_redo_allowed));
TranslationServer::get_singleton()->set_enabled(false);
// Load settings.
@@ -7051,8 +7068,8 @@ EditorNode::EditorNode() {
right_r_vsplit->hide();
// Add some offsets to left_r and main hsplits to make LEFT_R and RIGHT_L docks wider than minsize.
- left_r_hsplit->set_split_offset(70 * EDSCALE);
- main_hsplit->set_split_offset(-70 * EDSCALE);
+ left_r_hsplit->set_split_offset(270 * EDSCALE);
+ main_hsplit->set_split_offset(-270 * EDSCALE);
// Define corresponding default layout.
@@ -7067,8 +7084,8 @@ EditorNode::EditorNode() {
default_layout->set_value(docks_section, "dock_split_" + itos(i + 1), 0);
}
default_layout->set_value(docks_section, "dock_hsplit_1", 0);
- default_layout->set_value(docks_section, "dock_hsplit_2", 70 * EDSCALE);
- default_layout->set_value(docks_section, "dock_hsplit_3", -70 * EDSCALE);
+ default_layout->set_value(docks_section, "dock_hsplit_2", 270 * EDSCALE);
+ default_layout->set_value(docks_section, "dock_hsplit_3", -270 * EDSCALE);
default_layout->set_value(docks_section, "dock_hsplit_4", 0);
_update_layouts_menu();
@@ -7383,7 +7400,6 @@ EditorNode::EditorNode() {
_update_recent_scenes();
- editor_data.restore_editor_global_states();
set_process_shortcut_input(true);
load_errors = memnew(RichTextLabel);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index ae951808d5..fb2544c141 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -292,6 +292,7 @@ private:
Vector<EditorPlugin *> editor_plugins;
bool _initializing_plugins = false;
HashMap<String, EditorPlugin *> addon_name_to_plugin;
+ LocalVector<String> pending_addons;
PanelContainer *scene_root_parent = nullptr;
Control *theme_base = nullptr;
@@ -535,6 +536,7 @@ private:
static void _resource_loaded(Ref<Resource> p_resource, const String &p_path);
void _build_icon_type_cache();
+ void _enable_pending_addons();
void _dialog_action(String p_file);
@@ -729,7 +731,6 @@ public:
static EditorLog *get_log() { return singleton->log; }
static EditorData &get_editor_data() { return singleton->editor_data; }
static EditorFolding &get_editor_folding() { return singleton->editor_folding; }
- static Ref<EditorUndoRedoManager> &get_undo_redo();
static HBoxContainer *get_menu_hb() { return singleton->menu_hb; }
static VSplitContainer *get_top_split() { return singleton->top_split; }
@@ -914,7 +915,7 @@ public:
bool ensure_main_scene(bool p_from_native);
- Error run_play_native(int p_idx, int p_platform);
+ Error run_play_native(int p_id);
void run_play();
void run_play_current();
void run_play_custom(const String &p_custom);
diff --git a/editor/editor_plugin.cpp b/editor/editor_plugin.cpp
index a5d1ddb2fa..7f02148dfc 100644
--- a/editor/editor_plugin.cpp
+++ b/editor/editor_plugin.cpp
@@ -45,6 +45,7 @@
#include "editor/inspector_dock.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/editor_debugger_plugin.h"
+#include "editor/plugins/editor_resource_conversion_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "editor/plugins/script_editor_plugin.h"
#include "editor/project_settings_editor.h"
@@ -711,9 +712,6 @@ bool EditorPlugin::get_remove_list(List<Node *> *p_list) {
return false;
}
-void EditorPlugin::restore_global_state() {}
-void EditorPlugin::save_global_state() {}
-
void EditorPlugin::add_undo_redo_inspector_hook_callback(Callable p_callable) {
EditorNode::get_singleton()->get_editor_data().add_undo_redo_inspector_hook_callback(p_callable);
}
@@ -856,6 +854,14 @@ void EditorPlugin::remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plu
EditorDebuggerNode::get_singleton()->remove_debugger_plugin(p_plugin);
}
+void EditorPlugin::add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin) {
+ EditorNode::get_singleton()->add_resource_conversion_plugin(p_plugin);
+}
+
+void EditorPlugin::remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin) {
+ EditorNode::get_singleton()->remove_resource_conversion_plugin(p_plugin);
+}
+
void EditorPlugin::_editor_project_settings_changed() {
emit_signal(SNAME("project_settings_changed"));
}
@@ -911,6 +917,8 @@ void EditorPlugin::_bind_methods() {
ClassDB::bind_method(D_METHOD("remove_node_3d_gizmo_plugin", "plugin"), &EditorPlugin::remove_node_3d_gizmo_plugin);
ClassDB::bind_method(D_METHOD("add_inspector_plugin", "plugin"), &EditorPlugin::add_inspector_plugin);
ClassDB::bind_method(D_METHOD("remove_inspector_plugin", "plugin"), &EditorPlugin::remove_inspector_plugin);
+ ClassDB::bind_method(D_METHOD("add_resource_conversion_plugin", "plugin"), &EditorPlugin::add_resource_conversion_plugin);
+ ClassDB::bind_method(D_METHOD("remove_resource_conversion_plugin", "plugin"), &EditorPlugin::remove_resource_conversion_plugin);
ClassDB::bind_method(D_METHOD("set_input_event_forwarding_always_enabled"), &EditorPlugin::set_input_event_forwarding_always_enabled);
ClassDB::bind_method(D_METHOD("set_force_draw_over_forwarding_enabled"), &EditorPlugin::set_force_draw_over_forwarding_enabled);
@@ -977,8 +985,8 @@ void EditorPlugin::_bind_methods() {
BIND_ENUM_CONSTANT(AFTER_GUI_INPUT_CUSTOM);
}
-Ref<EditorUndoRedoManager> EditorPlugin::get_undo_redo() {
- return EditorNode::get_undo_redo();
+EditorUndoRedoManager *EditorPlugin::get_undo_redo() {
+ return EditorUndoRedoManager::get_singleton();
}
EditorPluginCreateFunc EditorPlugins::creation_funcs[MAX_CREATE_FUNCS];
diff --git a/editor/editor_plugin.h b/editor/editor_plugin.h
index 33081e867a..a5a17acdf1 100644
--- a/editor/editor_plugin.h
+++ b/editor/editor_plugin.h
@@ -48,6 +48,7 @@ class EditorInspector;
class EditorInspectorPlugin;
class EditorNode3DGizmoPlugin;
class EditorPaths;
+class EditorResourceConversionPlugin;
class EditorResourcePreview;
class EditorSceneFormatImporter;
class EditorScenePostImportPlugin;
@@ -148,7 +149,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
- Ref<EditorUndoRedoManager> get_undo_redo();
+ EditorUndoRedoManager *get_undo_redo();
void add_custom_type(const String &p_type, const String &p_base, const Ref<Script> &p_script, const Ref<Texture2D> &p_icon);
void remove_custom_type(const String &p_type);
@@ -277,9 +278,6 @@ public:
void make_bottom_panel_item_visible(Control *p_item);
void hide_bottom_panel();
- virtual void restore_global_state();
- virtual void save_global_state();
-
void add_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser);
void remove_translation_parser_plugin(const Ref<EditorTranslationParserPlugin> &p_parser);
@@ -307,6 +305,9 @@ public:
void add_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
void remove_debugger_plugin(const Ref<EditorDebuggerPlugin> &p_plugin);
+ void add_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
+ void remove_resource_conversion_plugin(const Ref<EditorResourceConversionPlugin> &p_plugin);
+
void enable_plugin();
void disable_plugin();
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 6c917a0c4f..46f52ec4af 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -342,12 +342,17 @@ void EditorPropertyTextEnum::_notification(int p_what) {
}
EditorPropertyTextEnum::EditorPropertyTextEnum() {
+ HBoxContainer *hb = memnew(HBoxContainer);
+ add_child(hb);
+
default_layout = memnew(HBoxContainer);
- add_child(default_layout);
+ default_layout->set_h_size_flags(SIZE_EXPAND_FILL);
+ hb->add_child(default_layout);
edit_custom_layout = memnew(HBoxContainer);
+ edit_custom_layout->set_h_size_flags(SIZE_EXPAND_FILL);
edit_custom_layout->hide();
- add_child(edit_custom_layout);
+ hb->add_child(edit_custom_layout);
option_button = memnew(OptionButton);
option_button->set_h_size_flags(SIZE_EXPAND_FILL);
@@ -561,15 +566,13 @@ bool EditorPropertyPath::_can_drop_data_fw(const Point2 &p_point, const Variant
}
void EditorPropertyPath::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorPropertyPath::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorPropertyPath::_drop_data_fw);
}
EditorPropertyPath::EditorPropertyPath() {
HBoxContainer *path_hb = memnew(HBoxContainer);
add_child(path_hb);
path = memnew(LineEdit);
- path->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CDU(path, EditorPropertyPath);
path->set_structured_text_bidi_override(TextServer::STRUCTURED_TEXT_FILE);
path_hb->add_child(path);
path->connect("text_submitted", callable_mp(this, &EditorPropertyPath::_path_selected));
@@ -3673,8 +3676,6 @@ void EditorPropertyNodePath::_notification(int p_what) {
}
void EditorPropertyNodePath::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorPropertyNodePath::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorPropertyNodePath::drop_data_fw);
}
EditorPropertyNodePath::EditorPropertyNodePath() {
@@ -3686,7 +3687,7 @@ EditorPropertyNodePath::EditorPropertyNodePath() {
assign->set_h_size_flags(SIZE_EXPAND_FILL);
assign->set_clip_text(true);
assign->connect("pressed", callable_mp(this, &EditorPropertyNodePath::_node_assign));
- assign->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CD(assign, EditorPropertyNodePath);
hbc->add_child(assign);
clear = memnew(Button);
@@ -3805,6 +3806,8 @@ static bool _find_recursive_resources(const Variant &v, HashSet<Resource *> &res
return true;
}
}
+
+ resources_found.erase(r.ptr());
} break;
default: {
}
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 069e80fc05..28c0b047d8 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -702,8 +702,6 @@ void EditorPropertyArray::_reorder_button_up() {
}
void EditorPropertyArray::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorPropertyArray::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorPropertyArray::drop_data_fw);
}
EditorPropertyArray::EditorPropertyArray() {
@@ -715,7 +713,7 @@ EditorPropertyArray::EditorPropertyArray() {
edit->set_clip_text(true);
edit->connect("pressed", callable_mp(this, &EditorPropertyArray::_edit_pressed));
edit->set_toggle_mode(true);
- edit->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CD(edit, EditorPropertyArray);
edit->connect("draw", callable_mp(this, &EditorPropertyArray::_button_draw));
add_child(edit);
add_focusable(edit);
diff --git a/editor/editor_resource_picker.cpp b/editor/editor_resource_picker.cpp
index 81b2fff97a..a1c913aadd 100644
--- a/editor/editor_resource_picker.cpp
+++ b/editor/editor_resource_picker.cpp
@@ -772,9 +772,6 @@ void EditorResourcePicker::drop_data_fw(const Point2 &p_point, const Variant &p_
void EditorResourcePicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_resource_preview"), &EditorResourcePicker::_update_resource_preview);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &EditorResourcePicker::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &EditorResourcePicker::drop_data_fw);
ClassDB::bind_method(D_METHOD("set_base_type", "base_type"), &EditorResourcePicker::set_base_type);
ClassDB::bind_method(D_METHOD("get_base_type"), &EditorResourcePicker::get_base_type);
@@ -950,7 +947,7 @@ EditorResourcePicker::EditorResourcePicker(bool p_hide_assign_button_controls) {
assign_button->set_flat(true);
assign_button->set_h_size_flags(SIZE_EXPAND_FILL);
assign_button->set_clip_text(true);
- assign_button->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(assign_button, EditorResourcePicker);
add_child(assign_button);
assign_button->connect("pressed", callable_mp(this, &EditorResourcePicker::_resource_selected));
assign_button->connect("draw", callable_mp(this, &EditorResourcePicker::_button_draw));
diff --git a/editor/editor_run_native.cpp b/editor/editor_run_native.cpp
index eab4e08cec..0628dc7116 100644
--- a/editor/editor_run_native.cpp
+++ b/editor/editor_run_native.cpp
@@ -37,56 +37,38 @@
void EditorRunNative::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE: {
- for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
- Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(i);
- if (eep.is_null()) {
- continue;
- }
- Ref<ImageTexture> icon = eep->get_run_icon();
- if (!icon.is_null()) {
- Ref<Image> im = icon->get_image();
- im = im->duplicate();
- im->clear_mipmaps();
- if (!im->is_empty()) {
- im->resize(16 * EDSCALE, 16 * EDSCALE);
- Ref<ImageTexture> small_icon = ImageTexture::create_from_image(im);
- MenuButton *mb = memnew(MenuButton);
- mb->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native).bind(i));
- mb->connect("pressed", callable_mp(this, &EditorRunNative::run_native).bind(-1, i));
- mb->set_icon(small_icon);
- add_child(mb);
- menus[i] = mb;
- }
- }
- }
+ case NOTIFICATION_THEME_CHANGED: {
+ remote_debug->set_icon(get_theme_icon(SNAME("PlayRemote"), SNAME("EditorIcons")));
} break;
-
case NOTIFICATION_PROCESS: {
bool changed = EditorExport::get_singleton()->poll_export_platforms() || first;
if (changed) {
- for (KeyValue<int, MenuButton *> &E : menus) {
- Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(E.key);
- MenuButton *mb = E.value;
- int dc = eep->get_options_count();
-
- if (dc == 0) {
- mb->hide();
- } else {
- mb->get_popup()->clear();
- mb->show();
- if (dc == 1) {
- mb->set_tooltip_text(eep->get_option_tooltip(0));
- } else {
- mb->set_tooltip_text(eep->get_options_tooltip());
- for (int i = 0; i < dc; i++) {
- mb->get_popup()->add_icon_item(eep->get_option_icon(i), eep->get_option_label(i));
- mb->get_popup()->set_item_tooltip(-1, eep->get_option_tooltip(i));
- }
+ PopupMenu *popup = remote_debug->get_popup();
+ popup->clear();
+ for (int i = 0; i < EditorExport::get_singleton()->get_export_platform_count(); i++) {
+ Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(i);
+ if (eep.is_null()) {
+ continue;
+ }
+ int dc = MIN(eep->get_options_count(), 9000);
+ if (dc > 0) {
+ popup->add_icon_item(eep->get_run_icon(), eep->get_name(), -1);
+ popup->set_item_disabled(-1, true);
+ for (int j = 0; j < dc; j++) {
+ popup->add_icon_item(eep->get_option_icon(j), eep->get_option_label(j), 10000 * i + j);
+ popup->set_item_tooltip(-1, eep->get_option_tooltip(j));
+ popup->set_item_indent(-1, 2);
}
}
}
+ if (popup->get_item_count() == 0) {
+ remote_debug->set_disabled(true);
+ remote_debug->set_tooltip_text(TTR("No Remote Debug export presets configured."));
+ } else {
+ remote_debug->set_disabled(false);
+ remote_debug->set_tooltip_text(TTR("Remote Debug"));
+ }
first = false;
}
@@ -94,25 +76,22 @@ void EditorRunNative::_notification(int p_what) {
}
}
-Error EditorRunNative::run_native(int p_idx, int p_platform) {
- if (!EditorNode::get_singleton()->ensure_main_scene(true)) {
- resume_idx = p_idx;
- resume_platform = p_platform;
+Error EditorRunNative::run_native(int p_id) {
+ if (p_id < 0) {
return OK;
}
- Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(p_platform);
- ERR_FAIL_COND_V(eep.is_null(), ERR_UNAVAILABLE);
+ int platform = p_id / 10000;
+ int idx = p_id % 10000;
- if (p_idx == -1) {
- if (eep->get_options_count() == 1) {
- menus[p_platform]->get_popup()->hide();
- p_idx = 0;
- } else {
- return ERR_INVALID_PARAMETER;
- }
+ if (!EditorNode::get_singleton()->ensure_main_scene(true)) {
+ resume_id = p_id;
+ return OK;
}
+ Ref<EditorExportPlatform> eep = EditorExport::get_singleton()->get_export_platform(platform);
+ ERR_FAIL_COND_V(eep.is_null(), ERR_UNAVAILABLE);
+
Ref<EditorExportPreset> preset;
for (int i = 0; i < EditorExport::get_singleton()->get_export_preset_count(); i++) {
@@ -151,7 +130,7 @@ Error EditorRunNative::run_native(int p_idx, int p_platform) {
}
eep->clear_messages();
- Error err = eep->run(preset, p_idx, flags);
+ Error err = eep->run(preset, idx, flags);
result_dialog_log->clear();
if (eep->fill_log_messages(result_dialog_log, err)) {
if (eep->get_worst_message_type() >= EditorExportPlatform::EXPORT_MESSAGE_ERROR) {
@@ -162,7 +141,7 @@ Error EditorRunNative::run_native(int p_idx, int p_platform) {
}
void EditorRunNative::resume_run_native() {
- run_native(resume_idx, resume_platform);
+ run_native(resume_id);
}
void EditorRunNative::_bind_methods() {
@@ -174,6 +153,14 @@ bool EditorRunNative::is_deploy_debug_remote_enabled() const {
}
EditorRunNative::EditorRunNative() {
+ remote_debug = memnew(MenuButton);
+ remote_debug->get_popup()->connect("id_pressed", callable_mp(this, &EditorRunNative::run_native));
+ remote_debug->set_icon(get_theme_icon(SNAME("PlayRemote"), SNAME("EditorIcons")));
+ remote_debug->set_tooltip_text(TTR("Remote Debug"));
+ remote_debug->set_disabled(true);
+
+ add_child(remote_debug);
+
result_dialog = memnew(AcceptDialog);
result_dialog->set_title(TTR("Project Run"));
result_dialog_log = memnew(RichTextLabel);
@@ -184,6 +171,4 @@ EditorRunNative::EditorRunNative() {
result_dialog->hide();
set_process(true);
- resume_idx = 0;
- resume_platform = 0;
}
diff --git a/editor/editor_run_native.h b/editor/editor_run_native.h
index a87e27de97..2a5431e54b 100644
--- a/editor/editor_run_native.h
+++ b/editor/editor_run_native.h
@@ -42,18 +42,17 @@ class EditorRunNative : public HBoxContainer {
RichTextLabel *result_dialog_log = nullptr;
AcceptDialog *result_dialog = nullptr;
- HashMap<int, MenuButton *> menus;
+ MenuButton *remote_debug = nullptr;
bool first = true;
- int resume_idx;
- int resume_platform;
+ int resume_id = -1;
protected:
static void _bind_methods();
void _notification(int p_what);
public:
- Error run_native(int p_idx, int p_platform);
+ Error run_native(int p_id);
bool is_deploy_debug_remote_enabled() const;
void resume_run_native();
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 2881302775..ad614b1769 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -132,7 +132,7 @@ void EditorSettingsDialog::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_method_notify_callback(EditorDebuggerNode::_method_changeds, nullptr);
undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_property_notify_callback(EditorDebuggerNode::_property_changeds, nullptr);
undo_redo->get_or_create_history(EditorUndoRedoManager::GLOBAL_HISTORY).undo_redo->set_commit_notify_callback(_undo_redo_callback, this);
@@ -161,7 +161,7 @@ void EditorSettingsDialog::_notification(int p_what) {
void EditorSettingsDialog::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
const Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed()) {
@@ -232,7 +232,7 @@ void EditorSettingsDialog::_event_config_confirmed() {
void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Array &p_events) {
Array old_input_array = EditorSettings::get_singleton()->get_builtin_action_overrides(p_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Built-in Action") + " '" + p_name + "'");
undo_redo->add_do_method(EditorSettings::get_singleton(), "mark_setting_changed", "builtin_action_overrides");
undo_redo->add_undo_method(EditorSettings::get_singleton(), "mark_setting_changed", "builtin_action_overrides");
@@ -248,7 +248,7 @@ void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Ar
void EditorSettingsDialog::_update_shortcut_events(const String &p_path, const Array &p_events) {
Ref<Shortcut> current_sc = EditorSettings::get_singleton()->get_shortcut(p_path);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Shortcut") + " '" + p_path + "'");
undo_redo->add_do_method(current_sc.ptr(), "set_events", p_events);
undo_redo->add_undo_method(current_sc.ptr(), "set_events", current_sc->get_events());
@@ -694,10 +694,6 @@ void EditorSettingsDialog::_editor_restart_close() {
void EditorSettingsDialog::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_shortcuts"), &EditorSettingsDialog::_update_shortcuts);
ClassDB::bind_method(D_METHOD("_settings_changed"), &EditorSettingsDialog::_settings_changed);
-
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &EditorSettingsDialog::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &EditorSettingsDialog::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &EditorSettingsDialog::drop_data_fw);
}
EditorSettingsDialog::EditorSettingsDialog() {
@@ -793,7 +789,7 @@ EditorSettingsDialog::EditorSettingsDialog() {
shortcuts->connect("item_activated", callable_mp(this, &EditorSettingsDialog::_shortcut_cell_double_clicked));
tab_shortcuts->add_child(shortcuts);
- shortcuts->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(shortcuts, EditorSettingsDialog);
// Adding event dialog
shortcut_editor = memnew(InputEventConfigurationDialog);
diff --git a/editor/editor_toaster.cpp b/editor/editor_toaster.cpp
index dd5d68a08e..558423df78 100644
--- a/editor/editor_toaster.cpp
+++ b/editor/editor_toaster.cpp
@@ -90,11 +90,12 @@ void EditorToaster::_notification(int p_what) {
}
// Hide element if it is not visible anymore.
- if (modulate_fade.a <= 0) {
- if (element.key->is_visible()) {
- element.key->hide();
- needs_update = true;
- }
+ if (modulate_fade.a <= 0 && element.key->is_visible()) {
+ element.key->hide();
+ needs_update = true;
+ } else if (modulate_fade.a >= 0 && !element.key->is_visible()) {
+ element.key->show();
+ needs_update = true;
}
}
@@ -419,12 +420,21 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t
// Create a new message if needed.
if (control == nullptr) {
+ HBoxContainer *hb = memnew(HBoxContainer);
+ hb->add_theme_constant_override("separation", 0);
+
Label *label = memnew(Label);
+ hb->add_child(label);
- control = popup(label, p_severity, default_message_duration, p_tooltip);
+ Label *count_label = memnew(Label);
+ hb->add_child(count_label);
+
+ control = popup(hb, p_severity, default_message_duration, p_tooltip);
toasts[control].message = p_message;
toasts[control].tooltip = p_tooltip;
toasts[control].count = 1;
+ toasts[control].message_label = label;
+ toasts[control].message_count_label = count_label;
} else {
if (toasts[control].popped) {
toasts[control].count += 1;
@@ -441,14 +451,31 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t
main_button->queue_redraw();
}
- // Retrieve the label back then update the text.
- Label *label = Object::cast_to<Label>(control->get_child(0)->get_child(0));
- ERR_FAIL_COND(!label);
+ // Retrieve the label back, then update the text.
+ Label *message_label = toasts[control].message_label;
+ ERR_FAIL_COND(!message_label);
+ message_label->set_text(p_message);
+ message_label->set_text_overrun_behavior(TextServer::OVERRUN_NO_TRIMMING);
+ message_label->set_custom_minimum_size(Size2());
+
+ Size2i size = message_label->get_combined_minimum_size();
+ int limit_width = get_viewport_rect().size.x / 2; // Limit label size to half the viewport size.
+ if (size.x > limit_width) {
+ message_label->set_text_overrun_behavior(TextServer::OVERRUN_TRIM_ELLIPSIS);
+ message_label->set_custom_minimum_size(Size2(limit_width, 0));
+ }
+
+ // Retrieve the count label back, then update the text.
+ Label *message_count_label = toasts[control].message_count_label;
if (toasts[control].count == 1) {
- label->set_text(p_message);
+ message_count_label->hide();
} else {
- label->set_text(vformat("%s (%d)", p_message, toasts[control].count));
+ message_count_label->set_text(vformat("(%d)", toasts[control].count));
+ message_count_label->show();
}
+
+ vbox_container->reset_size();
+
is_processing_error = false;
}
diff --git a/editor/editor_toaster.h b/editor/editor_toaster.h
index acd2a8fbf3..6b834f8288 100644
--- a/editor/editor_toaster.h
+++ b/editor/editor_toaster.h
@@ -79,6 +79,8 @@ private:
String message;
String tooltip;
int count = 0;
+ Label *message_label = nullptr;
+ Label *message_count_label = nullptr;
};
HashMap<Control *, Toast> toasts;
diff --git a/editor/editor_undo_redo_manager.cpp b/editor/editor_undo_redo_manager.cpp
index 2ef52bd85a..f65f905b25 100644
--- a/editor/editor_undo_redo_manager.cpp
+++ b/editor/editor_undo_redo_manager.cpp
@@ -39,6 +39,8 @@
#include "editor/editor_node.h"
#include "scene/main/node.h"
+EditorUndoRedoManager *EditorUndoRedoManager::singleton = nullptr;
+
EditorUndoRedoManager::History &EditorUndoRedoManager::get_or_create_history(int p_idx) {
if (!history_map.has(p_idx)) {
History history;
@@ -503,6 +505,16 @@ void EditorUndoRedoManager::_bind_methods() {
BIND_ENUM_CONSTANT(INVALID_HISTORY);
}
+EditorUndoRedoManager *EditorUndoRedoManager::get_singleton() {
+ return singleton;
+}
+
+EditorUndoRedoManager::EditorUndoRedoManager() {
+ if (!singleton) {
+ singleton = this;
+ }
+}
+
EditorUndoRedoManager::~EditorUndoRedoManager() {
for (const KeyValue<int, History> &E : history_map) {
discard_history(E.key, false);
diff --git a/editor/editor_undo_redo_manager.h b/editor/editor_undo_redo_manager.h
index 960d17d410..10daeae807 100644
--- a/editor/editor_undo_redo_manager.h
+++ b/editor/editor_undo_redo_manager.h
@@ -32,11 +32,13 @@
#define EDITOR_UNDO_REDO_MANAGER_H
#include "core/object/class_db.h"
-#include "core/object/ref_counted.h"
+#include "core/object/object.h"
#include "core/object/undo_redo.h"
-class EditorUndoRedoManager : public RefCounted {
- GDCLASS(EditorUndoRedoManager, RefCounted);
+class EditorUndoRedoManager : public Object {
+ GDCLASS(EditorUndoRedoManager, Object);
+
+ static EditorUndoRedoManager *singleton;
public:
enum SpecialHistory {
@@ -132,6 +134,9 @@ public:
int get_current_action_history_id();
void discard_history(int p_idx, bool p_erase_from_map = true);
+
+ static EditorUndoRedoManager *get_singleton();
+ EditorUndoRedoManager();
~EditorUndoRedoManager();
};
diff --git a/editor/export/editor_export.cpp b/editor/export/editor_export.cpp
index cc96107f97..1d147cc5b9 100644
--- a/editor/export/editor_export.cpp
+++ b/editor/export/editor_export.cpp
@@ -77,7 +77,6 @@ void EditorExport::_save() {
config->set_value(section, "encryption_exclude_filters", preset->get_enc_ex_filter());
config->set_value(section, "encrypt_pck", preset->get_enc_pck());
config->set_value(section, "encrypt_directory", preset->get_enc_directory());
- config->set_value(section, "script_export_mode", preset->get_script_export_mode());
config->set_value(section, "script_encryption_key", preset->get_script_encryption_key());
String option_section = "preset." + itos(i) + ".options";
@@ -264,9 +263,6 @@ void EditorExport::load_config() {
if (config->has_section_key(section, "encryption_exclude_filters")) {
preset->set_enc_ex_filter(config->get_value(section, "encryption_exclude_filters"));
}
- if (config->has_section_key(section, "script_export_mode")) {
- preset->set_script_export_mode(config->get_value(section, "script_export_mode"));
- }
if (config->has_section_key(section, "script_encryption_key")) {
preset->set_script_encryption_key(config->get_value(section, "script_encryption_key"));
}
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index 6478f99fb1..cacd181ad8 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -786,6 +786,7 @@ Error EditorExportPlatform::export_project_files(const Ref<EditorExportPreset> &
HashSet<String> paths;
Vector<String> path_remaps;
+ paths.insert(ProjectSettings::get_singleton()->get_project_data_path().path_join("global_script_class_cache.cfg"));
if (p_preset->get_export_filter() == EditorExportPreset::EXPORT_ALL_RESOURCES) {
//find stuff
_export_find_resources(EditorFileSystem::get_singleton()->get_filesystem(), paths);
diff --git a/editor/export/editor_export_preset.cpp b/editor/export/editor_export_preset.cpp
index 6cd8e85e6a..c6365806b3 100644
--- a/editor/export/editor_export_preset.cpp
+++ b/editor/export/editor_export_preset.cpp
@@ -203,15 +203,6 @@ bool EditorExportPreset::get_enc_directory() const {
return enc_directory;
}
-void EditorExportPreset::set_script_export_mode(int p_mode) {
- script_mode = p_mode;
- EditorExport::singleton->save_presets();
-}
-
-int EditorExportPreset::get_script_export_mode() const {
- return script_mode;
-}
-
void EditorExportPreset::set_script_encryption_key(const String &p_key) {
script_key = p_key;
EditorExport::singleton->save_presets();
diff --git a/editor/export/editor_export_preset.h b/editor/export/editor_export_preset.h
index 2055416d4b..de208f410e 100644
--- a/editor/export/editor_export_preset.h
+++ b/editor/export/editor_export_preset.h
@@ -46,11 +46,6 @@ public:
EXCLUDE_SELECTED_RESOURCES,
};
- enum ScriptExportMode {
- MODE_SCRIPT_TEXT,
- MODE_SCRIPT_COMPILED,
- };
-
private:
Ref<EditorExportPlatform> platform;
ExportFilter export_filter = EXPORT_ALL_RESOURCES;
@@ -78,7 +73,6 @@ private:
bool enc_pck = false;
bool enc_directory = false;
- int script_mode = MODE_SCRIPT_COMPILED;
String script_key;
protected:
@@ -132,9 +126,6 @@ public:
void set_enc_directory(bool p_enabled);
bool get_enc_directory() const;
- void set_script_export_mode(int p_mode);
- int get_script_export_mode() const;
-
void set_script_encryption_key(const String &p_key);
String get_script_encryption_key() const;
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index df5d2dcd29..2caebc6f04 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -317,9 +317,6 @@ void ProjectExportDialog::_edit_preset(int p_index) {
bool enc_directory_mode = current->get_enc_directory();
enc_directory->set_pressed(enc_directory_mode);
- int script_export_mode = current->get_script_export_mode();
- script_mode->select(script_export_mode);
-
String key = current->get_script_encryption_key();
if (!updating_script_key) {
script_key->set_text(key);
@@ -480,7 +477,7 @@ void ProjectExportDialog::_enc_filters_changed(const String &p_filters) {
}
void ProjectExportDialog::_open_key_help_link() {
- OS::get_singleton()->shell_open(vformat("%s/development/compiling/compiling_with_script_encryption_key.html", VERSION_DOCS_URL));
+ OS::get_singleton()->shell_open(vformat("%s/contributing/development/compiling/compiling_with_script_encryption_key.html", VERSION_DOCS_URL));
}
void ProjectExportDialog::_enc_pck_changed(bool p_pressed) {
@@ -513,19 +510,6 @@ void ProjectExportDialog::_enc_directory_changed(bool p_pressed) {
_update_current_preset();
}
-void ProjectExportDialog::_script_export_mode_changed(int p_mode) {
- if (updating) {
- return;
- }
-
- Ref<EditorExportPreset> current = get_current_preset();
- ERR_FAIL_COND(current.is_null());
-
- current->set_script_export_mode(p_mode);
-
- _update_current_preset();
-}
-
void ProjectExportDialog::_script_encryption_key_changed(const String &p_key) {
if (updating) {
return;
@@ -979,9 +963,6 @@ void ProjectExportDialog::_export_all(bool p_debug) {
}
void ProjectExportDialog::_bind_methods() {
- ClassDB::bind_method("_get_drag_data_fw", &ProjectExportDialog::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &ProjectExportDialog::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &ProjectExportDialog::drop_data_fw);
ClassDB::bind_method("_export_all", &ProjectExportDialog::_export_all);
ClassDB::bind_method("set_export_path", &ProjectExportDialog::set_export_path);
ClassDB::bind_method("get_export_path", &ProjectExportDialog::get_export_path);
@@ -1022,8 +1003,7 @@ ProjectExportDialog::ProjectExportDialog() {
preset_vb->add_child(mc);
mc->set_v_size_flags(Control::SIZE_EXPAND_FILL);
presets = memnew(ItemList);
- // TODO: Must reimplement drag forwarding.
- //presets->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(presets, ProjectExportDialog);
mc->add_child(presets);
presets->connect("item_selected", callable_mp(this, &ProjectExportDialog::_edit_preset));
duplicate_preset = memnew(Button);
@@ -1115,12 +1095,6 @@ ProjectExportDialog::ProjectExportDialog() {
exclude_filters);
exclude_filters->connect("text_changed", callable_mp(this, &ProjectExportDialog::_filter_changed));
- script_mode = memnew(OptionButton);
- resources_vb->add_margin_child(TTR("GDScript Export Mode:"), script_mode);
- script_mode->add_item(TTR("Text"), (int)EditorExportPreset::MODE_SCRIPT_TEXT);
- script_mode->add_item(TTR("Compiled Bytecode (Faster Loading)"), (int)EditorExportPreset::MODE_SCRIPT_COMPILED);
- script_mode->connect("item_selected", callable_mp(this, &ProjectExportDialog::_script_export_mode_changed));
-
// Feature tags.
VBoxContainer *feature_vb = memnew(VBoxContainer);
diff --git a/editor/export/project_export.h b/editor/export/project_export.h
index 1138d598cb..d392dba2a4 100644
--- a/editor/export/project_export.h
+++ b/editor/export/project_export.h
@@ -86,7 +86,6 @@ private:
LineEdit *custom_features = nullptr;
RichTextLabel *custom_feature_display = nullptr;
- OptionButton *script_mode = nullptr;
LineEdit *script_key = nullptr;
Label *script_key_error = nullptr;
@@ -152,7 +151,6 @@ private:
void _enc_pck_changed(bool p_pressed);
void _enc_directory_changed(bool p_pressed);
void _enc_filters_changed(const String &p_text);
- void _script_export_mode_changed(int p_mode);
void _script_encryption_key_changed(const String &p_key);
bool _validate_script_encryption_key(const String &p_key);
diff --git a/editor/fbx_importer_manager.cpp b/editor/fbx_importer_manager.cpp
index dfea2e706a..2a005034a5 100644
--- a/editor/fbx_importer_manager.cpp
+++ b/editor/fbx_importer_manager.cpp
@@ -144,12 +144,8 @@ FBXImporterManager::FBXImporterManager() {
browse_dialog = memnew(EditorFileDialog);
browse_dialog->set_access(EditorFileDialog::ACCESS_FILESYSTEM);
browse_dialog->set_file_mode(EditorFileDialog::FILE_MODE_OPEN_FILE);
-#if defined(X11_ENABLED)
- browse_dialog->add_filter("FBX2glTF-linux-x86_64");
-#elif defined(OSX_ENABLED)
- browse_dialog->add_filter("FBX2glTF-macos-x86_64");
-#elif defined(WINDOWS_ENABLED)
- browse_dialog->add_filter("FBX2glTF-windows-x86_64");
+#ifdef WINDOWS_ENABLED
+ browse_dialog->add_filter("*.exe");
#endif
browse_dialog->connect("file_selected", callable_mp(this, &FBXImporterManager::_select_file));
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index 6eed3e3e61..f1ea8e8e65 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -2051,7 +2051,8 @@ void FileSystemDock::_file_option(int p_option, const Vector<String> &p_selected
if (!fpath.ends_with("/")) {
fpath = fpath.get_base_dir();
}
- ScriptEditor::get_singleton()->open_text_file_create_dialog(fpath);
+ String dir = ProjectSettings::get_singleton()->globalize_path(fpath);
+ ScriptEditor::get_singleton()->open_text_file_create_dialog(dir);
} break;
}
}
@@ -2589,11 +2590,18 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
if (p_paths.size() == 1) {
p_popup->add_separator();
if (p_display_path_dependent_options) {
- p_popup->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("New Folder..."), FILE_NEW_FOLDER);
- p_popup->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("New Scene..."), FILE_NEW_SCENE);
- p_popup->add_icon_item(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), TTR("New Script..."), FILE_NEW_SCRIPT);
- p_popup->add_icon_item(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")), TTR("New Resource..."), FILE_NEW_RESOURCE);
- p_popup->add_icon_item(get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons")), TTR("New TextFile..."), FILE_NEW_TEXTFILE);
+ PopupMenu *new_menu = memnew(PopupMenu);
+ new_menu->set_name("New");
+ new_menu->connect("id_pressed", callable_mp(this, &FileSystemDock::_tree_rmb_option));
+
+ p_popup->add_child(new_menu);
+ p_popup->add_submenu_item(TTR("New"), "New");
+
+ new_menu->add_icon_item(get_theme_icon(SNAME("Folder"), SNAME("EditorIcons")), TTR("Folder..."), FILE_NEW_FOLDER);
+ new_menu->add_icon_item(get_theme_icon(SNAME("PackedScene"), SNAME("EditorIcons")), TTR("Scene..."), FILE_NEW_SCENE);
+ new_menu->add_icon_item(get_theme_icon(SNAME("Script"), SNAME("EditorIcons")), TTR("Script..."), FILE_NEW_SCRIPT);
+ new_menu->add_icon_item(get_theme_icon(SNAME("Object"), SNAME("EditorIcons")), TTR("Resource..."), FILE_NEW_RESOURCE);
+ new_menu->add_icon_item(get_theme_icon(SNAME("TextFile"), SNAME("EditorIcons")), TTR("TextFile..."), FILE_NEW_TEXTFILE);
p_popup->add_separator();
}
@@ -3020,9 +3028,6 @@ void FileSystemDock::_bind_methods() {
ClassDB::bind_method(D_METHOD("_tree_thumbnail_done"), &FileSystemDock::_tree_thumbnail_done);
ClassDB::bind_method(D_METHOD("_select_file"), &FileSystemDock::_select_file);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "position", "from"), &FileSystemDock::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "position", "data", "from"), &FileSystemDock::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "position", "data", "from"), &FileSystemDock::drop_data_fw);
ClassDB::bind_method(D_METHOD("navigate_to_path", "path"), &FileSystemDock::navigate_to_path);
ClassDB::bind_method(D_METHOD("_update_import_dock"), &FileSystemDock::_update_import_dock);
@@ -3122,10 +3127,11 @@ FileSystemDock::FileSystemDock() {
tree = memnew(Tree);
tree->set_hide_root(true);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(tree, FileSystemDock);
tree->set_allow_rmb_select(true);
tree->set_select_mode(Tree::SELECT_MULTI);
tree->set_custom_minimum_size(Size2(0, 15 * EDSCALE));
+ tree->set_column_clip_content(0, true);
split_box->add_child(tree);
tree->connect("item_activated", callable_mp(this, &FileSystemDock::_tree_activate_file));
@@ -3159,7 +3165,7 @@ FileSystemDock::FileSystemDock() {
files = memnew(ItemList);
files->set_v_size_flags(SIZE_EXPAND_FILL);
files->set_select_mode(ItemList::SELECT_MULTI);
- files->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(files, FileSystemDock);
files->connect("item_clicked", callable_mp(this, &FileSystemDock::_file_list_item_clicked));
files->connect("gui_input", callable_mp(this, &FileSystemDock::_file_list_gui_input));
files->connect("multi_selected", callable_mp(this, &FileSystemDock::_file_multi_selected));
diff --git a/editor/groups_editor.cpp b/editor/groups_editor.cpp
index 3ee7d5ddd8..7f0417ea29 100644
--- a/editor/groups_editor.cpp
+++ b/editor/groups_editor.cpp
@@ -130,7 +130,7 @@ void GroupDialog::_add_pressed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add to Group"));
while (selected) {
@@ -160,7 +160,7 @@ void GroupDialog::_removed_pressed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove from Group"));
while (selected) {
@@ -248,7 +248,7 @@ void GroupDialog::_group_renamed() {
renamed_group->set_text(0, name); // Spaces trimmed.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Group"));
List<Node *> nodes;
@@ -325,7 +325,7 @@ void GroupDialog::_modify_group_pressed(Object *p_item, int p_column, int p_id,
case DELETE_GROUP: {
String name = ti->get_text(0);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Group"));
List<Node *> nodes;
@@ -597,7 +597,7 @@ void GroupsEditor::_add_group(const String &p_group) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add to Group"));
undo_redo->add_do_method(node, "add_to_group", name, true);
@@ -652,7 +652,7 @@ void GroupsEditor::_group_renamed() {
ti->set_text(0, name); // Spaces trimmed.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Group"));
undo_redo->add_do_method(node, "remove_from_group", selected_group);
@@ -688,7 +688,7 @@ void GroupsEditor::_modify_group(Object *p_item, int p_column, int p_id, MouseBu
switch (p_id) {
case DELETE_GROUP: {
const String name = ti->get_text(0);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove from Group"));
undo_redo->add_do_method(node, "remove_from_group", name);
diff --git a/editor/history_dock.cpp b/editor/history_dock.cpp
index f9fe1093b8..41ca519400 100644
--- a/editor/history_dock.cpp
+++ b/editor/history_dock.cpp
@@ -221,7 +221,7 @@ void HistoryDock::_notification(int p_notification) {
HistoryDock::HistoryDock() {
set_name("History");
- ur_manager = EditorNode::get_undo_redo();
+ ur_manager = EditorUndoRedoManager::get_singleton();
ur_manager->connect("history_changed", callable_mp(this, &HistoryDock::on_history_changed));
ur_manager->connect("version_changed", callable_mp(this, &HistoryDock::on_version_changed));
diff --git a/editor/history_dock.h b/editor/history_dock.h
index 81d1d02b79..d507f19b07 100644
--- a/editor/history_dock.h
+++ b/editor/history_dock.h
@@ -40,7 +40,7 @@ class EditorUndoRedoManager;
class HistoryDock : public VBoxContainer {
GDCLASS(HistoryDock, VBoxContainer);
- Ref<EditorUndoRedoManager> ur_manager;
+ EditorUndoRedoManager *ur_manager;
ItemList *action_list = nullptr;
CheckBox *current_scene_checkbox = nullptr;
diff --git a/editor/icons/PlayRemote.svg b/editor/icons/PlayRemote.svg
new file mode 100644
index 0000000000..ea2195294f
--- /dev/null
+++ b/editor/icons/PlayRemote.svg
@@ -0,0 +1 @@
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16"><path d="m12.998 2.548-9.996.005a2.006 2.006 0 0 0-2.006 2v4.61c0 1.107.898 2.003 2.006 2.003h3.996v.9h-1.68v.381H3.001v2h2.315v.38h5.366v-.38H13v-2.004h-2.315v-.378H9.004v-.9h3.994a2.006 2.006 0 0 0 2.006-2.003v-4.61c0-1.106-.9-2.003-2.006-2.003zm-7.496 1.31 5 3-5 3z" style="fill:#e0e0e0;fill-opacity:1"/></svg>
diff --git a/editor/icons/README.md b/editor/icons/README.md
index 3159565180..d191000985 100644
--- a/editor/icons/README.md
+++ b/editor/icons/README.md
@@ -3,5 +3,5 @@
This folder contains all the icons used by Godot editor (except for platform
icons which are located in their respective platform folder).
-See [Editor icons](https://docs.godotengine.org/en/latest/development/editor/creating_icons.html)
+See [Editor icons](https://docs.godotengine.org/en/latest/contributing/development/editor/creating_icons.html)
in the documentation for details on creating icons for the Godot editor.
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index fcd706627d..a8d746fde6 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -262,7 +262,7 @@ void Collada::_parse_asset(XMLParser &parser) {
COLLADA_PRINT("up axis: " + parser.get_node_data());
} else if (name == "unit") {
- state.unit_scale = parser.get_attribute_value("meter").to_float();
+ state.unit_scale = parser.get_named_attribute_value("meter").to_float();
COLLADA_PRINT("unit scale: " + rtos(state.unit_scale));
}
@@ -273,7 +273,7 @@ void Collada::_parse_asset(XMLParser &parser) {
}
void Collada::_parse_image(XMLParser &parser) {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
if (!(state.import_flags & IMPORT_FLAG_SCENE)) {
if (!parser.is_empty()) {
@@ -286,7 +286,7 @@ void Collada::_parse_image(XMLParser &parser) {
if (state.version < State::Version(1, 4, 0)) {
/* <1.4 */
- String path = parser.get_attribute_value("source").strip_edges();
+ String path = parser.get_named_attribute_value("source").strip_edges();
if (!path.contains("://") && path.is_relative_path()) {
// path is relative to file being loaded, so convert to a resource path
image.path = ProjectSettings::get_singleton()->localize_path(state.local_path.get_base_dir().path_join(path.uri_decode()));
@@ -337,9 +337,9 @@ void Collada::_parse_material(XMLParser &parser) {
Material material;
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
if (parser.has_attribute("name")) {
- material.name = parser.get_attribute_value("name");
+ material.name = parser.get_named_attribute_value("name");
}
if (state.version < State::Version(1, 4, 0)) {
@@ -348,7 +348,7 @@ void Collada::_parse_material(XMLParser &parser) {
} else {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT && parser.get_node_name() == "instance_effect") {
- material.instance_effect = _uri_to_id(parser.get_attribute_value("url"));
+ material.instance_effect = _uri_to_id(parser.get_named_attribute_value("url"));
} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "material") {
break; //end of <asset>
}
@@ -549,7 +549,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
_parse_effect_material(parser, effect, id); // try again
} else if (parser.get_node_name() == "newparam") {
- String name = parser.get_attribute_value("sid");
+ String name = parser.get_named_attribute_value("sid");
Variant value = _parse_param(parser);
effect.params[name] = value;
COLLADA_PRINT("param: " + name + " value:" + String(value));
@@ -591,7 +591,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
}
} else if (parser.get_node_name() == "texture") {
- String sampler = parser.get_attribute_value("texture");
+ String sampler = parser.get_named_attribute_value("texture");
if (!effect.params.has(sampler)) {
ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
} else {
@@ -609,7 +609,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
} else if (what == "emission") {
effect.emission.texture = uri;
} else if (what == "bump") {
- if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+ if (parser.has_attribute("bumptype") && parser.get_named_attribute_value("bumptype") != "NORMALMAP") {
WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
}
@@ -654,7 +654,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "texture") {
- String sampler = parser.get_attribute_value("texture");
+ String sampler = parser.get_named_attribute_value("texture");
if (!effect.params.has(sampler)) {
ERR_PRINT(String("Couldn't find sampler: " + sampler + " in material:" + id).utf8().get_data());
} else {
@@ -665,7 +665,7 @@ void Collada::_parse_effect_material(XMLParser &parser, Effect &effect, String &
} else {
String uri = effect.params[surface];
- if (parser.has_attribute("bumptype") && parser.get_attribute_value("bumptype") != "NORMALMAP") {
+ if (parser.has_attribute("bumptype") && parser.get_named_attribute_value("bumptype") != "NORMALMAP") {
WARN_PRINT("'bump' texture type is not NORMALMAP, only NORMALMAP is supported.");
}
@@ -703,11 +703,11 @@ void Collada::_parse_effect(XMLParser &parser) {
return;
}
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
Effect effect;
if (parser.has_attribute("name")) {
- effect.name = parser.get_attribute_value("name");
+ effect.name = parser.get_named_attribute_value("name");
}
_parse_effect_material(parser, effect, id);
@@ -724,7 +724,7 @@ void Collada::_parse_camera(XMLParser &parser) {
return;
}
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
state.camera_data_map[id] = CameraData();
CameraData &camera = state.camera_data_map[id];
@@ -780,7 +780,7 @@ void Collada::_parse_light(XMLParser &parser) {
return;
}
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
state.light_data_map[id] = LightData();
LightData &light = state.light_data_map[id];
@@ -848,7 +848,7 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
CurveData &curvedata = state.curve_data_map[p_id];
curvedata.name = p_name;
- String closed = parser.get_attribute_value_safe("closed").to_lower();
+ String closed = parser.get_named_attribute_value_safe("closed").to_lower();
curvedata.closed = closed == "true" || closed == "1";
COLLADA_PRINT("curve name: " + p_name);
@@ -865,7 +865,7 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
String section = parser.get_node_name();
if (section == "source") {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
curvedata.sources[id] = CurveData::Source();
current_source = id;
COLLADA_PRINT("source data: " + id);
@@ -888,15 +888,15 @@ void Collada::_parse_curve_geometry(XMLParser &parser, String p_id, String p_nam
} else if (section == "accessor") { // child of source (below a technique tag)
if (curvedata.sources.has(current_source)) {
- curvedata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+ curvedata.sources[current_source].stride = parser.get_named_attribute_value("stride").to_int();
COLLADA_PRINT("section: " + current_source + " stride " + itos(curvedata.sources[current_source].stride));
}
} else if (section == "control_vertices") {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
curvedata.control_vertices[semantic] = source;
@@ -945,7 +945,7 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
String section = parser.get_node_name();
if (section == "source") {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
meshdata.sources[id] = MeshData::Source();
current_source = id;
COLLADA_PRINT("source data: " + id);
@@ -961,19 +961,19 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
} else if (section == "accessor") { // child of source (below a technique tag)
if (meshdata.sources.has(current_source)) {
- meshdata.sources[current_source].stride = parser.get_attribute_value("stride").to_int();
+ meshdata.sources[current_source].stride = parser.get_named_attribute_value("stride").to_int();
COLLADA_PRINT("section: " + current_source + " stride " + itos(meshdata.sources[current_source].stride));
}
} else if (section == "vertices") {
MeshData::Vertices vert;
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
int last_ref = 0;
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
if (semantic == "TEXCOORD") {
semantic = "TEXCOORD" + itos(last_ref++);
@@ -998,22 +998,22 @@ void Collada::_parse_mesh_geometry(XMLParser &parser, String p_id, String p_name
MeshData::Primitives prim;
if (parser.has_attribute("material")) {
- prim.material = parser.get_attribute_value("material");
+ prim.material = parser.get_named_attribute_value("material");
}
- prim.count = parser.get_attribute_value("count").to_int();
+ prim.count = parser.get_named_attribute_value("count").to_int();
prim.vertex_size = 0;
int last_ref = 0;
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
if (semantic == "TEXCOORD") {
semantic = "TEXCOORD" + itos(last_ref++);
}
- int offset = parser.get_attribute_value("offset").to_int();
+ int offset = parser.get_named_attribute_value("offset").to_int();
MeshData::Primitives::SourceRef sref;
sref.source = source;
@@ -1074,7 +1074,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
state.skin_controller_data_map[p_id] = SkinControllerData();
SkinControllerData &skindata = state.skin_controller_data_map[p_id];
- skindata.base = _uri_to_id(parser.get_attribute_value("source"));
+ skindata.base = _uri_to_id(parser.get_named_attribute_value("source"));
String current_source;
@@ -1091,7 +1091,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
COLLADA_PRINT("skeleton bind shape transform: " + skindata.bind_shape);
} else if (section == "source") {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
skindata.sources[id] = SkinControllerData::Source();
current_source = id;
COLLADA_PRINT("source data: " + id);
@@ -1125,7 +1125,7 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
if (skindata.sources.has(current_source)) {
int stride = 1;
if (parser.has_attribute("stride")) {
- stride = parser.get_attribute_value("stride").to_int();
+ stride = parser.get_named_attribute_value("stride").to_int();
}
skindata.sources[current_source].stride = stride;
@@ -1138,8 +1138,8 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
joint.sources[semantic] = source;
@@ -1155,15 +1155,15 @@ void Collada::_parse_skin_controller(XMLParser &parser, String p_id) {
} else if (section == "vertex_weights") {
SkinControllerData::Weights weights;
- weights.count = parser.get_attribute_value("count").to_int();
+ weights.count = parser.get_named_attribute_value("count").to_int();
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
- int offset = parser.get_attribute_value("offset").to_int();
+ int offset = parser.get_named_attribute_value("offset").to_int();
SkinControllerData::Weights::SourceRef sref;
sref.source = source;
@@ -1228,8 +1228,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
state.morph_controller_data_map[p_id] = MorphControllerData();
MorphControllerData &morphdata = state.morph_controller_data_map[p_id];
- morphdata.mesh = _uri_to_id(parser.get_attribute_value("source"));
- morphdata.mode = parser.get_attribute_value("method");
+ morphdata.mesh = _uri_to_id(parser.get_named_attribute_value("source"));
+ morphdata.mode = parser.get_named_attribute_value("method");
String current_source;
while (parser.read() == OK) {
@@ -1237,7 +1237,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
String section = parser.get_node_name();
if (section == "source") {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
morphdata.sources[id] = MorphControllerData::Source();
current_source = id;
COLLADA_PRINT("source data: " + id);
@@ -1261,7 +1261,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
if (morphdata.sources.has(current_source)) {
int stride = 1;
if (parser.has_attribute("stride")) {
- stride = parser.get_attribute_value("stride").to_int();
+ stride = parser.get_named_attribute_value("stride").to_int();
}
morphdata.sources[current_source].stride = stride;
@@ -1272,8 +1272,8 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "input") {
- String semantic = parser.get_attribute_value("semantic");
- String source = _uri_to_id(parser.get_attribute_value("source"));
+ String semantic = parser.get_named_attribute_value("semantic");
+ String source = _uri_to_id(parser.get_named_attribute_value("source"));
morphdata.targets[semantic] = source;
@@ -1295,7 +1295,7 @@ void Collada::_parse_morph_controller(XMLParser &parser, String p_id) {
}
void Collada::_parse_controller(XMLParser &parser) {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
if (parser.is_empty()) {
return;
@@ -1320,7 +1320,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
String type = parser.get_node_name();
NodeGeometry *geom = memnew(NodeGeometry);
geom->controller = type == "instance_controller";
- geom->source = _uri_to_id(parser.get_attribute_value_safe("url"));
+ geom->source = _uri_to_id(parser.get_named_attribute_value_safe("url"));
if (parser.is_empty()) { //nothing else to parse...
return geom;
@@ -1329,8 +1329,8 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "instance_material") {
- String symbol = parser.get_attribute_value("symbol");
- String target = _uri_to_id(parser.get_attribute_value("target"));
+ String symbol = parser.get_named_attribute_value("symbol");
+ String target = _uri_to_id(parser.get_named_attribute_value("target"));
NodeGeometry::Material mat;
mat.target = target;
@@ -1370,7 +1370,7 @@ Collada::Node *Collada::_parse_visual_instance_geometry(XMLParser &parser) {
Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
NodeCamera *cam = memnew(NodeCamera);
- cam->camera = _uri_to_id(parser.get_attribute_value_safe("url"));
+ cam->camera = _uri_to_id(parser.get_named_attribute_value_safe("url"));
if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness
cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
@@ -1391,7 +1391,7 @@ Collada::Node *Collada::_parse_visual_instance_camera(XMLParser &parser) {
Collada::Node *Collada::_parse_visual_instance_light(XMLParser &parser) {
NodeLight *cam = memnew(NodeLight);
- cam->light = _uri_to_id(parser.get_attribute_value_safe("url"));
+ cam->light = _uri_to_id(parser.get_named_attribute_value_safe("url"));
if (state.up_axis == Vector3::AXIS_Z) { //collada weirdness
cam->post_transform.basis.rotate(Vector3(1, 0, 0), -Math_PI * 0.5);
@@ -1437,7 +1437,7 @@ Collada::Node *Collada::_parse_visual_node_instance_data(XMLParser &parser) {
Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
String name;
- String id = parser.get_attribute_value_safe("id");
+ String id = parser.get_named_attribute_value_safe("id");
bool found_name = false;
@@ -1455,25 +1455,25 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
Node *node = nullptr;
- name = parser.has_attribute("name") ? parser.get_attribute_value_safe("name") : parser.get_attribute_value_safe("id");
+ name = parser.has_attribute("name") ? parser.get_named_attribute_value_safe("name") : parser.get_named_attribute_value_safe("id");
if (name.is_empty()) {
name = id;
} else {
found_name = true;
}
- if ((parser.has_attribute("type") && parser.get_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
+ if ((parser.has_attribute("type") && parser.get_named_attribute_value("type") == "JOINT") || state.idref_joints.has(name)) {
// handle a bone
NodeJoint *joint = memnew(NodeJoint);
if (parser.has_attribute("sid")) { //bones may not have sid
- joint->sid = parser.get_attribute_value("sid");
+ joint->sid = parser.get_named_attribute_value("sid");
//state.bone_map[joint->sid]=joint;
} else if (state.idref_joints.has(name)) {
joint->sid = name; //kind of a cheat but..
} else if (parser.has_attribute("name")) {
- joint->sid = parser.get_attribute_value_safe("name");
+ joint->sid = parser.get_named_attribute_value_safe("name");
}
if (!joint->sid.is_empty()) {
@@ -1490,7 +1490,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
if (section == "translate") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_TRANSLATE;
@@ -1501,7 +1501,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
} else if (section == "rotate") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_ROTATE;
@@ -1513,7 +1513,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
} else if (section == "scale") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_SCALE;
@@ -1527,7 +1527,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
} else if (section == "matrix") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_MATRIX;
@@ -1544,7 +1544,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
} else if (section == "visibility") {
Node::XForm xf;
if (parser.has_attribute("sid")) {
- xf.id = parser.get_attribute_value("sid");
+ xf.id = parser.get_named_attribute_value("sid");
}
xf.op = Node::XForm::OP_VISIBILITY;
@@ -1609,7 +1609,7 @@ Collada::Node *Collada::_parse_visual_scene_node(XMLParser &parser) {
}
void Collada::_parse_visual_scene(XMLParser &parser) {
- String id = parser.get_attribute_value("id");
+ String id = parser.get_named_attribute_value("id");
if (parser.is_empty()) {
return;
@@ -1619,7 +1619,7 @@ void Collada::_parse_visual_scene(XMLParser &parser) {
VisualScene &vscene = state.visual_scene_map[id];
if (parser.has_attribute("name")) {
- vscene.name = parser.get_attribute_value("name");
+ vscene.name = parser.get_named_attribute_value("name");
}
while (parser.read() == OK) {
@@ -1656,7 +1656,7 @@ void Collada::_parse_animation(XMLParser &parser) {
String id = "";
if (parser.has_attribute("id")) {
- id = parser.get_attribute_value("id");
+ id = parser.get_named_attribute_value("id");
}
String current_source;
@@ -1668,7 +1668,7 @@ void Collada::_parse_animation(XMLParser &parser) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
String name = parser.get_node_name();
if (name == "source") {
- current_source = parser.get_attribute_value("id");
+ current_source = parser.get_named_attribute_value("id");
source_param_names[current_source] = Vector<String>();
source_param_types[current_source] = Vector<String>();
@@ -1683,32 +1683,32 @@ void Collada::_parse_animation(XMLParser &parser) {
}
} else if (name == "accessor") {
if (!current_source.is_empty() && parser.has_attribute("stride")) {
- source_strides[current_source] = parser.get_attribute_value("stride").to_int();
+ source_strides[current_source] = parser.get_named_attribute_value("stride").to_int();
}
} else if (name == "sampler") {
- current_sampler = parser.get_attribute_value("id");
+ current_sampler = parser.get_named_attribute_value("id");
samplers[current_sampler] = HashMap<String, String>();
} else if (name == "param") {
if (parser.has_attribute("name")) {
- source_param_names[current_source].push_back(parser.get_attribute_value("name"));
+ source_param_names[current_source].push_back(parser.get_named_attribute_value("name"));
} else {
source_param_names[current_source].push_back("");
}
if (parser.has_attribute("type")) {
- source_param_types[current_source].push_back(parser.get_attribute_value("type"));
+ source_param_types[current_source].push_back(parser.get_named_attribute_value("type"));
} else {
source_param_types[current_source].push_back("");
}
} else if (name == "input") {
if (!current_sampler.is_empty()) {
- samplers[current_sampler][parser.get_attribute_value("semantic")] = parser.get_attribute_value("source");
+ samplers[current_sampler][parser.get_named_attribute_value("semantic")] = parser.get_named_attribute_value("source");
}
} else if (name == "channel") {
- channel_sources.push_back(parser.get_attribute_value("source"));
- channel_targets.push_back(parser.get_attribute_value("target"));
+ channel_sources.push_back(parser.get_named_attribute_value("source"));
+ channel_targets.push_back(parser.get_named_attribute_value("target"));
}
} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "animation") {
@@ -1857,22 +1857,22 @@ void Collada::_parse_animation_clip(XMLParser &parser) {
AnimationClip clip;
if (parser.has_attribute("name")) {
- clip.name = parser.get_attribute_value("name");
+ clip.name = parser.get_named_attribute_value("name");
} else if (parser.has_attribute("id")) {
- clip.name = parser.get_attribute_value("id");
+ clip.name = parser.get_named_attribute_value("id");
}
if (parser.has_attribute("start")) {
- clip.begin = parser.get_attribute_value("start").to_float();
+ clip.begin = parser.get_named_attribute_value("start").to_float();
}
if (parser.has_attribute("end")) {
- clip.end = parser.get_attribute_value("end").to_float();
+ clip.end = parser.get_named_attribute_value("end").to_float();
}
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
String name = parser.get_node_name();
if (name == "instance_animation") {
- String url = _uri_to_id(parser.get_attribute_value("url"));
+ String url = _uri_to_id(parser.get_named_attribute_value("url"));
clip.tracks.push_back(url);
}
@@ -1894,9 +1894,9 @@ void Collada::_parse_scene(XMLParser &parser) {
String name = parser.get_node_name();
if (name == "instance_visual_scene") {
- state.root_visual_scene = _uri_to_id(parser.get_attribute_value("url"));
+ state.root_visual_scene = _uri_to_id(parser.get_named_attribute_value("url"));
} else if (name == "instance_physics_scene") {
- state.root_physics_scene = _uri_to_id(parser.get_attribute_value("url"));
+ state.root_physics_scene = _uri_to_id(parser.get_named_attribute_value("url"));
}
} else if (parser.get_node_type() == XMLParser::NODE_ELEMENT_END && parser.get_node_name() == "scene") {
@@ -1925,8 +1925,8 @@ void Collada::_parse_library(XMLParser &parser) {
} else if (name == "light") {
_parse_light(parser);
} else if (name == "geometry") {
- String id = parser.get_attribute_value("id");
- String name2 = parser.get_attribute_value_safe("name");
+ String id = parser.get_named_attribute_value("id");
+ String name2 = parser.get_named_attribute_value_safe("name");
while (parser.read() == OK) {
if (parser.get_node_type() == XMLParser::NODE_ELEMENT) {
if (parser.get_node_name() == "mesh") {
@@ -2346,7 +2346,7 @@ Error Collada::load(const String &p_path, int p_flags) {
{
//version
- String version = parser.get_attribute_value("version");
+ String version = parser.get_named_attribute_value("version");
state.version.major = version.get_slice(".", 0).to_int();
state.version.minor = version.get_slice(".", 1).to_int();
state.version.rev = version.get_slice(".", 2).to_int();
diff --git a/editor/import/resource_importer_obj.cpp b/editor/import/resource_importer_obj.cpp
index f1fd1d5a03..3dd01754a3 100644
--- a/editor/import/resource_importer_obj.cpp
+++ b/editor/import/resource_importer_obj.cpp
@@ -206,6 +206,20 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
Ref<FileAccess> f = FileAccess::open(p_path, FileAccess::READ);
ERR_FAIL_COND_V_MSG(f.is_null(), ERR_CANT_OPEN, vformat("Couldn't open OBJ file '%s', it may not exist or not be readable.", p_path));
+ // Avoid trying to load/interpret potential build artifacts from Visual Studio (e.g. when compiling native plugins inside the project tree)
+ // This should only match, if it's indeed a COFF file header
+ // https://learn.microsoft.com/en-us/windows/win32/debug/pe-format#machine-types
+ const int first_bytes = f->get_16();
+ static const Vector<int> coff_header_machines{
+ 0x0, // IMAGE_FILE_MACHINE_UNKNOWN
+ 0x8664, // IMAGE_FILE_MACHINE_AMD64
+ 0x1c0, // IMAGE_FILE_MACHINE_ARM
+ 0x14c, // IMAGE_FILE_MACHINE_I386
+ 0x200, // IMAGE_FILE_MACHINE_IA64
+ };
+ ERR_FAIL_COND_V_MSG(coff_header_machines.find(first_bytes) != -1, ERR_FILE_CORRUPT, vformat("Couldn't read OBJ file '%s', it seems to be binary, corrupted, or empty.", p_path));
+ f->seek(0);
+
Ref<ArrayMesh> mesh;
mesh.instantiate();
@@ -218,7 +232,8 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
Vector<Vector3> normals;
Vector<Vector2> uvs;
Vector<Color> colors;
- String name;
+ const String default_name = "Mesh";
+ String name = default_name;
HashMap<String, HashMap<String, Ref<StandardMaterial3D>>> material_map;
@@ -395,9 +410,12 @@ static Error _parse_obj(const String &p_path, List<Ref<Mesh>> &r_meshes, bool p_
if (l.begins_with("o ") || f->eof_reached()) {
if (!p_single_mesh) {
- mesh->set_name(name);
- r_meshes.push_back(mesh);
- mesh.instantiate();
+ if (mesh->get_surface_count() > 0) {
+ mesh->set_name(name);
+ r_meshes.push_back(mesh);
+ mesh.instantiate();
+ }
+ name = default_name;
current_group = "";
current_material = "";
}
@@ -460,6 +478,7 @@ Node *EditorOBJImporter::import_scene(const String &p_path, uint32_t p_flags, co
for (const Ref<Mesh> &m : meshes) {
Ref<ImporterMesh> mesh;
mesh.instantiate();
+ mesh->set_name(m->get_name());
for (int i = 0; i < m->get_surface_count(); i++) {
mesh->add_surface(m->surface_get_primitive_type(i), m->surface_get_arrays(i), Array(), Dictionary(), m->surface_get_material(i));
}
diff --git a/editor/import/resource_importer_shader_file.cpp b/editor/import/resource_importer_shader_file.cpp
index 7187e85df0..ba48fc9029 100644
--- a/editor/import/resource_importer_shader_file.cpp
+++ b/editor/import/resource_importer_shader_file.cpp
@@ -91,6 +91,7 @@ static String _include_function(const String &p_path, void *userpointer) {
Error ResourceImporterShaderFile::import(const String &p_source_file, const String &p_save_path, const HashMap<StringName, Variant> &p_options, List<String> *r_platform_variants, List<String> *r_gen_files, Variant *r_metadata) {
/* STEP 1, Read shader code */
+ ERR_FAIL_COND_V_EDMSG((OS::get_singleton()->get_current_rendering_method() == "gl_compatibility"), ERR_UNAVAILABLE, "Cannot import custom .glsl shaders when using the gl_compatibility rendering_method. Please switch to the forward_plus or mobile rendering methods to use custom shaders.");
Error err;
Ref<FileAccess> file = FileAccess::open(p_source_file, FileAccess::READ, &err);
diff --git a/editor/import/scene_import_settings.cpp b/editor/import/scene_import_settings.cpp
index f6ec7da158..044f7475c2 100644
--- a/editor/import/scene_import_settings.cpp
+++ b/editor/import/scene_import_settings.cpp
@@ -703,15 +703,17 @@ void SceneImportSettings::_select(Tree *p_from, String p_type, String p_id) {
}
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();
+ if (md.mesh_node != nullptr) {
+ 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);
@@ -1234,6 +1236,12 @@ SceneImportSettings::SceneImportSettings() {
action_menu = memnew(MenuButton);
action_menu->set_text(TTR("Actions..."));
+ // Style the MenuButton like a regular Button to make it more noticeable.
+ action_menu->set_flat(false);
+ action_menu->add_theme_style_override("normal", get_theme_stylebox("normal", "Button"));
+ action_menu->add_theme_style_override("hover", get_theme_stylebox("hover", "Button"));
+ action_menu->add_theme_style_override("pressed", get_theme_stylebox("pressed", "Button"));
+ action_menu->set_focus_mode(Control::FOCUS_ALL);
menu_hb->add_child(action_menu);
action_menu->get_popup()->add_item(TTR("Extract Materials"), ACTION_EXTRACT_MATERIALS);
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index 4cd8976e80..b28373e308 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -186,8 +186,8 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) {
}
}
- int history_id = editor_data->get_undo_redo()->get_history_for_object(current).id;
- editor_data->get_undo_redo()->clear_history(true, history_id);
+ int history_id = EditorUndoRedoManager::get_singleton()->get_history_for_object(current).id;
+ EditorUndoRedoManager::get_singleton()->clear_history(true, history_id);
EditorNode::get_singleton()->get_editor_plugins_over()->edit(nullptr);
EditorNode::get_singleton()->get_editor_plugins_over()->edit(current);
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index 6fa980a8e5..5503645930 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -33,7 +33,6 @@
#include "core/config/project_settings.h"
#include "core/string/translation.h"
#include "editor/editor_file_dialog.h"
-#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_translation_parser.h"
#include "editor/editor_undo_redo_manager.h"
@@ -81,7 +80,7 @@ void LocalizationEditor::_translation_add(const PackedStringArray &p_paths) {
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add %d Translations"), p_paths.size()));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", GLOBAL_GET("internationalization/locale/translations"));
@@ -112,7 +111,7 @@ void LocalizationEditor::_translation_delete(Object *p_item, int p_column, int p
translations.remove_at(idx);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Translation"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", translations);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations", GLOBAL_GET("internationalization/locale/translations"));
@@ -143,7 +142,7 @@ void LocalizationEditor::_translation_res_add(const PackedStringArray &p_paths)
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Translation Resource Remap: Add %d Path(s)"), p_paths.size()));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", prev);
@@ -175,7 +174,7 @@ void LocalizationEditor::_translation_res_option_add(const PackedStringArray &p_
}
remaps[key] = r;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Translation Resource Remap: Add %d Remap(s)"), p_paths.size()));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps"));
@@ -239,7 +238,7 @@ void LocalizationEditor::_translation_res_option_changed() {
updating_translations = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Resource Remap Language"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps"));
@@ -273,7 +272,7 @@ void LocalizationEditor::_translation_res_delete(Object *p_item, int p_column, i
remaps.erase(key);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Resource Remap"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps"));
@@ -313,7 +312,7 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
r.remove_at(idx);
remaps[key] = r;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Resource Remap Option"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", remaps);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translation_remaps", GLOBAL_GET("internationalization/locale/translation_remaps"));
@@ -332,7 +331,7 @@ void LocalizationEditor::_pot_add(const PackedStringArray &p_paths) {
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add %d file(s) for POT generation"), p_paths.size()));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", GLOBAL_GET("internationalization/locale/translations_pot_files"));
@@ -359,7 +358,7 @@ void LocalizationEditor::_pot_delete(Object *p_item, int p_column, int p_button,
pot_translations.remove_at(idx);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove file from POT generation"));
undo_redo->add_do_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", pot_translations);
undo_redo->add_undo_property(ProjectSettings::get_singleton(), "internationalization/locale/translations_pot_files", GLOBAL_GET("internationalization/locale/translations_pot_files"));
diff --git a/editor/multi_node_edit.cpp b/editor/multi_node_edit.cpp
index 2bf5e7979d..4f0db70681 100644
--- a/editor/multi_node_edit.cpp
+++ b/editor/multi_node_edit.cpp
@@ -57,7 +57,7 @@ bool MultiNodeEdit::_set_impl(const StringName &p_name, const Variant &p_value,
node_path_target = es->get_node(p_value);
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(vformat(TTR("Set %s on %d nodes"), name, get_node_count()), UndoRedo::MERGE_ENDS);
for (const NodePath &E : nodes) {
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 8e94ae871b..7c23e19564 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -91,7 +91,7 @@ void AbstractPolygon2DEditor::_set_polygon(int p_idx, const Variant &p_polygon)
void AbstractPolygon2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
Node2D *node = _get_node();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(node, "set_polygon", p_polygon);
undo_redo->add_undo_method(node, "set_polygon", p_previous);
}
@@ -101,7 +101,7 @@ Vector2 AbstractPolygon2DEditor::_get_offset(int p_idx) const {
}
void AbstractPolygon2DEditor::_commit_action() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
undo_redo->add_undo_method(canvas_item_editor, "update_viewport");
undo_redo->commit_action();
@@ -205,7 +205,7 @@ void AbstractPolygon2DEditor::_wip_close() {
if (_is_line()) {
_set_polygon(0, wip);
} else if (wip.size() >= (_is_line() ? 2 : 3)) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Polygon"));
_action_add_polygon(wip);
if (_has_uv()) {
@@ -257,7 +257,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
return false;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> mb = p_event;
if (!_has_resource()) {
@@ -619,7 +619,7 @@ void AbstractPolygon2DEditor::_bind_methods() {
}
void AbstractPolygon2DEditor::remove_point(const Vertex &p_vertex) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Vector<Vector2> vertices = _get_polygon(p_vertex.polygon);
if (vertices.size() > (_is_line() ? 2 : 3)) {
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 85cca23e64..33aebe5883 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -157,7 +157,7 @@ void AnimationNodeBlendSpace1DEditor::_blend_space_gui_input(const Ref<InputEven
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
@@ -351,7 +351,7 @@ void AnimationNodeBlendSpace1DEditor::_config_changed(double) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace1D Config"));
undo_redo->add_do_method(blend_space.ptr(), "set_max_space", max_value->get_value());
undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
@@ -375,7 +375,7 @@ void AnimationNodeBlendSpace1DEditor::_labels_changed(String) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace1D Labels"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(blend_space.ptr(), "set_value_label", label_value->get_text());
undo_redo->add_undo_method(blend_space.ptr(), "set_value_label", blend_space->get_value_label());
@@ -431,7 +431,7 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
@@ -450,7 +450,7 @@ void AnimationNodeBlendSpace1DEditor::_add_animation_type(int p_index) {
anim->set_animation(animations_to_add[p_index]);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Animation Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
@@ -524,7 +524,7 @@ void AnimationNodeBlendSpace1DEditor::_erase_selected() {
if (selected_point != -1) {
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove BlendSpace1D Point"));
undo_redo->add_do_method(blend_space.ptr(), "remove_blend_point", selected_point);
undo_redo->add_undo_method(blend_space.ptr(), "add_blend_point", blend_space->get_blend_point_node(selected_point), blend_space->get_blend_point_position(selected_point), selected_point);
@@ -544,7 +544,7 @@ void AnimationNodeBlendSpace1DEditor::_edit_point_pos(double) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move BlendSpace1D Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, edit_value->get_value());
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index c22f0a9f15..0daf934e17 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -74,7 +74,6 @@ void AnimationNodeBlendSpace2DEditor::edit(const Ref<AnimationNode> &p_node) {
}
tool_create->set_disabled(read_only);
- interpolation->set_disabled(read_only);
max_x_value->set_editable(!read_only);
min_x_value->set_editable(!read_only);
max_y_value->set_editable(!read_only);
@@ -228,7 +227,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Triangle"));
undo_redo->add_do_method(blend_space.ptr(), "add_triangle", making_triangle[0], making_triangle[1], making_triangle[2]);
undo_redo->add_undo_method(blend_space.ptr(), "remove_triangle", blend_space->get_triangle_count());
@@ -254,7 +253,7 @@ void AnimationNodeBlendSpace2DEditor::_blend_space_gui_input(const Ref<InputEven
if (!read_only) {
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, point);
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
@@ -362,7 +361,7 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", node, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
@@ -381,7 +380,7 @@ void AnimationNodeBlendSpace2DEditor::_add_animation_type(int p_index) {
anim->set_animation(animations_to_add[p_index]);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Animation Point"));
undo_redo->add_do_method(blend_space.ptr(), "add_blend_point", anim, add_point_pos);
undo_redo->add_undo_method(blend_space.ptr(), "remove_blend_point", blend_space->get_blend_point_count());
@@ -676,7 +675,7 @@ void AnimationNodeBlendSpace2DEditor::_config_changed(double) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace2D Config"));
undo_redo->add_do_method(blend_space.ptr(), "set_max_space", Vector2(max_x_value->get_value(), max_y_value->get_value()));
undo_redo->add_undo_method(blend_space.ptr(), "set_max_space", blend_space->get_max_space());
@@ -702,7 +701,7 @@ void AnimationNodeBlendSpace2DEditor::_labels_changed(String) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change BlendSpace2D Labels"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(blend_space.ptr(), "set_x_label", label_x->get_text());
undo_redo->add_undo_method(blend_space.ptr(), "set_x_label", blend_space->get_x_label());
@@ -715,7 +714,7 @@ void AnimationNodeBlendSpace2DEditor::_labels_changed(String) {
}
void AnimationNodeBlendSpace2DEditor::_erase_selected() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (selected_point != -1) {
updating = true;
undo_redo->create_action(TTR("Remove BlendSpace2D Point"));
@@ -778,7 +777,7 @@ void AnimationNodeBlendSpace2DEditor::_edit_point_pos(double) {
return;
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node Point"));
undo_redo->add_do_method(blend_space.ptr(), "set_blend_point_position", selected_point, Vector2(edit_x->get_value(), edit_y->get_value()));
undo_redo->add_undo_method(blend_space.ptr(), "set_blend_point_position", selected_point, blend_space->get_blend_point_position(selected_point));
@@ -856,7 +855,7 @@ void AnimationNodeBlendSpace2DEditor::_open_editor() {
}
void AnimationNodeBlendSpace2DEditor::_auto_triangles_toggled() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Toggle Auto Triangles"));
undo_redo->add_do_method(blend_space.ptr(), "set_auto_triangles", auto_triangles->is_pressed());
undo_redo->add_undo_method(blend_space.ptr(), "set_auto_triangles", blend_space->get_auto_triangles());
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index f680993026..f5f9ec11b3 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -103,7 +103,7 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert
return;
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(tree, p_property, p_value);
undo_redo->add_undo_property(tree, p_property, tree->get(p_property));
@@ -187,7 +187,7 @@ void AnimationNodeBlendTreeEditor::update_graph() {
String base_path = AnimationTreeEditor::get_singleton()->get_base_path() + String(E) + "/" + F.name;
EditorProperty *prop = EditorInspector::instantiate_property_editor(tree, F.type, base_path, F.hint, F.hint_string, F.usage);
if (prop) {
- prop->set_read_only(read_only);
+ prop->set_read_only(read_only || (F.usage & PROPERTY_USAGE_READ_ONLY));
prop->set_object_and_property(tree, base_path);
prop->update_property();
prop->set_name_split_ratio(0);
@@ -363,7 +363,7 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
name = base_name + " " + itos(base);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node to BlendTree"));
undo_redo->add_do_method(blend_tree.ptr(), "add_node", name, anode, instance_pos / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "remove_node", name);
@@ -432,7 +432,7 @@ void AnimationNodeBlendTreeEditor::_popup_hide() {
void AnimationNodeBlendTreeEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_to, const StringName &p_which) {
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node Moved"));
undo_redo->add_do_method(blend_tree.ptr(), "set_node_position", p_which, p_to / EDSCALE);
undo_redo->add_undo_method(blend_tree.ptr(), "set_node_position", p_which, p_from / EDSCALE);
@@ -454,7 +454,7 @@ void AnimationNodeBlendTreeEditor::_connection_request(const String &p_from, int
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Connected"));
undo_redo->add_do_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
undo_redo->add_undo_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
@@ -471,7 +471,7 @@ void AnimationNodeBlendTreeEditor::_disconnection_request(const String &p_from,
graph->disconnect_node(p_from, p_from_index, p_to, p_to_index);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(blend_tree.ptr(), "disconnect_node", p_to, p_to_index);
undo_redo->add_undo_method(blend_tree.ptr(), "connect_node", p_to, p_to_index, p_from);
@@ -487,7 +487,7 @@ void AnimationNodeBlendTreeEditor::_anim_selected(int p_index, Array p_options,
Ref<AnimationNodeAnimation> anim = blend_tree->get_node(p_node);
ERR_FAIL_COND(!anim.is_valid());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Animation"));
undo_redo->add_do_method(anim.ptr(), "set_animation", option);
undo_redo->add_undo_method(anim.ptr(), "set_animation", anim->get_animation());
@@ -501,7 +501,7 @@ void AnimationNodeBlendTreeEditor::_delete_request(const String &p_which) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Node"));
undo_redo->add_do_method(blend_tree.ptr(), "remove_node", p_which);
undo_redo->add_undo_method(blend_tree.ptr(), "add_node", p_which, blend_tree->get_node(p_which), blend_tree.ptr()->get_node_position(p_which));
@@ -546,7 +546,7 @@ void AnimationNodeBlendTreeEditor::_delete_nodes_request(const TypedArray<String
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Node(s)"));
for (const StringName &F : to_erase) {
@@ -580,7 +580,7 @@ void AnimationNodeBlendTreeEditor::_open_in_editor(const String &p_which) {
void AnimationNodeBlendTreeEditor::_filter_toggled() {
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Toggle Filter On/Off"));
undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_enabled", filter_enabled->is_pressed());
undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_enabled", _filter_edit->is_filter_enabled());
@@ -598,7 +598,7 @@ void AnimationNodeBlendTreeEditor::_filter_edited() {
bool filtered = edited->is_checked(0);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Filter"));
undo_redo->add_do_method(_filter_edit.ptr(), "set_filter_path", edited_path, filtered);
undo_redo->add_undo_method(_filter_edit.ptr(), "set_filter_path", edited_path, _filter_edit->is_path_filtered(edited_path));
@@ -981,7 +981,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
String base_path = AnimationTreeEditor::get_singleton()->get_base_path();
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node Renamed"));
undo_redo->add_do_method(blend_tree.ptr(), "rename_node", prev_name, name);
undo_redo->add_undo_method(blend_tree.ptr(), "rename_node", name, prev_name);
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
index 9decbef51b..bf7e419fe4 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -94,7 +94,7 @@ void AnimationLibraryEditor::_add_library_validate(const String &p_name) {
void AnimationLibraryEditor::_add_library_confirm() {
if (adding_animation) {
String anim_name = add_library_name->get_text();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<AnimationLibrary> al = player->call("get_animation_library", adding_animation_to_library);
ERR_FAIL_COND(!al.is_valid());
@@ -111,7 +111,7 @@ void AnimationLibraryEditor::_add_library_confirm() {
} else {
String lib_name = add_library_name->get_text();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<AnimationLibrary> al;
al.instantiate();
@@ -211,7 +211,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
ald->add_animation(animation_name, animation);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Make Animation Library Unique: %s"), lib_name));
undo_redo->add_do_method(player, "remove_animation_library", lib_name);
undo_redo->add_do_method(player, "add_animation_library", lib_name, ald);
@@ -280,7 +280,7 @@ void AnimationLibraryEditor::_file_popup_selected(int p_id) {
Ref<Animation> animd = anim->duplicate();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Make Animation Unique: %s"), anim_name));
undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
undo_redo->add_do_method(al.ptr(), "add_animation", anim_name, animd);
@@ -328,7 +328,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
name = p_path.get_file().get_basename() + " " + itos(attempt);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add Animation Library: %s"), name));
undo_redo->add_do_method(player, "add_animation_library", name, al);
@@ -366,7 +366,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
name = p_path.get_file().get_basename() + " " + itos(attempt);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Load Animation into Library: %s"), name));
undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
@@ -382,7 +382,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
EditorNode::get_singleton()->save_resource_in_path(al, p_path);
if (al->get_path() != prev_path) { // Save successful.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Save Animation library to File: %s"), file_dialog_library));
undo_redo->add_do_method(al.ptr(), "set_path", al->get_path());
@@ -403,7 +403,7 @@ void AnimationLibraryEditor::_load_file(String p_path) {
String prev_path = anim->get_path();
EditorNode::get_singleton()->save_resource_in_path(anim, p_path);
if (anim->get_path() != prev_path) { // Save successful.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Save Animation to File: %s"), file_dialog_animation));
undo_redo->add_do_method(anim.ptr(), "set_path", anim->get_path());
@@ -421,7 +421,7 @@ void AnimationLibraryEditor::_item_renamed() {
String text = ti->get_text(0);
String old_text = ti->get_metadata(0);
bool restore_text = false;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (String(text).contains("/") || String(text).contains(":") || String(text).contains(",") || String(text).contains("[")) {
restore_text = true;
@@ -535,7 +535,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
name = base_name + " (" + itos(attempt) + ")";
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add Animation to Library: %s"), name));
undo_redo->add_do_method(al.ptr(), "add_animation", name, anim);
@@ -554,14 +554,14 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
file_popup->add_separator();
file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_LIBRARY);
Rect2 pos = tree->get_item_rect(p_item, 1, 0);
- Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height);
+ Vector2 popup_pos = tree->get_screen_transform().xform(pos.position + Vector2(0, pos.size.height));
file_popup->popup(Rect2(popup_pos, Size2()));
file_dialog_animation = StringName();
file_dialog_library = lib_name;
} break;
case LIB_BUTTON_DELETE: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove Animation Library: %s"), lib_name));
undo_redo->add_do_method(player, "remove_animation_library", lib_name);
undo_redo->add_undo_method(player, "add_animation_library", lib_name, al);
@@ -594,7 +594,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
file_popup->add_separator();
file_popup->add_item(TTR("Open in Inspector"), FILE_MENU_EDIT_ANIMATION);
Rect2 pos = tree->get_item_rect(p_item, 1, 0);
- Vector2 popup_pos = tree->get_screen_position() + pos.position + Vector2(0, pos.size.height);
+ Vector2 popup_pos = tree->get_screen_transform().xform(pos.position + Vector2(0, pos.size.height));
file_popup->popup(Rect2(popup_pos, Size2()));
file_dialog_animation = anim_name;
@@ -602,7 +602,7 @@ void AnimationLibraryEditor::_button_pressed(TreeItem *p_item, int p_column, int
} break;
case ANIM_BUTTON_DELETE: {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove Animation from Library: %s"), anim_name));
undo_redo->add_do_method(al.ptr(), "remove_animation", anim_name);
undo_redo->add_undo_method(al.ptr(), "add_animation", anim_name, anim);
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 10f2ce25d9..06241d07cf 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -94,6 +94,7 @@ void AnimationPlayerEditor::_notification(int p_what) {
// Need the last frame after it stopped.
frame->set_value(player->get_current_animation_position());
track_editor->set_anim_pos(player->get_current_animation_position());
+ stop->set_icon(stop_icon);
}
last_active = player->is_playing();
@@ -119,8 +120,15 @@ void AnimationPlayerEditor::_notification(int p_what) {
case NOTIFICATION_TRANSLATION_CHANGED:
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
- autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
+ stop_icon = get_theme_icon(SNAME("Stop"), SNAME("EditorIcons"));
+ pause_icon = get_theme_icon(SNAME("Pause"), SNAME("EditorIcons"));
+ if (player && player->is_playing()) {
+ stop->set_icon(pause_icon);
+ } else {
+ stop->set_icon(stop_icon);
+ }
+ autoplay->set_icon(get_theme_icon(SNAME("AutoPlay"), SNAME("EditorIcons")));
play->set_icon(get_theme_icon(SNAME("PlayStart"), SNAME("EditorIcons")));
play_from->set_icon(get_theme_icon(SNAME("Play"), SNAME("EditorIcons")));
play_bw->set_icon(get_theme_icon(SNAME("PlayStartBackwards"), SNAME("EditorIcons")));
@@ -137,7 +145,6 @@ void AnimationPlayerEditor::_notification(int p_what) {
autoplay_reset_img->blit_rect(reset_img, Rect2i(Point2i(), icon_size), Point2i(icon_size.x, 0));
autoplay_reset_icon = ImageTexture::create_from_image(autoplay_reset_img);
}
- stop->set_icon(get_theme_icon(SNAME("Stop"), SNAME("EditorIcons")));
onion_toggle->set_icon(get_theme_icon(SNAME("Onion"), SNAME("EditorIcons")));
onion_skinning->set_icon(get_theme_icon(SNAME("GuiTabMenuHl"), SNAME("EditorIcons")));
@@ -170,7 +177,7 @@ void AnimationPlayerEditor::_autoplay_pressed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
String current = animation->get_item_text(animation->get_selected());
if (player->get_autoplay() == current) {
//unset
@@ -204,7 +211,7 @@ void AnimationPlayerEditor::_play_pressed() {
}
//unstop
- stop->set_pressed(false);
+ stop->set_icon(pause_icon);
}
void AnimationPlayerEditor::_play_from_pressed() {
@@ -221,7 +228,7 @@ void AnimationPlayerEditor::_play_from_pressed() {
}
//unstop
- stop->set_pressed(false);
+ stop->set_icon(pause_icon);
}
String AnimationPlayerEditor::_get_current() const {
@@ -242,7 +249,7 @@ void AnimationPlayerEditor::_play_bw_pressed() {
}
//unstop
- stop->set_pressed(false);
+ stop->set_icon(pause_icon);
}
void AnimationPlayerEditor::_play_bw_from_pressed() {
@@ -259,7 +266,7 @@ void AnimationPlayerEditor::_play_bw_from_pressed() {
}
//unstop
- stop->set_pressed(false);
+ stop->set_icon(pause_icon);
}
void AnimationPlayerEditor::_stop_pressed() {
@@ -267,9 +274,16 @@ void AnimationPlayerEditor::_stop_pressed() {
return;
}
- player->pause();
- play->set_pressed(false);
- stop->set_pressed(true);
+ if (player->is_playing()) {
+ player->pause();
+ } else {
+ String current = _get_current();
+ player->stop();
+ player->set_assigned_animation(current);
+ frame->set_value(0);
+ track_editor->set_anim_pos(0);
+ }
+ stop->set_icon(stop_icon);
}
void AnimationPlayerEditor::_animation_selected(int p_which) {
@@ -310,7 +324,7 @@ void AnimationPlayerEditor::_animation_selected(int p_which) {
void AnimationPlayerEditor::_animation_new() {
int count = 1;
- String base = TTR("New Anim");
+ String base = "new_animation";
String current_library_name = "";
if (animation->has_selectable_items()) {
String current_animation_name = animation->get_item_text(animation->get_selected());
@@ -323,7 +337,7 @@ void AnimationPlayerEditor::_animation_new() {
while (true) {
String attempt = base;
if (count > 1) {
- attempt += " (" + itos(count) + ")";
+ attempt += vformat("_%d", count);
}
if (player->has_animation(attempt_prefix + attempt)) {
count++;
@@ -388,7 +402,7 @@ void AnimationPlayerEditor::_animation_remove_confirmed() {
if (current.contains("/")) {
current = current.get_slice("/", 1);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Animation"));
if (player->get_autoplay() == current) {
undo_redo->add_do_method(player, "set_autoplay", "");
@@ -464,7 +478,7 @@ void AnimationPlayerEditor::_animation_name_edited() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (name_dialog_op) {
case TOOL_RENAME_ANIM: {
String current = animation->get_item_text(animation->get_selected());
@@ -599,7 +613,7 @@ void AnimationPlayerEditor::_blend_editor_next_changed(const int p_idx) {
String current = animation->get_item_text(animation->get_selected());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Blend Next Changed"));
undo_redo->add_do_method(player, "animation_set_next", current, blend_editor.next->get_item_text(p_idx));
undo_redo->add_undo_method(player, "animation_set_next", current, player->animation_get_next(current));
@@ -686,7 +700,7 @@ void AnimationPlayerEditor::_blend_edited() {
float blend_time = selected->get_range(1);
float prev_blend_time = player->get_blend_time(current, to);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Blend Time"));
undo_redo->add_do_method(player, "set_blend_time", current, to, blend_time);
undo_redo->add_undo_method(player, "set_blend_time", current, to, prev_blend_time);
@@ -798,12 +812,9 @@ void AnimationPlayerEditor::_update_animation() {
updating = true;
if (player->is_playing()) {
- play->set_pressed(true);
- stop->set_pressed(false);
-
+ stop->set_icon(pause_icon);
} else {
- play->set_pressed(false);
- stop->set_pressed(true);
+ stop->set_icon(stop_icon);
}
scale->set_text(String::num(player->get_speed_scale(), 2));
@@ -1663,7 +1674,6 @@ AnimationPlayerEditor::AnimationPlayerEditor(AnimationPlayerEditorPlugin *p_plug
stop = memnew(Button);
stop->set_flat(true);
- stop->set_toggle_mode(true);
hb->add_child(stop);
stop->set_tooltip_text(TTR("Stop animation playback. (S)"));
diff --git a/editor/plugins/animation_player_editor_plugin.h b/editor/plugins/animation_player_editor_plugin.h
index 6c690c812c..327200506f 100644
--- a/editor/plugins/animation_player_editor_plugin.h
+++ b/editor/plugins/animation_player_editor_plugin.h
@@ -101,6 +101,8 @@ class AnimationPlayerEditor : public VBoxContainer {
OptionButton *library = nullptr;
Label *name_title = nullptr;
+ Ref<Texture2D> stop_icon;
+ Ref<Texture2D> pause_icon;
Ref<Texture2D> autoplay_icon;
Ref<Texture2D> reset_icon;
Ref<ImageTexture> autoplay_reset_icon;
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 0de5064a00..a675495429 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -246,7 +246,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
Ref<AnimationNode> an = state_machine->get_node(selected_node);
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node"));
for (int i = 0; i < node_rects.size(); i++) {
@@ -543,7 +543,7 @@ void AnimationNodeStateMachineEditor::_group_selected_nodes() {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action("Group");
// Move selected nodes to the new state machine
@@ -658,7 +658,7 @@ void AnimationNodeStateMachineEditor::_ungroup_selected_nodes() {
Vector<TransitionUR> transitions_ur;
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action("Ungroup");
// Move all child nodes to current state machine
@@ -935,7 +935,7 @@ void AnimationNodeStateMachineEditor::_stop_connecting() {
void AnimationNodeStateMachineEditor::_delete_selected() {
TreeItem *item = delete_tree->get_next_selected(nullptr);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
while (item) {
if (!updating) {
updating = true;
@@ -963,7 +963,7 @@ void AnimationNodeStateMachineEditor::_delete_all() {
selected_multi_transition = TransitionLine();
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action("Transition(s) Removed");
_erase_selected(true);
for (int i = 0; i < multi_transitions.size(); i++) {
@@ -1043,7 +1043,7 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node and Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, node, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
@@ -1070,7 +1070,7 @@ void AnimationNodeStateMachineEditor::_add_animation_type(int p_index) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node and Transition"));
undo_redo->add_do_method(state_machine.ptr(), "add_node", name, anim, add_node_pos);
undo_redo->add_undo_method(state_machine.ptr(), "remove_node", name);
@@ -1100,7 +1100,7 @@ void AnimationNodeStateMachineEditor::_add_transition(const bool p_nested_action
tr->set_advance_mode(auto_advance->is_pressed() ? AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_AUTO : AnimationNodeStateMachineTransition::AdvanceMode::ADVANCE_MODE_ENABLED);
tr->set_switch_mode(AnimationNodeStateMachineTransition::SwitchMode(switch_mode->get_selected()));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (!p_nested_action) {
updating = true;
undo_redo->create_action(TTR("Add Transition"));
@@ -1778,7 +1778,7 @@ void AnimationNodeStateMachineEditor::_name_edited(const String &p_text) {
}
updating = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node Renamed"));
undo_redo->add_do_method(state_machine.ptr(), "rename_node", prev_name, name);
undo_redo->add_undo_method(state_machine.ptr(), "rename_node", name, prev_name);
@@ -1813,7 +1813,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
if (!p_nested_action) {
updating = true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node Removed"));
for (int i = 0; i < node_rects.size(); i++) {
@@ -1882,7 +1882,7 @@ void AnimationNodeStateMachineEditor::_erase_selected(const bool p_nested_action
if (!p_nested_action) {
updating = true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Transition Removed"));
undo_redo->add_do_method(state_machine.ptr(), "remove_transition", selected_transition_from, selected_transition_to);
undo_redo->add_undo_method(state_machine.ptr(), "add_transition", selected_transition_from, selected_transition_to, tr);
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index 9f2cfc8d9c..eab5eb0404 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -705,6 +705,12 @@ const char *EditorAssetLibrary::support_key[SUPPORT_MAX] = {
"testing",
};
+const char *EditorAssetLibrary::support_text[SUPPORT_MAX] = {
+ TTRC("Official"),
+ TTRC("Community"),
+ TTRC("Testing"),
+};
+
void EditorAssetLibrary::_select_author(int p_id) {
// Open author window.
}
@@ -1242,15 +1248,28 @@ void EditorAssetLibrary::_http_request_completed(int p_status, int p_code, const
library_vb->add_child(asset_bottom_page);
if (result.is_empty()) {
+ String support_list;
+ for (int i = 0; i < SUPPORT_MAX; i++) {
+ if (support->get_popup()->is_item_checked(i)) {
+ if (!support_list.is_empty()) {
+ support_list += ", ";
+ }
+ support_list += TTRGET(support_text[i]);
+ }
+ }
+ if (support_list.is_empty()) {
+ support_list = "-";
+ }
+
if (!filter->get_text().is_empty()) {
library_info->set_text(
- vformat(TTR("No results for \"%s\"."), filter->get_text()));
+ vformat(TTR("No results for \"%s\" for support level(s): %s."), filter->get_text(), support_list));
} else {
// No results, even though the user didn't search for anything specific.
// This is typically because the version number changed recently
// and no assets compatible with the new version have been published yet.
library_info->set_text(
- vformat(TTR("No results compatible with %s %s."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH)));
+ vformat(TTR("No results compatible with %s %s for support level(s): %s.\nCheck the enabled support levels using the 'Support' button in the top-right corner."), String(VERSION_SHORT_NAME).capitalize(), String(VERSION_BRANCH), support_list));
}
library_info->show();
} else {
@@ -1510,9 +1529,9 @@ EditorAssetLibrary::EditorAssetLibrary(bool p_templates_only) {
search_hb2->add_child(support);
support->set_text(TTR("Support"));
support->get_popup()->set_hide_on_checkable_item_selection(false);
- support->get_popup()->add_check_item(TTR("Official"), SUPPORT_OFFICIAL);
- support->get_popup()->add_check_item(TTR("Community"), SUPPORT_COMMUNITY);
- support->get_popup()->add_check_item(TTR("Testing"), SUPPORT_TESTING);
+ support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_OFFICIAL]), SUPPORT_OFFICIAL);
+ support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_COMMUNITY]), SUPPORT_COMMUNITY);
+ support->get_popup()->add_check_item(TTRGET(support_text[SUPPORT_TESTING]), SUPPORT_TESTING);
support->get_popup()->set_item_checked(SUPPORT_OFFICIAL, true);
support->get_popup()->set_item_checked(SUPPORT_COMMUNITY, true);
support->get_popup()->connect("id_pressed", callable_mp(this, &EditorAssetLibrary::_support_toggled));
diff --git a/editor/plugins/asset_library_editor_plugin.h b/editor/plugins/asset_library_editor_plugin.h
index 0667f474da..8c74da0e2a 100644
--- a/editor/plugins/asset_library_editor_plugin.h
+++ b/editor/plugins/asset_library_editor_plugin.h
@@ -234,6 +234,7 @@ class EditorAssetLibrary : public PanelContainer {
static const char *sort_key[SORT_MAX];
static const char *sort_text[SORT_MAX];
static const char *support_key[SUPPORT_MAX];
+ static const char *support_text[SUPPORT_MAX];
///MainListing
diff --git a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
index acd3271f97..bb3b8a124e 100644
--- a/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
+++ b/editor/plugins/audio_stream_randomizer_editor_plugin.cpp
@@ -44,8 +44,8 @@ void AudioStreamRandomizerEditorPlugin::make_visible(bool p_visible) {
}
void AudioStreamRandomizerEditorPlugin::_move_stream_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo_man.is_null());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
AudioStreamRandomizer *randomizer = Object::cast_to<AudioStreamRandomizer>(p_edited);
if (!randomizer) {
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index bd7b7ff1cb..4c14755b03 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -868,7 +868,7 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(action_name);
for (CanvasItem *ci : modified_canvas_items) {
CanvasItemEditorSelectedItem *se = editor_selection->get_node_editor_data<CanvasItemEditorSelectedItem>(ci);
@@ -933,7 +933,7 @@ void CanvasItemEditor::_add_node_pressed(int p_result) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Node(s) to Position"));
for (Node *node : nodes_to_move) {
CanvasItem *ci = Object::cast_to<CanvasItem>(node);
@@ -1022,7 +1022,7 @@ void CanvasItemEditor::_on_grid_menu_id_pressed(int p_id) {
}
bool CanvasItemEditor::_gui_input_rulers_and_guides(const Ref<InputEvent> &p_event) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> b = p_event;
Ref<InputEventMouseMotion> m = p_event;
@@ -1850,7 +1850,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() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_ctrl_pressed()) || tool == TOOL_SCALE)) {
+ if (b.is_valid() && b->get_button_index() == MouseButton::LEFT && b->is_pressed() && ((b->is_alt_pressed() && b->is_command_or_control_pressed()) || tool == TOOL_SCALE)) {
List<CanvasItem *> selection = _get_edited_canvas_items();
if (selection.size() == 1) {
CanvasItem *ci = selection[0];
@@ -1897,7 +1897,7 @@ bool CanvasItemEditor::_gui_input_scale(const Ref<InputEvent> &p_event) {
Transform2D simple_xform = (viewport->get_transform() * unscaled_transform).affine_inverse() * transform;
bool uniform = m->is_shift_pressed();
- bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
+ bool is_ctrl = m->is_ctrl_pressed();
Point2 drag_from_local = simple_xform.xform(drag_from);
Point2 drag_to_local = simple_xform.xform(drag_to);
@@ -1989,7 +1989,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() == MouseButton::LEFT && b->is_pressed()) {
- if ((b->is_alt_pressed() && !b->is_ctrl_pressed()) || tool == TOOL_MOVE) {
+ if ((b->is_alt_pressed() && !b->is_command_or_control_pressed()) || tool == TOOL_MOVE) {
List<CanvasItem *> selection = _get_edited_canvas_items();
drag_selection.clear();
@@ -3418,7 +3418,7 @@ void CanvasItemEditor::_draw_selection() {
}
// Draw the move handles
- bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CTRL);
+ bool is_ctrl = Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
bool is_alt = Input::get_singleton()->is_key_pressed(Key::ALT);
if (tool == TOOL_MOVE && show_transformation_gizmos) {
if (_is_node_movable(ci)) {
@@ -4263,7 +4263,7 @@ void CanvasItemEditor::_update_override_camera_button(bool p_game_running) {
}
void CanvasItemEditor::_popup_callback(int p_op) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
last_option = MenuOption(p_op);
switch (p_op) {
case SHOW_ORIGIN: {
@@ -5570,7 +5570,7 @@ void CanvasItemEditorViewport::_create_nodes(Node *parent, Node *child, String &
String name = path.get_file().get_basename();
child->set_name(Node::adjust_name_casing(name));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<Texture2D> texture = ResourceCache::get_ref(path);
if (parent) {
@@ -5649,7 +5649,7 @@ bool CanvasItemEditorViewport::_create_instance(Node *parent, String &path, cons
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
undo_redo->add_do_method(instantiated_scene, "set_owner", edited_scene);
undo_redo->add_do_reference(instantiated_scene);
@@ -5690,7 +5690,7 @@ void CanvasItemEditorViewport::_perform_drop_data() {
Vector<String> error_files;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Node"));
for (int i = 0; i < selected_files.size(); i++) {
diff --git a/editor/plugins/cast_2d_editor_plugin.cpp b/editor/plugins/cast_2d_editor_plugin.cpp
index 078198e64b..723082c293 100644
--- a/editor/plugins/cast_2d_editor_plugin.cpp
+++ b/editor/plugins/cast_2d_editor_plugin.cpp
@@ -77,7 +77,7 @@ bool Cast2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_event) {
return false;
}
} else if (pressed) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set target_position"));
undo_redo->add_do_property(node, "target_position", target_position);
undo_redo->add_do_method(canvas_item_editor, "update_viewport");
diff --git a/editor/plugins/collision_shape_2d_editor_plugin.cpp b/editor/plugins/collision_shape_2d_editor_plugin.cpp
index bed4658976..c2d5885e43 100644
--- a/editor/plugins/collision_shape_2d_editor_plugin.cpp
+++ b/editor/plugins/collision_shape_2d_editor_plugin.cpp
@@ -219,7 +219,7 @@ void CollisionShape2DEditor::set_handle(int idx, Point2 &p_point) {
}
void CollisionShape2DEditor::commit_handle(int idx, Variant &p_org) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Handle"));
switch (shape_type) {
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index ad3e861b79..470b90aa7f 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -721,7 +721,7 @@ void ControlEditorToolbar::_anchors_preset_selected(int p_preset) {
LayoutPreset preset = (LayoutPreset)p_preset;
List<Node *> selection = editor_selection->get_selected_node_list();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Anchors, Offsets, Grow Direction"));
for (Node *E : selection) {
@@ -742,7 +742,7 @@ void ControlEditorToolbar::_anchors_preset_selected(int p_preset) {
void ControlEditorToolbar::_anchors_to_current_ratio() {
List<Node *> selection = editor_selection->get_selected_node_list();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Anchors, Offsets (Keep Ratio)"));
for (Node *E : selection) {
@@ -793,7 +793,7 @@ void ControlEditorToolbar::_anchor_mode_toggled(bool p_status) {
void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertical) {
List<Node *> selection = editor_selection->get_selected_node_list();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_vertical) {
undo_redo->create_action(TTR("Change Vertical Size Flags"));
} else {
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index b0bcda946e..20710bac19 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -140,7 +140,7 @@ void CurveEditor::gui_input(const Ref<InputEvent> &p_event) {
if (!mb.is_pressed() && _dragging && mb.get_button_index() == MouseButton::LEFT) {
_dragging = false;
if (_has_undo_data) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(_selected_tangent == TANGENT_NONE ? TTR("Modify Curve Point") : TTR("Modify Curve Tangent"));
undo_redo->add_do_method(*_curve_ref, "_set_data", _curve_ref->get_data());
undo_redo->add_undo_method(*_curve_ref, "_set_data", _undo_data);
@@ -301,7 +301,7 @@ void CurveEditor::on_preset_item_selected(int preset_id) {
break;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Load Curve Preset"));
undo_redo->add_do_method(&curve, "_set_data", curve.get_data());
undo_redo->add_undo_method(&curve, "_set_data", previous_data);
@@ -433,7 +433,7 @@ CurveEditor::TangentIndex CurveEditor::get_tangent_at(Vector2 pos) const {
void CurveEditor::add_point(Vector2 pos) {
ERR_FAIL_COND(_curve_ref.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Curve Point"));
Vector2 point_pos = get_world_pos(pos);
@@ -455,7 +455,7 @@ void CurveEditor::add_point(Vector2 pos) {
void CurveEditor::remove_point(int index) {
ERR_FAIL_COND(_curve_ref.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Curve Point"));
Curve::Point p = _curve_ref->get_point(index);
@@ -477,7 +477,7 @@ void CurveEditor::remove_point(int index) {
void CurveEditor::toggle_linear(TangentIndex tangent) {
ERR_FAIL_COND(_curve_ref.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Toggle Curve Linear Tangent"));
if (tangent == TANGENT_NONE) {
@@ -621,8 +621,8 @@ struct CanvasItemPlotCurve {
color2(p_color2) {}
void operator()(Vector2 pos0, Vector2 pos1, bool in_definition) {
- // FIXME: Using a line width greater than 1 breaks curve rendering
- ci.draw_line(pos0, pos1, in_definition ? color1 : color2, 1);
+ // FIXME: Using a quad line breaks curve rendering.
+ ci.draw_line(pos0, pos1, in_definition ? color1 : color2, -1);
}
};
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index 1a51224198..04b2a9337e 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -113,7 +113,7 @@ void GPUParticles2DEditorPlugin::_menu_callback(int p_idx) {
cpu_particles->set_process_mode(particles->get_process_mode());
cpu_particles->set_z_index(particles->get_z_index());
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Convert to CPUParticles2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", particles, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
@@ -161,7 +161,7 @@ void GPUParticles2DEditorPlugin::_generate_visibility_rect() {
particles->set_emitting(false);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Generate Visibility Rect"));
undo_redo->add_do_method(particles, "set_visibility_rect", rect);
undo_redo->add_undo_method(particles, "set_visibility_rect", particles->get_visibility_rect());
diff --git a/editor/plugins/gpu_particles_3d_editor_plugin.cpp b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
index 19ac553708..65f66c2661 100644
--- a/editor/plugins/gpu_particles_3d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_3d_editor_plugin.cpp
@@ -274,7 +274,7 @@ void GPUParticles3DEditor::_menu_option(int p_option) {
cpu_particles->set_visible(node->is_visible());
cpu_particles->set_process_mode(node->get_process_mode());
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Convert to CPUParticles3D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, cpu_particles, true, false);
ur->add_do_reference(cpu_particles);
@@ -324,7 +324,7 @@ void GPUParticles3DEditor::_generate_aabb() {
node->set_emitting(false);
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Generate Visibility AABB"));
ur->add_do_method(node, "set_visibility_aabb", rect);
ur->add_undo_method(node, "set_visibility_aabb", node->get_visibility_aabb());
diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp
index 68aafd6fa8..3676c2c222 100644
--- a/editor/plugins/gradient_editor.cpp
+++ b/editor/plugins/gradient_editor.cpp
@@ -99,7 +99,7 @@ void GradientEditor::_gradient_changed() {
void GradientEditor::_ramp_changed() {
editing = true;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Gradient Edited"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(gradient.ptr(), "set_offsets", get_offsets());
undo_redo->add_do_method(gradient.ptr(), "set_colors", get_colors());
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index e03353a67b..7bd159a5b8 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -55,7 +55,7 @@ void GradientTexture2DEditorRect::_update_fill_position() {
String property_name = handle == HANDLE_FILL_FROM ? "fill_from" : "fill_to";
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Set %s"), property_name), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(texture.ptr(), property_name, percent);
undo_redo->add_undo_property(texture.ptr(), property_name, handle == HANDLE_FILL_FROM ? texture->get_fill_from() : texture->get_fill_to());
@@ -188,7 +188,7 @@ GradientTexture2DEditorRect::GradientTexture2DEditorRect() {
///////////////////////
void GradientTexture2DEditor::_reverse_button_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Swap GradientTexture2D Fill Points"));
undo_redo->add_do_property(texture.ptr(), "fill_from", texture->get_fill_to());
undo_redo->add_do_property(texture.ptr(), "fill_to", texture->get_fill_from());
diff --git a/editor/plugins/light_occluder_2d_editor_plugin.cpp b/editor/plugins/light_occluder_2d_editor_plugin.cpp
index bee1206b90..429add4540 100644
--- a/editor/plugins/light_occluder_2d_editor_plugin.cpp
+++ b/editor/plugins/light_occluder_2d_editor_plugin.cpp
@@ -84,7 +84,7 @@ void LightOccluder2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) co
void LightOccluder2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
Ref<OccluderPolygon2D> occluder = _ensure_occluder();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(occluder.ptr(), "set_polygon", p_polygon);
undo_redo->add_undo_method(occluder.ptr(), "set_polygon", p_previous);
}
@@ -98,7 +98,7 @@ void LightOccluder2DEditor::_create_resource() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Occluder Polygon"));
undo_redo->add_do_method(node, "set_occluder_polygon", Ref<OccluderPolygon2D>(memnew(OccluderPolygon2D)));
undo_redo->add_undo_method(node, "set_occluder_polygon", Variant(Ref<RefCounted>()));
diff --git a/editor/plugins/line_2d_editor_plugin.cpp b/editor/plugins/line_2d_editor_plugin.cpp
index f2c487dd14..0185617c36 100644
--- a/editor/plugins/line_2d_editor_plugin.cpp
+++ b/editor/plugins/line_2d_editor_plugin.cpp
@@ -55,7 +55,7 @@ void Line2DEditor::_set_polygon(int p_idx, const Variant &p_polygon) const {
void Line2DEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
Node2D *_node = _get_node();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(_node, "set_points", p_polygon);
undo_redo->add_undo_method(_node, "set_points", p_previous);
}
diff --git a/editor/plugins/material_editor_plugin.cpp b/editor/plugins/material_editor_plugin.cpp
index bb2bac7c04..36c143ca8d 100644
--- a/editor/plugins/material_editor_plugin.cpp
+++ b/editor/plugins/material_editor_plugin.cpp
@@ -291,8 +291,8 @@ void EditorInspectorPluginMaterial::parse_begin(Object *p_object) {
}
void EditorInspectorPluginMaterial::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- Ref<EditorUndoRedoManager> undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo.is_valid());
+ EditorUndoRedoManager *undo_redo = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo);
// For BaseMaterial3D, if a roughness or metallic textures is being assigned to an empty slot,
// set the respective metallic or roughness factor to 1.0 as a convenience feature
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index 6cc551d367..e8976667dd 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -65,7 +65,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
switch (p_option) {
case MENU_OPTION_CREATE_STATIC_TRIMESH_BODY: {
EditorSelection *editor_selection = EditorNode::get_singleton()->get_editor_selection();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
List<Node *> selection = editor_selection->get_selected_node_list();
@@ -152,7 +152,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
Node *owner = get_tree()->get_edited_scene_root();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Trimesh Static Shape"));
@@ -182,7 +182,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (simplify) {
ur->create_action(TTR("Create Simplified Convex Shape"));
@@ -222,7 +222,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Multiple Convex Shapes"));
@@ -259,7 +259,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
Node *owner = get_tree()->get_edited_scene_root();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Navigation Mesh"));
ur->add_do_method(node, "add_child", nmi, true);
@@ -275,7 +275,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
outline_dialog->popup_centered(Vector2(200, 90));
} break;
case MENU_OPTION_CREATE_DEBUG_TANGENTS: {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Debug Tangents"));
MeshInstance3D *tangents = node->create_debug_tangents_node();
@@ -334,7 +334,7 @@ void MeshInstance3DEditor::_menu_option(int p_option) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Unwrap UV2"));
ur->add_do_method(node, "set_mesh", unwrapped_mesh);
@@ -460,7 +460,7 @@ void MeshInstance3DEditor::_debug_uv_draw() {
debug_uv->draw_rect(Rect2(Vector2(), debug_uv->get_size()), get_theme_color(SNAME("dark_color_3"), SNAME("Editor")));
debug_uv->draw_set_transform(Vector2(), 0, debug_uv->get_size());
// Use a translucent color to allow overlapping triangles to be visible.
- debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5), Math::round(EDSCALE));
+ debug_uv->draw_multiline(uv_lines, get_theme_color(SNAME("mono_color"), SNAME("Editor")) * Color(1, 1, 1, 0.5));
}
void MeshInstance3DEditor::_create_outline_mesh() {
@@ -493,7 +493,7 @@ void MeshInstance3DEditor::_create_outline_mesh() {
mi->set_mesh(mesho);
Node *owner = get_tree()->get_edited_scene_root();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Outline"));
diff --git a/editor/plugins/navigation_link_2d_editor_plugin.cpp b/editor/plugins/navigation_link_2d_editor_plugin.cpp
index 53f9ff019f..21a1d839f0 100644
--- a/editor/plugins/navigation_link_2d_editor_plugin.cpp
+++ b/editor/plugins/navigation_link_2d_editor_plugin.cpp
@@ -85,7 +85,7 @@ bool NavigationLink2DEditor::forward_canvas_gui_input(const Ref<InputEvent> &p_e
end_grabbed = false;
}
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (start_grabbed) {
undo_redo->create_action(TTR("Set start_location"));
undo_redo->add_do_method(node, "set_start_location", node->get_start_location());
diff --git a/editor/plugins/navigation_polygon_editor_plugin.cpp b/editor/plugins/navigation_polygon_editor_plugin.cpp
index cbc225a7ff..957a520d8a 100644
--- a/editor/plugins/navigation_polygon_editor_plugin.cpp
+++ b/editor/plugins/navigation_polygon_editor_plugin.cpp
@@ -76,7 +76,7 @@ void NavigationPolygonEditor::_set_polygon(int p_idx, const Variant &p_polygon)
void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
Ref<NavigationPolygon> navpoly = _ensure_navpoly();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "add_outline", p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "remove_outline", navpoly->get_outline_count());
undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
@@ -85,7 +85,7 @@ void NavigationPolygonEditor::_action_add_polygon(const Variant &p_polygon) {
void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
Ref<NavigationPolygon> navpoly = _ensure_navpoly();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "remove_outline", p_idx);
undo_redo->add_undo_method(navpoly.ptr(), "add_outline_at_index", navpoly->get_outline(p_idx), p_idx);
undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
@@ -94,7 +94,7 @@ void NavigationPolygonEditor::_action_remove_polygon(int p_idx) {
void NavigationPolygonEditor::_action_set_polygon(int p_idx, const Variant &p_previous, const Variant &p_polygon) {
Ref<NavigationPolygon> navpoly = _ensure_navpoly();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(navpoly.ptr(), "set_outline", p_idx, p_polygon);
undo_redo->add_undo_method(navpoly.ptr(), "set_outline", p_idx, p_previous);
undo_redo->add_do_method(navpoly.ptr(), "make_polygons_from_outlines");
@@ -110,7 +110,7 @@ void NavigationPolygonEditor::_create_resource() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Navigation Polygon"));
undo_redo->add_do_method(node, "set_navigation_polygon", Ref<NavigationPolygon>(memnew(NavigationPolygon)));
undo_redo->add_undo_method(node, "set_navigation_polygon", Variant(Ref<RefCounted>()));
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index 74db91a309..bb71c27bff 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -1337,13 +1337,13 @@ void Light3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
light->set_param(p_id == 0 ? Light3D::PARAM_RANGE : Light3D::PARAM_SPOT_ANGLE, p_restore);
} else if (p_id == 0) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Light Radius"));
ur->add_do_method(light, "set_param", Light3D::PARAM_RANGE, light->get_param(Light3D::PARAM_RANGE));
ur->add_undo_method(light, "set_param", Light3D::PARAM_RANGE, p_restore);
ur->commit_action();
} else if (p_id == 1) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Light Radius"));
ur->add_do_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, light->get_param(Light3D::PARAM_SPOT_ANGLE));
ur->add_undo_method(light, "set_param", Light3D::PARAM_SPOT_ANGLE, p_restore);
@@ -1562,7 +1562,7 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi
player->set_emission_angle(p_restore);
} else {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change AudioStreamPlayer3D Emission Angle"));
ur->add_do_method(player, "set_emission_angle", player->get_emission_angle());
ur->add_undo_method(player, "set_emission_angle", p_restore);
@@ -1823,7 +1823,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
if (p_cancel) {
camera->set("fov", p_restore);
} else {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Camera FOV"));
ur->add_do_property(camera, "fov", camera->get_fov());
ur->add_undo_property(camera, "fov", p_restore);
@@ -1834,7 +1834,7 @@ void Camera3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_
if (p_cancel) {
camera->set("size", p_restore);
} else {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Camera Size"));
ur->add_do_property(camera, "size", camera->get_size());
ur->add_undo_property(camera, "size", p_restore);
@@ -2160,7 +2160,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(so.ptr(), "set_radius", so->get_radius());
ur->add_undo_method(so.ptr(), "set_radius", p_restore);
@@ -2174,7 +2174,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(bo.ptr(), "set_size", bo->get_size());
ur->add_undo_method(bo.ptr(), "set_size", p_restore);
@@ -2188,7 +2188,7 @@ void OccluderInstance3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_giz
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(qo.ptr(), "set_size", qo->get_size());
ur->add_undo_method(qo.ptr(), "set_size", p_restore);
@@ -2902,7 +2902,7 @@ void VisibleOnScreenNotifier3DGizmoPlugin::commit_handle(const EditorNode3DGizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Notifier AABB"));
ur->add_do_method(notifier, "set_aabb", notifier->get_aabb());
ur->add_undo_method(notifier, "set_aabb", p_restore);
@@ -3093,7 +3093,7 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Particles AABB"));
ur->add_do_method(particles, "set_visibility_aabb", particles->get_visibility_aabb());
ur->add_undo_method(particles, "set_visibility_aabb", p_restore);
@@ -3259,7 +3259,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Radius"));
ur->add_do_method(sn, "set_radius", sn->call("get_radius"));
ur->add_undo_method(sn, "set_radius", p_restore);
@@ -3272,7 +3272,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
@@ -3531,7 +3531,7 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(probe, "set_extents", probe->get_extents());
ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
@@ -3683,7 +3683,7 @@ void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id,
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Decal Extents"));
ur->add_do_method(decal, "set_extents", decal->get_extents());
ur->add_undo_method(decal, "set_extents", restore);
@@ -3823,7 +3823,7 @@ void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_i
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Probe Extents"));
ur->add_do_method(probe, "set_extents", probe->get_extents());
ur->add_undo_method(probe, "set_extents", restore);
@@ -4438,7 +4438,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
ur->add_undo_method(ss.ptr(), "set_radius", p_restore);
@@ -4452,7 +4452,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(ss.ptr(), "set_size", ss->get_size());
ur->add_undo_method(ss.ptr(), "set_size", p_restore);
@@ -4469,7 +4469,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Capsule Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
@@ -4494,7 +4494,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Cylinder Shape Radius"));
ur->add_do_method(ss.ptr(), "set_radius", ss->get_radius());
@@ -4519,7 +4519,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Separation Ray Shape Length"));
ur->add_do_method(ss.ptr(), "set_length", ss->get_length());
ur->add_undo_method(ss.ptr(), "set_length", p_restore);
@@ -5184,7 +5184,7 @@ void NavigationLink3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Start Location"));
ur->add_do_method(link, "set_start_location", link->get_start_location());
@@ -5946,7 +5946,7 @@ void FogVolumeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Fog Volume Extents"));
ur->add_do_method(sn, "set_extents", sn->call("get_extents"));
ur->add_undo_method(sn, "set_extents", p_restore);
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 4fe1a6c034..dea07ab50c 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -3104,7 +3104,7 @@ void Node3DEditorViewport::_draw() {
}
void Node3DEditorViewport::_menu_option(int p_option) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case VIEW_TOP: {
cursor.y_rot = 0;
@@ -3894,8 +3894,6 @@ Dictionary Node3DEditorViewport::get_state() const {
void Node3DEditorViewport::_bind_methods() {
ClassDB::bind_method(D_METHOD("update_transform_gizmo_view"), &Node3DEditorViewport::update_transform_gizmo_view); // Used by call_deferred.
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &Node3DEditorViewport::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &Node3DEditorViewport::drop_data_fw);
ADD_SIGNAL(MethodInfo("toggle_maximize_view", PropertyInfo(Variant::OBJECT, "viewport")));
ADD_SIGNAL(MethodInfo("clicked", PropertyInfo(Variant::OBJECT, "viewport")));
@@ -4257,7 +4255,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
instantiated_scene->set_scene_file_path(ProjectSettings::get_singleton()->localize_path(path));
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(parent, "add_child", instantiated_scene, true);
undo_redo->add_do_method(instantiated_scene, "set_owner", EditorNode::get_singleton()->get_edited_scene());
undo_redo->add_do_reference(instantiated_scene);
@@ -4286,7 +4284,7 @@ bool Node3DEditorViewport::_create_instance(Node *parent, String &path, const Po
}
void Node3DEditorViewport::_perform_drop_data() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (spatial_editor->get_preview_material_target().is_valid()) {
GeometryInstance3D *geometry_instance = Object::cast_to<GeometryInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target()));
MeshInstance3D *mesh_instance = Object::cast_to<MeshInstance3D>(ObjectDB::get_instance(spatial_editor->get_preview_material_target()));
@@ -4496,7 +4494,7 @@ void Node3DEditorViewport::commit_transform() {
TTRC("Translate"),
TTRC("Scale"),
};
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(_transform_name[_edit.mode]);
List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -4921,7 +4919,7 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
c->add_child(viewport);
surface = memnew(Control);
- surface->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CD(surface, Node3DEditorViewport);
add_child(surface);
surface->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
surface->set_clip_contents(true);
@@ -6014,7 +6012,7 @@ void Node3DEditor::_xform_dialog_action() {
t.basis.rotate(rotate);
t.origin = translate;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("XForm Dialog"));
const List<Node *> &selection = editor_selection->get_selected_node_list();
@@ -6126,7 +6124,7 @@ void Node3DEditor::_update_camera_override_viewport(Object *p_viewport) {
}
void Node3DEditor::_menu_item_pressed(int p_option) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case MENU_TOOL_SELECT:
case MENU_TOOL_MOVE:
@@ -7312,7 +7310,7 @@ void Node3DEditor::_snap_selected_nodes_to_floor() {
}
if (snapped_to_floor) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Snap Nodes to Floor"));
// Perform snapping if at least one node can be snapped
@@ -7382,7 +7380,7 @@ void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) {
ERR_FAIL_COND(!base);
Node *new_sun = preview_sun->duplicate();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Preview Sun to Scene"));
undo_redo->add_do_method(base, "add_child", new_sun, true);
// Move to the beginning of the scene tree since more "global" nodes
@@ -7416,7 +7414,7 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
new_env->set_camera_attributes(preview_environment->get_camera_attributes()->duplicate(true));
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Preview Environment to Scene"));
undo_redo->add_do_method(base, "add_child", new_env, true);
// Move to the beginning of the scene tree since more "global" nodes
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index b78ffb7612..63f6643ba3 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -120,7 +120,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
}
// Check for point deletion.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if ((mb->get_button_index() == MouseButton::RIGHT && mode == MODE_EDIT) || (mb->get_button_index() == MouseButton::LEFT && mode == MODE_DELETE)) {
if (dist_to_p < grab_threshold) {
undo_redo->create_action(TTR("Remove Point from Curve"));
@@ -155,7 +155,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && ((mb->is_command_or_control_pressed() && mode == MODE_EDIT) || mode == MODE_CREATE)) {
Ref<Curve2D> curve = node->get_curve();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Point to Curve"));
undo_redo->add_do_method(curve.ptr(), "add_point", cpoint);
undo_redo->add_undo_method(curve.ptr(), "remove_point", curve->get_point_count());
@@ -191,7 +191,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
insertion_point = curve->get_point_count() - 2;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Split Curve"));
undo_redo->add_do_method(curve.ptr(), "add_point", xform.affine_inverse().xform(gpoint2), Vector2(0, 0), Vector2(0, 0), insertion_point + 1);
undo_redo->add_undo_method(curve.ptr(), "remove_point", insertion_point + 1);
@@ -215,7 +215,7 @@ bool Path2DEditor::forward_gui_input(const Ref<InputEvent> &p_event) {
if (!mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && action != ACTION_NONE) {
Ref<Curve2D> curve = node->get_curve();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Vector2 new_pos = moving_from + xform.affine_inverse().basis_xform(gpoint - moving_screen_from);
switch (action) {
case ACTION_NONE:
@@ -491,7 +491,7 @@ void Path2DEditor::_mode_selected(int p_mode) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Point from Curve"));
undo_redo->add_do_method(node->get_curve().ptr(), "add_point", begin);
undo_redo->add_undo_method(node->get_curve().ptr(), "remove_point", node->get_curve()->get_point_count());
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index 917b8245a3..75cd04bee8 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -174,7 +174,7 @@ void Path3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant &p_res
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (!p_secondary) {
if (p_cancel) {
@@ -409,7 +409,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
}
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (closest_seg != -1) {
//subdivide
@@ -451,21 +451,21 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
// Find the offset and point index of the place to break up.
// Also check for the control points.
if (dist_to_p < click_dist) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Path Point"));
ur->add_do_method(c.ptr(), "remove_point", i);
ur->add_undo_method(c.ptr(), "add_point", c->get_point_position(i), c->get_point_in(i), c->get_point_out(i), i);
ur->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_out < click_dist) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Out-Control Point"));
ur->add_do_method(c.ptr(), "set_point_out", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_out", i, c->get_point_out(i));
ur->commit_action();
return EditorPlugin::AFTER_GUI_INPUT_STOP;
} else if (dist_to_p_in < click_dist) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove In-Control Point"));
ur->add_do_method(c.ptr(), "set_point_in", i, Vector3());
ur->add_undo_method(c.ptr(), "set_point_in", i, c->get_point_in(i));
@@ -544,7 +544,7 @@ void Path3DEditorPlugin::_close_curve() {
if (c->get_point_position(0) == c->get_point_position(c->get_point_count() - 1)) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Close Curve"));
ur->add_do_method(c.ptr(), "add_point", c->get_point_position(0), c->get_point_in(0), c->get_point_out(0), -1);
ur->add_undo_method(c.ptr(), "remove_point", c->get_point_count());
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 9d8f1a1578..05fc464226 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -156,7 +156,7 @@ void Polygon2DEditor::_sync_bones() {
Array new_bones = node->call("_get_bones");
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Sync Bones"));
undo_redo->add_do_method(node, "_set_bones", new_bones);
undo_redo->add_undo_method(node, "_set_bones", prev_bones);
@@ -286,7 +286,7 @@ void Polygon2DEditor::_uv_edit_popup_hide() {
}
void Polygon2DEditor::_menu_option(int p_option) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case MODE_EDIT_UV: {
if (node->get_texture().is_null()) {
@@ -399,7 +399,7 @@ void Polygon2DEditor::_update_polygon_editing_state() {
void Polygon2DEditor::_commit_action() {
// Makes that undo/redoing actions made outside of the UV editor still affect its polygon.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(uv_edit_draw, "queue_redraw");
undo_redo->add_undo_method(uv_edit_draw, "queue_redraw");
undo_redo->add_do_method(CanvasItemEditor::get_singleton(), "update_viewport");
@@ -467,7 +467,7 @@ void Polygon2DEditor::_uv_input(const Ref<InputEvent> &p_input) {
mtx.columns[2] = -uv_draw_ofs;
mtx.scale_basis(Vector2(uv_draw_zoom, uv_draw_zoom));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 8dc0ca9431..9defb4de9b 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -96,7 +96,7 @@ void Polygon3DEditor::_menu_option(int p_option) {
void Polygon3DEditor::_wip_close() {
Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
ERR_FAIL_COND_MSG(!obj, "Edited object is not valid.");
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create Polygon3D"));
undo_redo->add_undo_method(obj, "set_polygon", obj->call("get_polygon"));
undo_redo->add_do_method(obj, "set_polygon", wip);
@@ -186,7 +186,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
if (mb->is_pressed()) {
if (mb->is_ctrl_pressed()) {
if (poly.size() < 3) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Poly"));
undo_redo->add_undo_method(obj, "set_polygon", poly);
poly.push_back(cpoint);
@@ -265,7 +265,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
ERR_FAIL_INDEX_V(edited_point, poly.size(), EditorPlugin::AFTER_GUI_INPUT_PASS);
poly.write[edited_point] = edited_point_pos;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Poly"));
undo_redo->add_do_method(obj, "set_polygon", poly);
undo_redo->add_undo_method(obj, "set_polygon", pre_move_edit);
@@ -294,7 +294,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
}
if (closest_idx >= 0) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Poly (Remove Point)"));
undo_redo->add_undo_method(obj, "set_polygon", poly);
poly.remove_at(closest_idx);
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index 2a5529e229..dcbff2c756 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -71,7 +71,7 @@ void ResourcePreloaderEditor::_files_load_request(const Vector<String> &p_paths)
name = basename + " " + itos(counter);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Resource"));
undo_redo->add_do_method(preloader, "add_resource", name, resource);
undo_redo->add_undo_method(preloader, "remove_resource", name);
@@ -116,7 +116,7 @@ void ResourcePreloaderEditor::_item_edited() {
}
Ref<Resource> samp = preloader->get_resource(old_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Resource"));
undo_redo->add_do_method(preloader, "remove_resource", old_name);
undo_redo->add_do_method(preloader, "add_resource", new_name, samp);
@@ -129,7 +129,7 @@ void ResourcePreloaderEditor::_item_edited() {
}
void ResourcePreloaderEditor::_remove_resource(const String &p_to_remove) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Resource"));
undo_redo->add_do_method(preloader, "remove_resource", p_to_remove);
undo_redo->add_undo_method(preloader, "add_resource", p_to_remove, preloader->get_resource(p_to_remove));
@@ -163,7 +163,7 @@ void ResourcePreloaderEditor::_paste_pressed() {
name = basename + " " + itos(counter);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Paste Resource"));
undo_redo->add_do_method(preloader, "add_resource", name, r);
undo_redo->add_undo_method(preloader, "remove_resource", name);
@@ -322,7 +322,7 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant
name = basename + "_" + itos(counter);
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Resource"));
undo_redo->add_do_method(preloader, "add_resource", name, r);
undo_redo->add_undo_method(preloader, "remove_resource", name);
@@ -342,10 +342,6 @@ void ResourcePreloaderEditor::drop_data_fw(const Point2 &p_point, const Variant
void ResourcePreloaderEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_library"), &ResourcePreloaderEditor::_update_library);
ClassDB::bind_method(D_METHOD("_remove_resource", "to_remove"), &ResourcePreloaderEditor::_remove_resource);
-
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ResourcePreloaderEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ResourcePreloaderEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ResourcePreloaderEditor::drop_data_fw);
}
ResourcePreloaderEditor::ResourcePreloaderEditor() {
@@ -379,7 +375,7 @@ ResourcePreloaderEditor::ResourcePreloaderEditor() {
tree->set_column_expand(1, true);
tree->set_v_size_flags(SIZE_EXPAND_FILL);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(tree, ResourcePreloaderEditor);
vbc->add_child(tree);
dialog = memnew(AcceptDialog);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index caa42b677c..e515b46b1e 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -439,6 +439,8 @@ void ScriptEditor::_goto_script_line(Ref<RefCounted> p_script, int p_line) {
} else if (current) {
current->goto_line(p_line, true);
}
+
+ _save_history();
}
}
}
@@ -2172,6 +2174,8 @@ Error ScriptEditor::_save_text_file(Ref<TextFile> p_text_file, const String &p_p
p_text_file->set_last_modified_time(FileAccess::get_modified_time(p_path));
}
+ EditorFileSystem::get_singleton()->update_file(p_path);
+
_res_saved_callback(sqscr);
return OK;
}
@@ -2254,11 +2258,14 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
args.push_back(script_path);
}
- Error err = OS::get_singleton()->create_process(path, args);
- if (err == OK) {
- return false;
+ if (!path.is_empty()) {
+ Error err = OS::get_singleton()->create_process(path, args);
+ if (err == OK) {
+ return false;
+ }
}
- WARN_PRINT("Couldn't open external text editor, using internal");
+
+ ERR_PRINT("Couldn't open external text editor, falling back to the internal editor. Review your `text_editor/external/` editor settings.");
}
for (int i = 0; i < tab_container->get_tab_count(); i++) {
@@ -2487,7 +2494,6 @@ void ScriptEditor::save_all_scripts() {
}
_update_script_names();
- EditorFileSystem::get_singleton()->update_script_classes();
}
void ScriptEditor::apply_scripts() const {
@@ -2553,9 +2559,9 @@ void ScriptEditor::open_script_create_dialog(const String &p_base_name, const St
}
void ScriptEditor::open_text_file_create_dialog(const String &p_base_path, const String &p_base_name) {
- file_dialog->set_current_file(p_base_name);
- file_dialog->set_current_dir(p_base_path);
_menu_option(FILE_NEW_TEXTFILE);
+ file_dialog->set_current_dir(p_base_path);
+ file_dialog->set_current_file(p_base_name);
open_textfile_after_create = false;
}
@@ -3610,10 +3616,6 @@ void ScriptEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("register_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::register_syntax_highlighter);
ClassDB::bind_method(D_METHOD("unregister_syntax_highlighter", "syntax_highlighter"), &ScriptEditor::unregister_syntax_highlighter);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ScriptEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ScriptEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ScriptEditor::drop_data_fw);
-
ClassDB::bind_method(D_METHOD("goto_line", "line_number"), &ScriptEditor::_goto_script_line2);
ClassDB::bind_method(D_METHOD("get_current_script"), &ScriptEditor::_get_current_script);
ClassDB::bind_method(D_METHOD("get_open_scripts"), &ScriptEditor::_get_open_scripts);
@@ -3669,7 +3671,7 @@ ScriptEditor::ScriptEditor() {
_sort_list_on_update = true;
script_list->connect("item_clicked", callable_mp(this, &ScriptEditor::_script_list_clicked), CONNECT_DEFERRED);
script_list->set_allow_rmb_select(true);
- script_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(script_list, ScriptEditor);
context_menu = memnew(PopupMenu);
add_child(context_menu);
@@ -4005,12 +4007,6 @@ void ScriptEditorPlugin::apply_changes() {
script_editor->apply_scripts();
}
-void ScriptEditorPlugin::restore_global_state() {
-}
-
-void ScriptEditorPlugin::save_global_state() {
-}
-
void ScriptEditorPlugin::set_window_layout(Ref<ConfigFile> p_layout) {
script_editor->set_window_layout(p_layout);
}
diff --git a/editor/plugins/script_editor_plugin.h b/editor/plugins/script_editor_plugin.h
index d4c80c416b..988d07621c 100644
--- a/editor/plugins/script_editor_plugin.h
+++ b/editor/plugins/script_editor_plugin.h
@@ -542,9 +542,6 @@ public:
virtual void save_external_data() override;
virtual void apply_changes() override;
- virtual void restore_global_state() override;
- virtual void save_global_state() override;
-
virtual void set_window_layout(Ref<ConfigFile> p_layout) override;
virtual void get_window_layout(Ref<ConfigFile> p_layout) override;
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 4d525cc5a9..6bb725f7a0 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -1490,14 +1490,6 @@ void ScriptTextEditor::_notification(int p_what) {
}
}
-void ScriptTextEditor::_bind_methods() {
- ClassDB::bind_method("_update_connected_methods", &ScriptTextEditor::_update_connected_methods);
-
- ClassDB::bind_method("_get_drag_data_fw", &ScriptTextEditor::get_drag_data_fw);
- ClassDB::bind_method("_can_drop_data_fw", &ScriptTextEditor::can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &ScriptTextEditor::drop_data_fw);
-}
-
Control *ScriptTextEditor::get_edit_menu() {
return edit_hb;
}
@@ -2167,7 +2159,7 @@ ScriptTextEditor::ScriptTextEditor() {
connection_info_dialog = memnew(ConnectionInfoDialog);
- code_editor->get_text_editor()->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(code_editor, ScriptTextEditor);
}
ScriptTextEditor::~ScriptTextEditor() {
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index 9db0191128..1d96376748 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -176,7 +176,6 @@ protected:
void _warning_clicked(Variant p_line);
void _notification(int p_what);
- static void _bind_methods();
HashMap<String, Ref<EditorSyntaxHighlighter>> highlighters;
void _change_syntax_highlighter(int p_idx);
diff --git a/editor/plugins/shader_editor_plugin.cpp b/editor/plugins/shader_editor_plugin.cpp
index a822584619..87d602ccf1 100644
--- a/editor/plugins/shader_editor_plugin.cpp
+++ b/editor/plugins/shader_editor_plugin.cpp
@@ -229,7 +229,7 @@ void ShaderEditorPlugin::_close_shader(int p_index) {
memdelete(c);
edited_shaders.remove_at(p_index);
_update_shader_list();
- EditorNode::get_undo_redo()->clear_history(); // To prevent undo on deleted graphs.
+ EditorUndoRedoManager::get_singleton()->clear_history(); // To prevent undo on deleted graphs.
}
void ShaderEditorPlugin::_resource_saved(Object *obj) {
@@ -413,12 +413,6 @@ void ShaderEditorPlugin::drop_data_fw(const Point2 &p_point, const Variant &p_da
}
}
-void ShaderEditorPlugin::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw", "point", "from"), &ShaderEditorPlugin::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw", "point", "data", "from"), &ShaderEditorPlugin::drop_data_fw);
-}
-
ShaderEditorPlugin::ShaderEditorPlugin() {
main_split = memnew(HSplitContainer);
@@ -451,7 +445,7 @@ ShaderEditorPlugin::ShaderEditorPlugin() {
vb->add_child(shader_list);
shader_list->connect("item_selected", callable_mp(this, &ShaderEditorPlugin::_shader_selected));
shader_list->connect("item_clicked", callable_mp(this, &ShaderEditorPlugin::_shader_list_clicked));
- shader_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(shader_list, ShaderEditorPlugin);
main_split->add_child(vb);
vb->set_custom_minimum_size(Size2(200, 300) * EDSCALE);
diff --git a/editor/plugins/shader_editor_plugin.h b/editor/plugins/shader_editor_plugin.h
index 8ca4a534ab..408d08ade0 100644
--- a/editor/plugins/shader_editor_plugin.h
+++ b/editor/plugins/shader_editor_plugin.h
@@ -92,9 +92,6 @@ class ShaderEditorPlugin : public EditorPlugin {
bool can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const;
void drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from);
-protected:
- static void _bind_methods();
-
public:
virtual String get_name() const override { return "Shader"; }
virtual void edit(Object *p_object) override;
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index d90d6b6756..06db696330 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -61,7 +61,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Rest Pose to Bones"));
for (int i = 0; i < node->get_bone_count(); i++) {
Bone2D *bone = node->get_bone(i);
@@ -77,7 +77,7 @@ void Skeleton2DEditor::_menu_option(int p_option) {
err_dialog->popup_centered();
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Rest Pose from Bones"));
for (int i = 0; i < node->get_bone_count(); i++) {
Bone2D *bone = node->get_bone(i);
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 956150ec69..3ee9823f3a 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -116,7 +116,7 @@ void BoneTransformEditor::_value_changed(const String &p_property, Variant p_val
return;
}
if (skeleton) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
undo_redo->add_undo_property(skeleton, p_property, skeleton->get(p_property));
undo_redo->add_do_property(skeleton, p_property, p_value);
@@ -271,7 +271,7 @@ void Skeleton3DEditor::reset_pose(const bool p_all_bones) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Transform"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
for (int i = 0; i < bone_len; i++) {
@@ -338,7 +338,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Rest"), UndoRedo::MERGE_ENDS);
if (p_all_bones) {
for (int i = 0; i < bone_len; i++) {
@@ -358,7 +358,7 @@ void Skeleton3DEditor::pose_to_rest(const bool p_all_bones) {
}
void Skeleton3DEditor::create_physical_skeleton() {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ERR_FAIL_COND(!get_tree());
Node *owner = get_tree()->get_edited_scene_root();
@@ -593,7 +593,7 @@ void Skeleton3DEditor::move_skeleton_bone(NodePath p_skeleton_path, int32_t p_se
Node *node = get_node_or_null(p_skeleton_path);
Skeleton3D *skeleton_node = Object::cast_to<Skeleton3D>(node);
ERR_FAIL_NULL(skeleton_node);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Parentage"));
// If the target is a child of ourselves, we move only *us* and not our children.
if (skeleton_node->is_bone_parent_of(p_target_boneidx, p_selected_boneidx)) {
@@ -813,7 +813,7 @@ void Skeleton3DEditor::create_editors() {
joint_tree->set_v_size_flags(SIZE_EXPAND_FILL);
joint_tree->set_h_size_flags(SIZE_EXPAND_FILL);
joint_tree->set_allow_rmb_select(true);
- joint_tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(joint_tree, Skeleton3DEditor);
s_con->add_child(joint_tree);
pose_editor = memnew(BoneTransformEditor(skeleton));
@@ -889,10 +889,6 @@ void Skeleton3DEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_properties"), &Skeleton3DEditor::_update_properties);
ClassDB::bind_method(D_METHOD("_on_click_skeleton_option"), &Skeleton3DEditor::_on_click_skeleton_option);
- ClassDB::bind_method(D_METHOD("get_drag_data_fw"), &Skeleton3DEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("can_drop_data_fw"), &Skeleton3DEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("drop_data_fw"), &Skeleton3DEditor::drop_data_fw);
-
ClassDB::bind_method(D_METHOD("move_skeleton_bone"), &Skeleton3DEditor::move_skeleton_bone);
ClassDB::bind_method(D_METHOD("_draw_gizmo"), &Skeleton3DEditor::_draw_gizmo);
@@ -1323,7 +1319,7 @@ void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, c
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Bone Transform"));
if (ne->get_tool_mode() == Node3DEditor::TOOL_MODE_SELECT || ne->get_tool_mode() == Node3DEditor::TOOL_MODE_MOVE) {
for (int i = 0; i < p_ids.size(); i++) {
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 2a8994d239..0d00bfa8fd 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -344,7 +344,7 @@ void Sprite2DEditor::_convert_to_mesh_2d_node() {
MeshInstance2D *mesh_instance = memnew(MeshInstance2D);
mesh_instance->set_mesh(mesh);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Convert to MeshInstance2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, mesh_instance, true, false);
ur->add_do_reference(mesh_instance);
@@ -402,7 +402,7 @@ void Sprite2DEditor::_convert_to_polygon_2d_node() {
polygon_2d_instance->set_polygon(polygon);
polygon_2d_instance->set_polygons(polys);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Convert to Polygon2D"));
ur->add_do_method(SceneTreeDock::get_singleton(), "replace_node", node, polygon_2d_instance, true, false);
ur->add_do_reference(polygon_2d_instance);
@@ -424,7 +424,7 @@ void Sprite2DEditor::_create_collision_polygon_2d_node() {
CollisionPolygon2D *collision_polygon_2d_instance = memnew(CollisionPolygon2D);
collision_polygon_2d_instance->set_polygon(outline);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create CollisionPolygon2D Sibling"));
ur->add_do_method(this, "_add_as_sibling_or_child", node, collision_polygon_2d_instance);
ur->add_do_reference(collision_polygon_2d_instance);
@@ -457,7 +457,7 @@ void Sprite2DEditor::_create_light_occluder_2d_node() {
LightOccluder2D *light_occluder_2d_instance = memnew(LightOccluder2D);
light_occluder_2d_instance->set_occluder_polygon(polygon);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create LightOccluder2D Sibling"));
ur->add_do_method(this, "_add_as_sibling_or_child", node, light_occluder_2d_instance);
ur->add_do_reference(light_occluder_2d_instance);
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index f4ec026504..74c9286325 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -251,7 +251,7 @@ void SpriteFramesEditor::_sheet_add_frames() {
const Size2i offset = _get_offset();
const Size2i separation = _get_separation();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Frame"));
int fc = frames->get_frame_count(edited_anim);
@@ -470,7 +470,7 @@ void SpriteFramesEditor::_file_load_request(const Vector<String> &p_path, int p_
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Frame"));
int fc = frames->get_frame_count(edited_anim);
@@ -541,7 +541,7 @@ void SpriteFramesEditor::_paste_pressed() {
return; ///beh should show an error i guess
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Paste Frame"));
undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, duration);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, frames->get_frame_count(edited_anim));
@@ -584,7 +584,7 @@ void SpriteFramesEditor::_empty_pressed() {
Ref<Texture2D> texture;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Empty"));
undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from);
@@ -608,7 +608,7 @@ void SpriteFramesEditor::_empty2_pressed() {
Ref<Texture2D> texture;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Empty"));
undo_redo->add_do_method(frames, "add_frame", edited_anim, texture, 1.0, from + 1);
undo_redo->add_undo_method(frames, "remove_frame", edited_anim, from + 1);
@@ -632,7 +632,7 @@ void SpriteFramesEditor::_up_pressed() {
sel = to_move;
sel -= 1;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Frame"));
undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move - 1), frames->get_frame_duration(edited_anim, to_move - 1));
undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move - 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
@@ -658,7 +658,7 @@ void SpriteFramesEditor::_down_pressed() {
sel = to_move;
sel += 1;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Move Frame"));
undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move, frames->get_frame_texture(edited_anim, to_move + 1), frames->get_frame_duration(edited_anim, to_move + 1));
undo_redo->add_do_method(frames, "set_frame", edited_anim, to_move + 1, frames->get_frame_texture(edited_anim, to_move), frames->get_frame_duration(edited_anim, to_move));
@@ -681,7 +681,7 @@ void SpriteFramesEditor::_delete_pressed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Resource"));
undo_redo->add_do_method(frames, "remove_frame", edited_anim, to_delete);
undo_redo->add_undo_method(frames, "add_frame", edited_anim, frames->get_frame_texture(edited_anim, to_delete), frames->get_frame_duration(edited_anim, to_delete), to_delete);
@@ -768,7 +768,7 @@ void SpriteFramesEditor::_animation_name_edited() {
List<Node *> nodes;
_find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Animation"));
undo_redo->add_do_method(frames, "rename_animation", edited_anim, name);
undo_redo->add_undo_method(frames, "rename_animation", name, edited_anim);
@@ -788,17 +788,17 @@ void SpriteFramesEditor::_animation_name_edited() {
}
void SpriteFramesEditor::_animation_add() {
- String name = "New Anim";
+ String name = "new_animation";
int counter = 0;
while (frames->has_animation(name)) {
counter++;
- name = "New Anim " + itos(counter);
+ name = vformat("new_animation_%d", counter);
}
List<Node *> nodes;
_find_anim_sprites(EditorNode::get_singleton()->get_edited_scene(), &nodes, Ref<SpriteFrames>(frames));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Animation"));
undo_redo->add_do_method(frames, "add_animation", name);
undo_redo->add_undo_method(frames, "remove_animation", name);
@@ -831,7 +831,7 @@ void SpriteFramesEditor::_animation_remove() {
}
void SpriteFramesEditor::_animation_remove_confirmed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Animation"));
undo_redo->add_do_method(frames, "remove_animation", edited_anim);
undo_redo->add_undo_method(frames, "add_animation", edited_anim);
@@ -860,7 +860,7 @@ void SpriteFramesEditor::_animation_loop_changed() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation Loop"));
undo_redo->add_do_method(frames, "set_animation_loop", edited_anim, anim_loop->is_pressed());
undo_redo->add_undo_method(frames, "set_animation_loop", edited_anim, frames->get_animation_loop(edited_anim));
@@ -874,7 +874,7 @@ void SpriteFramesEditor::_animation_speed_changed(double p_value) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Animation FPS"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(frames, "set_animation_speed", edited_anim, p_value);
undo_redo->add_undo_method(frames, "set_animation_speed", edited_anim, frames->get_animation_speed(edited_anim));
@@ -926,7 +926,7 @@ void SpriteFramesEditor::_frame_duration_changed(double p_value) {
Ref<Texture2D> texture = frames->get_frame_texture(edited_anim, index);
float old_duration = frames->get_frame_duration(edited_anim, index);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Frame Duration"));
undo_redo->add_do_method(frames, "set_frame", edited_anim, index, texture, p_value);
undo_redo->add_undo_method(frames, "set_frame", edited_anim, index, texture, old_duration);
@@ -1206,7 +1206,7 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
reorder = true;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (reorder) { //drop is from reordering frames
int from_frame = -1;
float duration = 1.0;
@@ -1247,9 +1247,6 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
void SpriteFramesEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_library", "skipsel"), &SpriteFramesEditor::_update_library, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SpriteFramesEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SpriteFramesEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SpriteFramesEditor::drop_data_fw);
}
SpriteFramesEditor::SpriteFramesEditor() {
@@ -1408,7 +1405,7 @@ SpriteFramesEditor::SpriteFramesEditor() {
frame_list->set_max_columns(0);
frame_list->set_icon_mode(ItemList::ICON_MODE_TOP);
frame_list->set_max_text_lines(2);
- frame_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(frame_list, SpriteFramesEditor);
frame_list->connect("gui_input", callable_mp(this, &SpriteFramesEditor::_frame_list_gui_input));
frame_list->connect("item_selected", callable_mp(this, &SpriteFramesEditor::_frame_list_item_selected));
diff --git a/editor/plugins/text_editor.cpp b/editor/plugins/text_editor.cpp
index ad5881c76f..a376699e54 100644
--- a/editor/plugins/text_editor.cpp
+++ b/editor/plugins/text_editor.cpp
@@ -649,8 +649,6 @@ TextEditor::TextEditor() {
goto_line_dialog = memnew(GotoLineDialog);
add_child(goto_line_dialog);
-
- code_editor->get_text_editor()->set_drag_forwarding_compat(this);
}
TextEditor::~TextEditor() {
diff --git a/editor/plugins/texture_region_editor_plugin.cpp b/editor/plugins/texture_region_editor_plugin.cpp
index 05d32e1d08..9bad2f2fbf 100644
--- a/editor/plugins/texture_region_editor_plugin.cpp
+++ b/editor/plugins/texture_region_editor_plugin.cpp
@@ -300,7 +300,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
mtx.xform(rect.position + Vector2(0, rect.size.y / 2)) + Vector2(-handle_offset, 0)
};
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> mb = p_input;
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT) {
@@ -349,7 +349,7 @@ void TextureRegionEditor::_region_input(const Ref<InputEvent> &p_input) {
for (const Rect2 &E : autoslice_cache) {
if (E.has_point(point)) {
rect = E;
- if (Input::get_singleton()->is_key_pressed(Key::CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !(Input::get_singleton()->is_key_pressed(Key(Key::SHIFT | Key::ALT)))) {
Rect2 r;
if (atlas_tex.is_valid()) {
r = atlas_tex->get_region();
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index 68c1041a0b..40aac77a99 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -800,7 +800,7 @@ void ThemeItemImportTree::_import_selected() {
ProgressDialog::get_singleton()->end_task("import_theme_items");
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Import Theme Items"));
ur->add_do_method(*edited_theme, "clear");
@@ -1498,7 +1498,7 @@ void ThemeItemEditorDialog::_item_tree_button_pressed(Object *p_item, int p_colu
String item_name = item->get_text(0);
int data_type = item->get_parent()->get_metadata(0);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Theme Item"));
ur->add_do_method(*edited_theme, "clear_theme_item", (Theme::DataType)data_type, item_name, edited_item_type);
ur->add_undo_method(*edited_theme, "set_theme_item", (Theme::DataType)data_type, item_name, edited_item_type, edited_theme->get_theme_item((Theme::DataType)data_type, item_name, edited_item_type));
@@ -1517,7 +1517,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
const String new_type = edit_add_type_value->get_text().strip_edges();
edit_add_type_value->clear();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Add Theme Type"));
ur->add_do_method(*edited_theme, "add_type", new_type);
@@ -1529,7 +1529,7 @@ void ThemeItemEditorDialog::_add_theme_type(const String &p_new_text) {
}
void ThemeItemEditorDialog::_add_theme_item(Theme::DataType p_data_type, String p_item_name, String p_item_type) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Create Theme Item"));
switch (p_data_type) {
@@ -1574,7 +1574,7 @@ void ThemeItemEditorDialog::_remove_theme_type(const String &p_theme_type) {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Theme Type"));
new_snapshot->remove_type(p_theme_type);
@@ -1597,7 +1597,7 @@ void ThemeItemEditorDialog::_remove_data_type_items(Theme::DataType p_data_type,
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Data Type Items From Theme"));
new_snapshot->get_theme_item_list(p_data_type, p_item_type, &names);
@@ -1626,7 +1626,7 @@ void ThemeItemEditorDialog::_remove_class_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Class Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1662,7 +1662,7 @@ void ThemeItemEditorDialog::_remove_custom_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Custom Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1698,7 +1698,7 @@ void ThemeItemEditorDialog::_remove_all_items() {
Ref<Theme> old_snapshot = edited_theme->duplicate();
Ref<Theme> new_snapshot = edited_theme->duplicate();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove All Items From Theme"));
for (int dt = 0; dt < Theme::DATA_TYPE_MAX; dt++) {
@@ -1802,7 +1802,7 @@ 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) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Rename Theme Item"));
ur->add_do_method(*edited_theme, "rename_theme_item", edit_item_data_type, edit_item_old_name, theme_item_name->get_text(), edited_item_type);
@@ -2828,7 +2828,7 @@ void ThemeTypeEditor::_add_default_type_items() {
updating = false;
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Override All Default Theme Items"));
ur->add_do_method(*edited_theme, "merge_with", new_snapshot);
@@ -2848,7 +2848,7 @@ void ThemeTypeEditor::_item_add_cbk(int p_data_type, Control *p_control) {
}
String item_name = le->get_text().strip_edges();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Add Theme Item"));
switch (p_data_type) {
@@ -2893,7 +2893,7 @@ void ThemeTypeEditor::_item_add_lineedit_cbk(String p_value, int p_data_type, Co
}
void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Override Theme Item"));
switch (p_data_type) {
@@ -2932,7 +2932,7 @@ void ThemeTypeEditor::_item_override_cbk(int p_data_type, String p_item_name) {
}
void ThemeTypeEditor::_item_remove_cbk(int p_data_type, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Remove Theme Item"));
switch (p_data_type) {
@@ -3006,7 +3006,7 @@ void ThemeTypeEditor::_item_rename_confirmed(int p_data_type, String p_item_name
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Rename Theme Item"));
switch (p_data_type) {
@@ -3062,7 +3062,7 @@ void ThemeTypeEditor::_item_rename_canceled(int p_data_type, String p_item_name,
}
void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Color Item in Theme"), UndoRedo::MERGE_ENDS);
ur->add_do_method(*edited_theme, "set_color", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_color", p_item_name, edited_type, edited_theme->get_color(p_item_name, edited_type));
@@ -3070,7 +3070,7 @@ void ThemeTypeEditor::_color_item_changed(Color p_value, String p_item_name) {
}
void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Constant Item in Theme"));
ur->add_do_method(*edited_theme, "set_constant", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_constant", p_item_name, edited_type, edited_theme->get_constant(p_item_name, edited_type));
@@ -3078,7 +3078,7 @@ void ThemeTypeEditor::_constant_item_changed(float p_value, String p_item_name)
}
void ThemeTypeEditor::_font_size_item_changed(float p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Font Size Item in Theme"));
ur->add_do_method(*edited_theme, "set_font_size", p_item_name, edited_type, p_value);
ur->add_undo_method(*edited_theme, "set_font_size", p_item_name, edited_type, edited_theme->get_font_size(p_item_name, edited_type));
@@ -3090,7 +3090,7 @@ void ThemeTypeEditor::_edit_resource_item(Ref<Resource> p_resource, bool p_edit)
}
void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Font Item in Theme"));
ur->add_do_method(*edited_theme, "set_font", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Font>());
@@ -3107,7 +3107,7 @@ void ThemeTypeEditor::_font_item_changed(Ref<Font> p_value, String p_item_name)
}
void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Icon Item in Theme"));
ur->add_do_method(*edited_theme, "set_icon", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<Texture2D>());
@@ -3124,7 +3124,7 @@ void ThemeTypeEditor::_icon_item_changed(Ref<Texture2D> p_value, String p_item_n
}
void ThemeTypeEditor::_stylebox_item_changed(Ref<StyleBox> p_value, String p_item_name) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Stylebox Item in Theme"));
ur->add_do_method(*edited_theme, "set_stylebox", p_item_name, edited_type, p_value.is_valid() ? p_value : Ref<StyleBox>());
@@ -3167,7 +3167,7 @@ void ThemeTypeEditor::_on_pin_leader_button_pressed(Control *p_editor, String p_
stylebox = Object::cast_to<EditorResourcePicker>(p_editor)->get_edited_resource();
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Pin Stylebox"));
ur->add_do_method(this, "_pin_leading_stylebox", p_item_name, stylebox);
@@ -3200,7 +3200,7 @@ void ThemeTypeEditor::_pin_leading_stylebox(String p_item_name, Ref<StyleBox> p_
}
void ThemeTypeEditor::_on_unpin_leader_button_pressed() {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Unpin Stylebox"));
ur->add_do_method(this, "_unpin_leading_stylebox");
ur->add_undo_method(this, "_pin_leading_stylebox", leading_stylebox.item_name, leading_stylebox.stylebox);
@@ -3269,7 +3269,7 @@ void ThemeTypeEditor::_update_stylebox_from_leading() {
}
void ThemeTypeEditor::_type_variation_changed(const String p_value) {
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Set Theme Type Variation"));
if (p_value.is_empty()) {
diff --git a/editor/plugins/tiles/atlas_merging_dialog.cpp b/editor/plugins/tiles/atlas_merging_dialog.cpp
index 4128029fc6..eaf72d36ba 100644
--- a/editor/plugins/tiles/atlas_merging_dialog.cpp
+++ b/editor/plugins/tiles/atlas_merging_dialog.cpp
@@ -31,7 +31,6 @@
#include "atlas_merging_dialog.h"
#include "editor/editor_file_dialog.h"
-#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_undo_redo_manager.h"
@@ -172,7 +171,7 @@ void AtlasMergingDialog::_merge_confirmed(String p_path) {
Ref<Texture2D> new_texture_resource = ResourceLoader::load(p_path, "Texture2D");
merged->set_texture(new_texture_resource);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Merge TileSetAtlasSource"));
int next_id = tile_set->get_next_source_id();
undo_redo->add_do_method(*tile_set, "add_source", merged, next_id);
@@ -212,7 +211,7 @@ void AtlasMergingDialog::ok_pressed() {
}
void AtlasMergingDialog::cancel_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (int i = 0; i < commited_actions_count; i++) {
undo_redo->undo();
}
diff --git a/editor/plugins/tiles/tile_atlas_view.cpp b/editor/plugins/tiles/tile_atlas_view.cpp
index 3c6ed0f049..0ac375407c 100644
--- a/editor/plugins/tiles/tile_atlas_view.cpp
+++ b/editor/plugins/tiles/tile_atlas_view.cpp
@@ -454,21 +454,31 @@ void TileAtlasView::set_padding(Side p_side, int p_padding) {
margin_container_paddings[p_side] = p_padding;
}
-Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos) const {
+Vector2i TileAtlasView::get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p_clamp) const {
Ref<Texture2D> texture = tile_set_atlas_source->get_texture();
- if (texture.is_valid()) {
- Vector2i margins = tile_set_atlas_source->get_margins();
- Vector2i separation = tile_set_atlas_source->get_separation();
- Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
+ if (!texture.is_valid()) {
+ return TileSetSource::INVALID_ATLAS_COORDS;
+ }
+
+ Vector2i margins = tile_set_atlas_source->get_margins();
+ Vector2i separation = tile_set_atlas_source->get_separation();
+ Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
- // Compute index in atlas
- Vector2 pos = p_pos - margins;
- Vector2i ret = (pos / (texture_region_size + separation)).floor();
+ // Compute index in atlas
+ Vector2 pos = p_pos - margins;
+ Vector2i ret = (pos / (texture_region_size + separation)).floor();
- return ret;
+ // Return invalid value (without clamp).
+ Rect2i rect = Rect2(Vector2i(), tile_set_atlas_source->get_atlas_grid_size());
+ if (!p_clamp && !rect.has_point(ret)) {
+ return TileSetSource::INVALID_ATLAS_COORDS;
}
- return TileSetSource::INVALID_ATLAS_COORDS;
+ // Clamp.
+ ret.x = CLAMP(ret.x, 0, rect.size.x - 1);
+ ret.y = CLAMP(ret.y, 0, rect.size.y - 1);
+
+ return ret;
}
void TileAtlasView::_update_alternative_tiles_rect_cache() {
diff --git a/editor/plugins/tiles/tile_atlas_view.h b/editor/plugins/tiles/tile_atlas_view.h
index 166abca2a3..f719bee704 100644
--- a/editor/plugins/tiles/tile_atlas_view.h
+++ b/editor/plugins/tiles/tile_atlas_view.h
@@ -128,7 +128,7 @@ public:
void set_texture_grid_visible(bool p_visible) { base_tiles_texture_grid->set_visible(p_visible); };
void set_tile_shape_grid_visible(bool p_visible) { base_tiles_shape_grid->set_visible(p_visible); };
- Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos) const;
+ Vector2i get_atlas_tile_coords_at_pos(const Vector2 p_pos, bool p_clamp = false) const;
void add_control_over_atlas_tiles(Control *p_control, bool scaled = true) {
if (scaled) {
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index fb4787f13c..81aa9bf272 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -265,12 +265,12 @@ void GenericTilePolygonEditor::_zoom_changed() {
}
void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
if (use_undo_redo) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
} else {
// This nice hack allows for discarding undo actions without making code too complex.
- undo_redo.instantiate();
+ undo_redo = memnew(EditorUndoRedoManager);
}
switch (p_item_pressed) {
@@ -361,6 +361,10 @@ void GenericTilePolygonEditor::_advanced_menu_item_pressed(int p_item_pressed) {
default:
break;
}
+
+ if (!use_undo_redo) {
+ memdelete(undo_redo);
+ }
}
void GenericTilePolygonEditor::_grab_polygon_point(Vector2 p_pos, const Transform2D &p_polygon_xform, int &r_polygon_index, int &r_point_index) {
@@ -445,12 +449,12 @@ void GenericTilePolygonEditor::_snap_to_half_pixel(Point2 &r_point) {
}
void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event) {
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
if (use_undo_redo) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
} else {
// This nice hack allows for discarding undo actions without making code too complex.
- undo_redo.instantiate();
+ undo_redo = memnew(EditorUndoRedoManager);
}
real_t grab_threshold = EDITOR_GET("editors/polygon_editor/point_grab_radius");
@@ -493,11 +497,11 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
- if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_ctrl_pressed()) {
+ if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_command_or_control_pressed()) {
editor_zoom_widget->set_zoom_by_increments(1);
_zoom_changed();
accept_event();
- } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_ctrl_pressed()) {
+ } else if (mb->get_button_index() == MouseButton::WHEEL_DOWN && mb->is_command_or_control_pressed()) {
editor_zoom_widget->set_zoom_by_increments(-1);
_zoom_changed();
accept_event();
@@ -643,6 +647,10 @@ void GenericTilePolygonEditor::_base_control_gui_input(Ref<InputEvent> p_event)
}
base_control->queue_redraw();
+
+ if (!use_undo_redo) {
+ memdelete(undo_redo);
+ }
}
void GenericTilePolygonEditor::set_use_undo_redo(bool p_use_undo_redo) {
@@ -902,7 +910,7 @@ Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_s
}
void TileDataDefaultEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/%s", coords.x, coords.y, E.key.alternative_tile, property), E.value);
@@ -918,8 +926,8 @@ void TileDataDefaultEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas_
p_canvas_item->draw_set_transform_matrix(p_transform);
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -953,7 +961,7 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (drag_type == DRAG_TYPE_PAINT) {
- Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true));
for (int i = 0; i < line.size(); i++) {
Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
@@ -971,19 +979,19 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
}
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Ref<InputEventMouseButton> mb = p_event;
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
- if (picker_button->is_pressed()) {
- Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
+ if (picker_button->is_pressed() || (mb->is_command_or_control_pressed() && !mb->is_shift_pressed())) {
+ Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true);
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
_set_painted_value(p_tile_set_atlas_source, coords, 0);
picker_button->set_pressed(false);
}
- } else if (mb->is_ctrl_pressed()) {
+ } else if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) {
drag_type = DRAG_TYPE_PAINT_RECT;
drag_modified.clear();
drag_painted_value = _get_painted_value();
@@ -992,7 +1000,7 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
drag_type = DRAG_TYPE_PAINT;
drag_modified.clear();
drag_painted_value = _get_painted_value();
- Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
+ Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true);
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
TileMapCell cell;
@@ -1007,8 +1015,8 @@ void TileDataDefaultEditor::forward_painting_atlas_gui_input(TileAtlasView *p_ti
} else {
if (drag_type == DRAG_TYPE_PAINT_RECT) {
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true));
rect = rect.abs();
drag_modified.clear();
@@ -1095,7 +1103,7 @@ void TileDataDefaultEditor::forward_painting_alternatives_gui_input(TileAtlasVie
drag_last_pos = mb->get_position();
}
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Painting Tiles Property"));
_setup_undo_redo_action(p_tile_set_atlas_source, drag_modified, drag_painted_value);
undo_redo->commit_action(false);
@@ -1345,7 +1353,7 @@ Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_
}
void TileDataOcclusionShapeEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/occlusion_layer_%d/polygon", coords.x, coords.y, E.key.alternative_tile, occlusion_layer), E.value);
@@ -1524,26 +1532,32 @@ Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas
}
void TileDataCollisionEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
- Array new_array = p_new_value;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ Dictionary new_dict = p_new_value;
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (KeyValue<TileMapCell, Variant> &E : p_previous_values) {
- Array old_array = E.value;
-
Vector2i coords = E.key.get_atlas_coords();
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_array.size());
- for (int i = 0; i < old_array.size(); i++) {
- Dictionary dict = old_array[i];
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["points"]);
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way"]);
- undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way_margin"]);
+
+ Dictionary old_dict = E.value;
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/linear_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_dict["linear_velocity"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/angular_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_dict["angular_velocity"]);
+ Array old_polygon_array = old_dict["polygons"];
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), old_polygon_array.size());
+ for (int i = 0; i < old_polygon_array.size(); i++) {
+ Dictionary polygon_dict = old_polygon_array[i];
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["points"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way"]);
+ undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way_margin"]);
}
- undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_array.size());
- for (int i = 0; i < new_array.size(); i++) {
- Dictionary dict = new_array[i];
- undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["points"]);
- undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way"]);
- undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), dict["one_way_margin"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/linear_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_dict["linear_velocity"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/angular_velocity", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_dict["angular_velocity"]);
+ Array new_polygon_array = new_dict["polygons"];
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygons_count", coords.x, coords.y, E.key.alternative_tile, physics_layer), new_polygon_array.size());
+ for (int i = 0; i < new_polygon_array.size(); i++) {
+ Dictionary polygon_dict = new_polygon_array[i];
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/points", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["points"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way"]);
+ undo_redo->add_do_property(p_tile_set_atlas_source, vformat("%d:%d/%d/physics_layer_%d/polygon_%d/one_way_margin", coords.x, coords.y, E.key.alternative_tile, physics_layer, i), polygon_dict["one_way_margin"]);
}
}
}
@@ -1804,8 +1818,8 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
p_canvas_item->draw_set_transform_matrix(p_transform);
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -1834,8 +1848,8 @@ void TileDataTerrainsEditor::forward_draw_over_atlas(TileAtlasView *p_tile_atlas
int terrain_set = int(painted["terrain_set"]);
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position())));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(p_transform.affine_inverse().xform(p_canvas_item->get_local_mouse_position()), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -1995,7 +2009,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) {
- Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true));
for (int i = 0; i < line.size(); i++) {
Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
@@ -2029,7 +2043,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
} else if (drag_type == DRAG_TYPE_PAINT_TERRAIN_BITS) {
int terrain_set = Dictionary(drag_painted_value)["terrain_set"];
int terrain = Dictionary(drag_painted_value)["terrain"];
- Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position()));
+ Vector<Vector2i> line = Geometry2D::bresenham_line(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_pos, true), p_tile_atlas_view->get_atlas_tile_coords_at_pos(mm->get_position(), true));
for (int i = 0; i < line.size(); i++) {
Vector2i coords = p_tile_set_atlas_source->get_tile_at_coords(line[i]);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
@@ -2083,7 +2097,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
if (mb.is_valid()) {
if (mb->get_button_index() == MouseButton::LEFT || mb->get_button_index() == MouseButton::RIGHT) {
if (mb->is_pressed()) {
- if (mb->get_button_index() == MouseButton::LEFT && picker_button->is_pressed()) {
+ if (picker_button->is_pressed() || (mb->is_command_or_control_pressed() && !mb->is_shift_pressed())) {
Vector2i coords = p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position());
coords = p_tile_set_atlas_source->get_tile_at_coords(coords);
if (coords != TileSetSource::INVALID_ATLAS_COORDS) {
@@ -2126,7 +2140,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
if (mb->get_button_index() == MouseButton::RIGHT) {
terrain_set = -1;
}
- if (mb->is_ctrl_pressed()) {
+ if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) {
// Paint terrain set with rect.
drag_type = DRAG_TYPE_PAINT_TERRAIN_SET_RECT;
drag_modified.clear();
@@ -2167,7 +2181,7 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
if (mb->get_button_index() == MouseButton::RIGHT) {
terrain = -1;
}
- if (mb->is_ctrl_pressed()) {
+ if (mb->is_command_or_control_pressed() && mb->is_shift_pressed()) {
// Paint terrain bits with rect.
drag_type = DRAG_TYPE_PAINT_TERRAIN_BITS_RECT;
drag_modified.clear();
@@ -2227,11 +2241,11 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
}
}
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET_RECT) {
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -2318,8 +2332,8 @@ void TileDataTerrainsEditor::forward_painting_atlas_gui_input(TileAtlasView *p_t
int terrain = int(painted["terrain"]);
Rect2i rect;
- rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos));
- rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position()));
+ rect.set_position(p_tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_pos, true));
+ rect.set_end(p_tile_atlas_view->get_atlas_tile_coords_at_pos(mb->get_position(), true));
rect = rect.abs();
RBSet<TileMapCell> edited;
@@ -2600,7 +2614,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
}
}
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (drag_type == DRAG_TYPE_PAINT_TERRAIN_SET) {
undo_redo->create_action(TTR("Painting Tiles Property"));
for (KeyValue<TileMapCell, Variant> &E : drag_modified) {
@@ -2747,7 +2761,7 @@ Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atla
}
void TileDataNavigationEditor::_setup_undo_redo_action(TileSetAtlasSource *p_tile_set_atlas_source, HashMap<TileMapCell, Variant, TileMapCell> p_previous_values, Variant p_new_value) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const KeyValue<TileMapCell, Variant> &E : p_previous_values) {
Vector2i coords = E.key.get_atlas_coords();
undo_redo->add_undo_property(p_tile_set_atlas_source, vformat("%d:%d/%d/navigation_layer_%d/polygon", coords.x, coords.y, E.key.alternative_tile, navigation_layer), E.value);
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index e9c313a372..885d41b8da 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -273,7 +273,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven
if (ED_IS_SHORTCUT("tiles_editor/paste", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
select_last_pattern = true;
int new_pattern_index = tile_set->get_patterns_count();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add TileSet pattern"));
undo_redo->add_do_method(*tile_set, "add_pattern", tile_map_clipboard, new_pattern_index);
undo_redo->add_undo_method(*tile_set, "remove_pattern", new_pattern_index);
@@ -283,7 +283,7 @@ void TileMapEditorTilesPlugin::_patterns_item_list_gui_input(const Ref<InputEven
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
Vector<int> selected = patterns_item_list->get_selected_items();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove TileSet patterns"));
for (int i = 0; i < selected.size(); i++) {
int pattern_index = selected[i];
@@ -515,7 +515,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (ED_IS_SHORTCUT("tiles_editor/cut", p_event)) {
// Delete selected tiles.
if (!tile_map_selection.is_empty()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete tiles"));
for (const Vector2i &E : tile_map_selection) {
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
@@ -547,7 +547,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event)) {
// Delete selected tiles.
if (!tile_map_selection.is_empty()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete tiles"));
for (const Vector2i &E : tile_map_selection) {
undo_redo->add_do_method(tile_map, "set_cell", tile_map_layer, E, TileSet::INVALID_SOURCE, TileSetSource::INVALID_ATLAS_COORDS, TileSetSource::INVALID_TILE_ALTERNATIVE);
@@ -646,12 +646,12 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
} else {
// Check if we are picking a tile.
- if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
+ if (picker_button->is_pressed() || (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
drag_type = DRAG_TYPE_PICK;
drag_start_mouse_pos = mpos;
} else {
// Paint otherwise.
- if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
drag_type = DRAG_TYPE_PAINT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
@@ -667,11 +667,11 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
tile_map->set_cell(tile_map_layer, coords, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
_fix_invalid_tiles_in_tile_map_selection();
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
drag_type = DRAG_TYPE_LINE;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
drag_type = DRAG_TYPE_RECT;
drag_start_mouse_pos = mpos;
drag_modified.clear();
@@ -742,7 +742,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
// Draw the selection.
if ((tiles_bottom_panel->is_visible_in_tree() || patterns_bottom_panel->is_visible_in_tree()) && tool_buttons_group->get_pressed_button() == select_tool_button) {
// In select mode, we only draw the current selection if we are modifying it (pressing control or shift).
- if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
+ if (drag_type == DRAG_TYPE_MOVE || (drag_type == DRAG_TYPE_SELECT && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
// Do nothing
} else {
Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
@@ -812,7 +812,7 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Vector2i coords = tile_map->map_pattern(tile_map->local_to_map(drag_last_mouse_pos - mouse_offset), clipboard_used_cells[i], tile_map_clipboard);
preview[coords] = TileMapCell(tile_map_clipboard->get_cell_source_id(clipboard_used_cells[i]), tile_map_clipboard->get_cell_atlas_coords(clipboard_used_cells[i]), tile_map_clipboard->get_cell_alternative_tile(clipboard_used_cells[i]));
}
- } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
+ } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single pattern.
@@ -1240,20 +1240,20 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (drag_type) {
case DRAG_TYPE_SELECT: {
undo_redo->create_action(TTR("Change selection"));
undo_redo->add_undo_method(this, "_set_tile_map_selection", _get_tile_map_selection());
- if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (!Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
tile_map_selection.clear();
}
Rect2i rect = Rect2i(tile_map->local_to_map(drag_start_mouse_pos), tile_map->local_to_map(mpos) - tile_map->local_to_map(drag_start_mouse_pos)).abs();
for (int x = rect.position.x; x <= rect.get_end().x; x++) {
for (int y = rect.position.y; y <= rect.get_end().y; y++) {
Vector2i coords = Vector2i(x, y);
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
if (tile_map_selection.has(coords)) {
tile_map_selection.erase(coords);
}
@@ -1716,8 +1716,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
// Draw the selection rect.
if (tile_set_dragging_selection) {
- Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos);
- Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos, true);
+ Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i region = Rect2i(start_tile, end_tile - start_tile).abs();
region.size += Vector2i(1, 1);
@@ -1812,8 +1812,8 @@ void TileMapEditorTilesPlugin::_tile_atlas_control_gui_input(const Ref<InputEven
tile_set_selection.clear();
}
// Compute the covered area.
- Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos);
- Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_set_drag_start_mouse_pos, true);
+ Vector2i end_tile = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
if (start_tile != TileSetSource::INVALID_ATLAS_COORDS && end_tile != TileSetSource::INVALID_ATLAS_COORDS) {
Rect2i region = Rect2i(start_tile, end_tile - start_tile).abs();
region.size += Vector2i(1, 1);
@@ -2236,7 +2236,6 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
scene_tiles_list = memnew(ItemList);
scene_tiles_list->set_h_size_flags(Control::SIZE_EXPAND_FILL);
scene_tiles_list->set_v_size_flags(Control::SIZE_EXPAND_FILL);
- scene_tiles_list->set_drag_forwarding_compat(this);
scene_tiles_list->set_select_mode(ItemList::SELECT_MULTI);
scene_tiles_list->connect("multi_selected", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_multi_selected));
scene_tiles_list->connect("empty_clicked", callable_mp(this, &TileMapEditorTilesPlugin::_scenes_list_lmb_empty_clicked));
@@ -2641,7 +2640,7 @@ void TileMapEditorTerrainsPlugin::_stop_dragging() {
Transform2D xform = CanvasItemEditor::get_singleton()->get_canvas_transform() * tile_map->get_global_transform();
Vector2 mpos = xform.affine_inverse().xform(CanvasItemEditor::get_singleton()->get_viewport_control()->get_local_mouse_position());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (drag_type) {
case DRAG_TYPE_PICK: {
Vector2i coords = tile_map->local_to_map(mpos);
@@ -2875,7 +2874,7 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_type = DRAG_TYPE_PICK;
} else {
// Paint otherwise.
- if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
+ if (tool_buttons_group->get_pressed_button() == paint_tool_button && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT)) {
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
return true;
}
@@ -2890,14 +2889,14 @@ bool TileMapEditorTerrainsPlugin::forward_canvas_gui_input(const Ref<InputEvent>
drag_modified[E.key] = tile_map->get_cell(tile_map_layer, E.key);
tile_map->set_cell(tile_map_layer, E.key, E.value.source_id, E.value.get_atlas_coords(), E.value.alternative_tile);
}
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == line_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
return true;
}
drag_type = DRAG_TYPE_LINE;
drag_start_mouse_pos = mpos;
drag_modified.clear();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ } else if (tool_buttons_group->get_pressed_button() == rect_tool_button || (tool_buttons_group->get_pressed_button() == paint_tool_button && Input::get_singleton()->is_key_pressed(Key::SHIFT) && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
if (selected_terrain_set < 0 || selected_terrain < 0 || (selected_type == SELECTED_TYPE_PATTERN && !selected_terrains_pattern.is_valid())) {
return true;
}
@@ -2982,7 +2981,7 @@ void TileMapEditorTerrainsPlugin::forward_canvas_draw_over_viewport(Control *p_o
tile_xform.set_scale(tile_shape_size);
tile_set->draw_tile_shape(p_overlay, xform * tile_xform, Color(1.0, 1.0, 1.0), false);
}
- } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
+ } else if (!picker_button->is_pressed() && !(drag_type == DRAG_TYPE_NONE && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && !Input::get_singleton()->is_key_pressed(Key::SHIFT))) {
bool expand_grid = false;
if (tool_buttons_group->get_pressed_button() == paint_tool_button && drag_type == DRAG_TYPE_NONE) {
// Preview for a single tile.
@@ -3489,7 +3488,7 @@ void TileMapEditor::_advanced_menu_button_id_pressed(int p_id) {
}
if (p_id == 0) { // Replace Tile Proxies
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Replace Tiles with Proxies"));
for (int layer_index = 0; layer_index < tile_map->get_layers_count(); layer_index++) {
TypedArray<Vector2i> used_cells = tile_map->get_used_cells(layer_index);
@@ -3706,8 +3705,8 @@ void TileMapEditor::_update_layers_selection() {
}
void TileMapEditor::_move_tile_map_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo_man.is_null());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
TileMap *tile_map = Object::cast_to<TileMap>(p_edited);
if (!tile_map) {
diff --git a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
index ef82e748a8..f6aeffa13f 100644
--- a/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
+++ b/editor/plugins/tiles/tile_proxies_manager_dialog.cpp
@@ -30,10 +30,11 @@
#include "tile_proxies_manager_dialog.h"
-#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "scene/gui/dialogs.h"
+#include "scene/gui/popup_menu.h"
#include "scene/gui/separator.h"
void TileProxiesManagerDialog::_right_clicked(int p_item, Vector2 p_local_mouse_pos, MouseButton p_mouse_button_index, Object *p_item_list) {
@@ -55,7 +56,7 @@ void TileProxiesManagerDialog::_menu_id_pressed(int p_id) {
}
void TileProxiesManagerDialog::_delete_selected_bindings() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Tile Proxies"));
Vector<int> source_level_selected = source_level_list->get_selected_items();
@@ -155,7 +156,7 @@ void TileProxiesManagerDialog::_property_changed(const String &p_path, const Var
}
void TileProxiesManagerDialog::_add_button_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (from.source_id != TileSet::INVALID_SOURCE && to.source_id != TileSet::INVALID_SOURCE) {
Vector2i from_coords = from.get_atlas_coords();
Vector2i to_coords = to.get_atlas_coords();
@@ -196,7 +197,7 @@ void TileProxiesManagerDialog::_add_button_pressed() {
}
void TileProxiesManagerDialog::_clear_invalid_button_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete All Invalid Tile Proxies"));
undo_redo->add_do_method(*tile_set, "cleanup_invalid_tile_proxies");
@@ -224,7 +225,7 @@ void TileProxiesManagerDialog::_clear_invalid_button_pressed() {
}
void TileProxiesManagerDialog::_clear_all_button_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete All Tile Proxies"));
undo_redo->add_do_method(*tile_set, "clear_tile_proxies");
@@ -305,7 +306,7 @@ void TileProxiesManagerDialog::_unhandled_key_input(Ref<InputEvent> p_event) {
}
void TileProxiesManagerDialog::cancel_pressed() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (int i = 0; i < commited_actions_count; i++) {
undo_redo->undo();
}
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index 146a53f3dd..32421daa92 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -110,7 +110,7 @@ void TileSetAtlasSourceEditor::TileSetAtlasSourceProxyObject::_get_property_list
p_list->push_back(PropertyInfo(Variant::STRING, "name", PROPERTY_HINT_NONE, ""));
p_list->push_back(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "margins", PROPERTY_HINT_NONE, "suffix:px"));
- p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE, "suffix:px"));
+ p_list->push_back(PropertyInfo(Variant::VECTOR2I, "separation", PROPERTY_HINT_NONE));
p_list->push_back(PropertyInfo(Variant::VECTOR2I, "texture_region_size", PROPERTY_HINT_NONE, "suffix:px"));
p_list->push_back(PropertyInfo(Variant::BOOL, "use_texture_padding", PROPERTY_HINT_NONE, ""));
}
@@ -164,7 +164,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
if (p_name == "atlas_coords") {
Vector2i as_vector2i = Vector2i(p_value);
bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(as_vector2i, tile_set_atlas_source->get_tile_size_in_atlas(coords), tile_set_atlas_source->get_tile_animation_columns(coords), tile_set_atlas_source->get_tile_animation_separation(coords), tile_set_atlas_source->get_tile_animation_frames_count(coords), coords);
- ERR_FAIL_COND_V(!has_room_for_tile, false);
+ ERR_FAIL_COND_V_EDMSG(!has_room_for_tile, false, "Cannot move the tile, invalid coordinates or not enough room in the atlas for the tile and its animation frames.");
if (tiles_set_atlas_source_editor->selection.front()->get().tile == coords) {
tiles_set_atlas_source_editor->selection.clear();
@@ -223,7 +223,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
for (TileSelection tile : tiles) {
bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_separation(tile.tile), tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile);
if (!has_room_for_tile) {
- ERR_PRINT("No room for tile");
+ ERR_PRINT(vformat("Cannot change the number of columns to %s for tile animation. Not enough room in the atlas to layout %s frame(s).", p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile)));
} else {
tile_set_atlas_source->set_tile_animation_columns(tile.tile, p_value);
}
@@ -234,7 +234,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
for (TileSelection tile : tiles) {
bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile), tile.tile);
if (!has_room_for_tile) {
- ERR_PRINT("No room for tile");
+ ERR_PRINT(vformat("Cannot change separation between frames of the animation to %s. Not enough room in the atlas to layout %s frame(s).", p_value, tile_set_atlas_source->get_tile_animation_frames_count(tile.tile)));
} else {
tile_set_atlas_source->set_tile_animation_separation(tile.tile, p_value);
}
@@ -249,11 +249,16 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
return true;
} else if (p_name == "animation_frames_count") {
for (TileSelection tile : tiles) {
- bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), tile_set_atlas_source->get_tile_animation_separation(tile.tile), p_value, tile.tile);
+ int frame_count = p_value;
+ if (frame_count == 0) {
+ frame_count = 1;
+ }
+
+ bool has_room_for_tile = tile_set_atlas_source->has_room_for_tile(tile.tile, tile_set_atlas_source->get_tile_size_in_atlas(tile.tile), tile_set_atlas_source->get_tile_animation_columns(tile.tile), tile_set_atlas_source->get_tile_animation_separation(tile.tile), frame_count, tile.tile);
if (!has_room_for_tile) {
- ERR_PRINT("No room for tile");
+ ERR_PRINT(vformat("Cannot add frames to the animation, not enough room in the atlas to layout %s frames.", frame_count));
} else {
- tile_set_atlas_source->set_tile_animation_frames_count(tile.tile, p_value);
+ tile_set_atlas_source->set_tile_animation_frames_count(tile.tile, frame_count);
}
}
notify_property_list_changed();
@@ -1015,44 +1020,13 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Handle the event.
Ref<InputEventMouseMotion> mm = p_event;
if (mm.is_valid()) {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i last_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_last_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
- if (drag_type == DRAG_TYPE_NONE) {
- if (selection.size() == 1) {
- // Change the cursor depending on the hovered thing.
- TileSelection selected = selection.front()->get();
- if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
- Vector2 mouse_local_pos = tile_atlas_control->get_local_mouse_position();
- Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
- Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
- Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
- Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
- const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
- const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
- CursorShape cursor_shape = CURSOR_ARROW;
- bool can_grow[4];
- for (int i = 0; i < 4; i++) {
- can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
- can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
- }
- for (int i = 0; i < 4; i++) {
- Vector2 pos = rect.position + rect.size * coords[i];
- if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
- cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
- }
- Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
- if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
- cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
- }
- }
- tile_atlas_control->set_default_cursor_shape(cursor_shape);
- }
- }
- } else if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) {
+ if (drag_type == DRAG_TYPE_CREATE_BIG_TILE) {
// Create big tile.
new_base_tiles_coords = new_base_tiles_coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
@@ -1097,7 +1071,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Move tile.
Vector2 mouse_offset = (Vector2(tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile)) / 2.0 - Vector2(0.5, 0.5)) * tile_set->get_tile_size();
Vector2i coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position() - mouse_offset);
- coords = coords.max(Vector2i(0, 0)).min(grid_size - Vector2i(1, 1));
if (drag_current_tile != coords && tile_set_atlas_source->has_room_for_tile(coords, tile_set_atlas_source->get_tile_size_in_atlas(drag_current_tile), tile_set_atlas_source->get_tile_animation_columns(drag_current_tile), tile_set_atlas_source->get_tile_animation_separation(drag_current_tile), tile_set_atlas_source->get_tile_animation_frames_count(drag_current_tile), drag_current_tile)) {
tile_set_atlas_source->move_tile_in_atlas(drag_current_tile, coords);
selection.clear();
@@ -1243,7 +1216,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
- CursorShape cursor_shape = CURSOR_ARROW;
bool can_grow[4];
for (int i = 0; i < 4; i++) {
can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
@@ -1257,7 +1229,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
drag_last_mouse_pos = drag_start_mouse_pos;
drag_current_tile = selected.tile;
drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
}
Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
@@ -1266,10 +1237,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
drag_last_mouse_pos = drag_start_mouse_pos;
drag_current_tile = selected.tile;
drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
}
}
- tile_atlas_control->set_default_cursor_shape(cursor_shape);
}
}
@@ -1292,7 +1261,6 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
drag_last_mouse_pos = drag_start_mouse_pos;
drag_current_tile = selected.tile;
drag_start_tile_shape = Rect2i(selected.tile, tile_set_atlas_source->get_tile_size_in_atlas(selected.tile));
- tile_atlas_control->set_default_cursor_shape(CURSOR_MOVE);
} else {
// Start selection dragging.
drag_type = DRAG_TYPE_RECT_SELECT;
@@ -1332,7 +1300,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
}
void TileSetAtlasSourceEditor::_end_dragging() {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (drag_type) {
case DRAG_TYPE_CREATE_TILES:
undo_redo->create_action(TTR("Create tiles"));
@@ -1370,8 +1338,8 @@ void TileSetAtlasSourceEditor::_end_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_CREATE_TILES_USING_RECT: {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
undo_redo->create_action(TTR("Create tiles"));
@@ -1387,8 +1355,8 @@ void TileSetAtlasSourceEditor::_end_dragging() {
undo_redo->commit_action();
} break;
case DRAG_TYPE_REMOVE_TILES_USING_RECT: {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
List<PropertyInfo> list;
@@ -1438,8 +1406,8 @@ void TileSetAtlasSourceEditor::_end_dragging() {
}
break;
case DRAG_TYPE_RECT_SELECT: {
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
ERR_FAIL_COND(start_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS);
ERR_FAIL_COND(new_base_tiles_coords == TileSetSource::INVALID_ATLAS_COORDS);
@@ -1509,12 +1477,12 @@ void TileSetAtlasSourceEditor::_end_dragging() {
// We have a tile.
menu_option_coords = selected.tile;
menu_option_alternative = 0;
- base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ base_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i()));
} else if (hovered_base_tile_coords != TileSetSource::INVALID_ATLAS_COORDS) {
// We don't have a tile, but can create one.
menu_option_coords = hovered_base_tile_coords;
menu_option_alternative = TileSetSource::INVALID_TILE_ALTERNATIVE;
- empty_base_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ empty_base_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i()));
}
} break;
case DRAG_TYPE_RESIZE_TOP_LEFT:
@@ -1543,7 +1511,67 @@ void TileSetAtlasSourceEditor::_end_dragging() {
drag_modified_tiles.clear();
drag_type = DRAG_TYPE_NONE;
- tile_atlas_control->set_default_cursor_shape(CURSOR_ARROW);
+ // Change mouse accordingly.
+}
+
+Control::CursorShape TileSetAtlasSourceEditor::get_cursor_shape(const Point2 &p_pos) const {
+ Control::CursorShape cursor_shape = get_default_cursor_shape();
+ if (drag_type == DRAG_TYPE_NONE) {
+ if (selection.size() == 1) {
+ // Change the cursor depending on the hovered thing.
+ TileSelection selected = selection.front()->get();
+ if (selected.tile != TileSetSource::INVALID_ATLAS_COORDS && selected.alternative == 0) {
+ Transform2D xform = tile_atlas_control->get_global_transform().affine_inverse() * get_global_transform();
+ Vector2 mouse_local_pos = xform.xform(p_pos);
+ Vector2i size_in_atlas = tile_set_atlas_source->get_tile_size_in_atlas(selected.tile);
+ Rect2 region = tile_set_atlas_source->get_tile_texture_region(selected.tile);
+ Size2 zoomed_size = resize_handle->get_size() / tile_atlas_view->get_zoom();
+ Rect2 rect = region.grow_individual(zoomed_size.x, zoomed_size.y, 0, 0);
+ const Vector2i coords[] = { Vector2i(0, 0), Vector2i(1, 0), Vector2i(1, 1), Vector2i(0, 1) };
+ const Vector2i directions[] = { Vector2i(0, -1), Vector2i(1, 0), Vector2i(0, 1), Vector2i(-1, 0) };
+ bool can_grow[4];
+ for (int i = 0; i < 4; i++) {
+ can_grow[i] = tile_set_atlas_source->has_room_for_tile(selected.tile + directions[i], tile_set_atlas_source->get_tile_size_in_atlas(selected.tile), tile_set_atlas_source->get_tile_animation_columns(selected.tile), tile_set_atlas_source->get_tile_animation_separation(selected.tile), tile_set_atlas_source->get_tile_animation_frames_count(selected.tile), selected.tile);
+ can_grow[i] |= (i % 2 == 0) ? size_in_atlas.y > 1 : size_in_atlas.x > 1;
+ }
+ for (int i = 0; i < 4; i++) {
+ Vector2 pos = rect.position + rect.size * coords[i];
+ if (can_grow[i] && can_grow[(i + 3) % 4] && Rect2(pos, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_BDIAGSIZE : CURSOR_FDIAGSIZE;
+ }
+ Vector2 next_pos = rect.position + rect.size * coords[(i + 1) % 4];
+ if (can_grow[i] && Rect2((pos + next_pos) / 2.0, zoomed_size).has_point(mouse_local_pos)) {
+ cursor_shape = (i % 2) ? CURSOR_HSIZE : CURSOR_VSIZE;
+ }
+ }
+ }
+ }
+ } else {
+ switch (drag_type) {
+ case DRAG_TYPE_RESIZE_TOP_LEFT:
+ case DRAG_TYPE_RESIZE_BOTTOM_RIGHT:
+ cursor_shape = CURSOR_FDIAGSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_TOP:
+ case DRAG_TYPE_RESIZE_BOTTOM:
+ cursor_shape = CURSOR_VSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_TOP_RIGHT:
+ case DRAG_TYPE_RESIZE_BOTTOM_LEFT:
+ cursor_shape = CURSOR_BDIAGSIZE;
+ break;
+ case DRAG_TYPE_RESIZE_LEFT:
+ case DRAG_TYPE_RESIZE_RIGHT:
+ cursor_shape = CURSOR_HSIZE;
+ break;
+ case DRAG_TYPE_MOVE_TILE:
+ cursor_shape = CURSOR_MOVE;
+ break;
+ default:
+ break;
+ }
+ }
+ return cursor_shape;
}
HashMap<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_properties_per_tiles(const List<PropertyInfo> &r_list, const TileSetAtlasSource *p_atlas) {
@@ -1563,7 +1591,7 @@ HashMap<Vector2i, List<const PropertyInfo *>> TileSetAtlasSourceEditor::_group_p
}
void TileSetAtlasSourceEditor::_menu_option(int p_option) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_option) {
case TILE_DELETE: {
@@ -1747,8 +1775,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
}
} else if (drag_type == DRAG_TYPE_RECT_SELECT || drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT) {
// Draw tiles to be removed.
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
@@ -1777,8 +1805,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i tile_size = tile_set_atlas_source->get_texture_region_size();
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
for (int x = area.get_position().x; x < area.get_end().x; x++) {
@@ -1795,8 +1823,8 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_draw() {
// Draw the hovered tile.
if (drag_type == DRAG_TYPE_REMOVE_TILES_USING_RECT || drag_type == DRAG_TYPE_CREATE_TILES_USING_RECT) {
// Draw the rect.
- Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos);
- Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position());
+ Vector2i start_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(drag_start_mouse_pos, true);
+ Vector2i new_base_tiles_coords = tile_atlas_view->get_atlas_tile_coords_at_pos(tile_atlas_control->get_local_mouse_position(), true);
Rect2i area = Rect2i(start_base_tiles_coords, new_base_tiles_coords - start_base_tiles_coords).abs();
area.set_end((area.get_end() + Vector2i(1, 1)).min(tile_set_atlas_source->get_atlas_grid_size()));
Vector2i margins = tile_set_atlas_source->get_margins();
@@ -1950,7 +1978,7 @@ void TileSetAtlasSourceEditor::_tile_alternatives_control_gui_input(const Ref<In
selected = selection.front()->get();
menu_option_coords = selected.tile;
menu_option_alternative = selected.alternative;
- alternative_tile_popup_menu->popup(Rect2i(get_global_mouse_position(), Size2i()));
+ alternative_tile_popup_menu->popup(Rect2i(get_screen_transform().xform(get_local_mouse_position()), Size2i()));
}
}
@@ -2079,8 +2107,8 @@ void TileSetAtlasSourceEditor::_atlas_source_proxy_object_changed(String p_what)
}
void TileSetAtlasSourceEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(!undo_redo_man.is_valid());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
@@ -2210,7 +2238,7 @@ void TileSetAtlasSourceEditor::_auto_create_tiles() {
Vector2i separation = tile_set_atlas_source->get_separation();
Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
Size2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Create tiles in non-transparent texture regions"));
for (int y = 0; y < grid_size.y; y++) {
for (int x = 0; x < grid_size.x; x++) {
@@ -2256,7 +2284,7 @@ void TileSetAtlasSourceEditor::_auto_remove_tiles() {
Vector2i texture_region_size = tile_set_atlas_source->get_texture_region_size();
Vector2i grid_size = tile_set_atlas_source->get_atlas_grid_size();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove tiles in fully transparent texture regions"));
List<PropertyInfo> list;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.h b/editor/plugins/tiles/tile_set_atlas_source_editor.h
index 85f780ea26..bcab1296ad 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.h
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.h
@@ -277,6 +277,8 @@ public:
void edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_source, int p_source_id);
void init_source();
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos) const override;
+
TileSetAtlasSourceEditor();
~TileSetAtlasSourceEditor();
};
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index b44cb18dc7..53c2d4de51 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -67,7 +67,7 @@ void TileSetEditor::_drop_data_fw(const Point2 &p_point, const Variant &p_data,
// Actually create the new source.
Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
atlas_source->set_texture(resource);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a new atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
@@ -260,7 +260,7 @@ void TileSetEditor::_source_delete_pressed() {
Ref<TileSetSource> source = tile_set->get_source(to_delete);
// Remove the source.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove source"));
undo_redo->add_do_method(*tile_set, "remove_source", to_delete);
undo_redo->add_undo_method(*tile_set, "add_source", source, to_delete);
@@ -279,7 +279,7 @@ void TileSetEditor::_source_add_id_pressed(int p_id_pressed) {
Ref<TileSetAtlasSource> atlas_source = memnew(TileSetAtlasSource);
// Add a new source.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", atlas_source, source_id);
undo_redo->add_do_method(*atlas_source, "set_texture_region_size", tile_set->get_tile_size());
@@ -294,7 +294,7 @@ void TileSetEditor::_source_add_id_pressed(int p_id_pressed) {
Ref<TileSetScenesCollectionSource> scene_collection_source = memnew(TileSetScenesCollectionSource);
// Add a new source.
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add atlas source"));
undo_redo->add_do_method(*tile_set, "add_source", scene_collection_source, source_id);
undo_redo->add_undo_method(*tile_set, "remove_source", source_id);
@@ -369,7 +369,7 @@ void TileSetEditor::_patterns_item_list_gui_input(const Ref<InputEvent> &p_event
if (ED_IS_SHORTCUT("tiles_editor/delete", p_event) && p_event->is_pressed() && !p_event->is_echo()) {
Vector<int> selected = patterns_item_list->get_selected_items();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove TileSet patterns"));
for (int i = 0; i < selected.size(); i++) {
int pattern_index = selected[i];
@@ -416,8 +416,8 @@ void TileSetEditor::_tab_changed(int p_tab_changed) {
}
void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_edited, String p_array_prefix, int p_from_index, int p_to_pos) {
- Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo_man.is_null());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
TileSet *ed_tile_set = Object::cast_to<TileSet>(p_edited);
if (!ed_tile_set) {
@@ -462,6 +462,35 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
}
#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
+
+ // Add undo method to adding array element.
+ if (p_array_prefix == "occlusion_layer_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_occlusion_layer", p_to_pos < 0 ? ed_tile_set->get_occlusion_layers_count() : p_to_pos);
+ }
+ } else if (p_array_prefix == "physics_layer_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_physics_layer", p_to_pos < 0 ? ed_tile_set->get_physics_layers_count() : p_to_pos);
+ }
+ } else if (p_array_prefix == "terrain_set_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_terrain_set", p_to_pos < 0 ? ed_tile_set->get_terrain_sets_count() : p_to_pos);
+ }
+ } else if (components.size() >= 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "terrain_") {
+ int terrain_set = components[0].trim_prefix("terrain_set_").to_int();
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_terrain", terrain_set, p_to_pos < 0 ? ed_tile_set->get_terrains_count(terrain_set) : p_to_pos);
+ }
+ } else if (p_array_prefix == "navigation_layer_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_navigation_layer", p_to_pos < 0 ? ed_tile_set->get_navigation_layers_count() : p_to_pos);
+ }
+ } else if (p_array_prefix == "custom_data_layer_") {
+ if (p_from_index < 0) {
+ undo_redo_man->add_undo_method(ed_tile_set, "remove_custom_data_layer", p_to_pos < 0 ? ed_tile_set->get_custom_data_layers_count() : p_to_pos);
+ }
+ }
+
// Save layers' properties.
List<PropertyInfo> properties;
ed_tile_set->get_property_list(&properties);
@@ -543,7 +572,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
}
#undef ADD_UNDO
- // Add do method.
+ // Add do method to add/remove array element.
if (p_array_prefix == "occlusion_layer_") {
if (p_from_index < 0) {
undo_redo_man->add_do_method(ed_tile_set, "add_occlusion_layer", p_to_pos);
@@ -597,8 +626,8 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
}
void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p_edited, String p_property, Variant p_new_value) {
- Ref<EditorUndoRedoManager> undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
- ERR_FAIL_COND(undo_redo_man.is_null());
+ EditorUndoRedoManager *undo_redo_man = Object::cast_to<EditorUndoRedoManager>(p_undo_redo);
+ ERR_FAIL_NULL(undo_redo_man);
#define ADD_UNDO(obj, property) undo_redo_man->add_undo_property(obj, property, obj->get(property));
TileSet *ed_tile_set = Object::cast_to<TileSet>(p_edited);
@@ -637,11 +666,6 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
#undef ADD_UNDO
}
-void TileSetEditor::_bind_methods() {
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetEditor::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetEditor::_drop_data_fw);
-}
-
void TileSetEditor::edit(Ref<TileSet> p_tile_set) {
if (p_tile_set == tile_set) {
return;
@@ -728,7 +752,7 @@ TileSetEditor::TileSetEditor() {
sources_list->add_user_signal(MethodInfo("sort_request"));
sources_list->connect("sort_request", callable_mp(this, &TileSetEditor::_update_sources_list).bind(-1));
sources_list->set_texture_filter(CanvasItem::TEXTURE_FILTER_NEAREST);
- sources_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CDU(sources_list, TileSetEditor);
split_container_left_side->add_child(sources_list);
HBoxContainer *sources_bottom_actions = memnew(HBoxContainer);
diff --git a/editor/plugins/tiles/tile_set_editor.h b/editor/plugins/tiles/tile_set_editor.h
index 33200a0632..e3dff11277 100644
--- a/editor/plugins/tiles/tile_set_editor.h
+++ b/editor/plugins/tiles/tile_set_editor.h
@@ -97,7 +97,6 @@ private:
protected:
void _notification(int p_what);
- static void _bind_methods();
public:
_FORCE_INLINE_ static TileSetEditor *get_singleton() { return singleton; }
diff --git a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
index 0ff8788626..6251cd18f7 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -237,7 +237,7 @@ void TileSetScenesCollectionSourceEditor::_scenes_list_item_activated(int p_inde
void TileSetScenesCollectionSourceEditor::_source_add_pressed() {
int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", Ref<PackedScene>(), scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
@@ -252,7 +252,7 @@ void TileSetScenesCollectionSourceEditor::_source_delete_pressed() {
ERR_FAIL_COND(selected_indices.size() <= 0);
int scene_id = scene_tiles_list->get_item_metadata(selected_indices[0]);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "create_scene_tile", tile_set_scenes_collection_source->get_scene_tile_scene(scene_id), scene_id);
@@ -404,7 +404,7 @@ void TileSetScenesCollectionSourceEditor::_drop_data_fw(const Point2 &p_point, c
Ref<PackedScene> resource = ResourceLoader::load(files[i]);
if (resource.is_valid()) {
int scene_id = tile_set_scenes_collection_source->get_next_scene_tile_id();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add a Scene Tile"));
undo_redo->add_do_method(tile_set_scenes_collection_source, "create_scene_tile", resource, scene_id);
undo_redo->add_undo_method(tile_set_scenes_collection_source, "remove_scene_tile", scene_id);
@@ -453,8 +453,6 @@ void TileSetScenesCollectionSourceEditor::_bind_methods() {
ADD_SIGNAL(MethodInfo("source_id_changed", PropertyInfo(Variant::INT, "source_id")));
ClassDB::bind_method(D_METHOD("_scene_thumbnail_done"), &TileSetScenesCollectionSourceEditor::_scene_thumbnail_done);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TileSetScenesCollectionSourceEditor::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TileSetScenesCollectionSourceEditor::_drop_data_fw);
}
TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
@@ -509,7 +507,7 @@ TileSetScenesCollectionSourceEditor::TileSetScenesCollectionSourceEditor() {
scene_tiles_list = memnew(ItemList);
scene_tiles_list->set_h_size_flags(SIZE_EXPAND_FILL);
scene_tiles_list->set_v_size_flags(SIZE_EXPAND_FILL);
- scene_tiles_list->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CDU(scene_tiles_list, TileSetScenesCollectionSourceEditor);
scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_tile_inspector).unbind(1));
scene_tiles_list->connect("item_selected", callable_mp(this, &TileSetScenesCollectionSourceEditor::_update_action_buttons).unbind(1));
scene_tiles_list->connect("item_activated", callable_mp(this, &TileSetScenesCollectionSourceEditor::_scenes_list_item_activated));
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 56dbdb49eb..96b1ad7ee0 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -129,30 +129,32 @@ void VisualShaderGraphPlugin::set_connections(const List<VisualShader::Connectio
void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p_node_id, int p_port_id) {
if (visual_shader->get_shader_type() == p_type && links.has(p_node_id) && links[p_node_id].output_ports.has(p_port_id)) {
- for (const KeyValue<int, Port> &E : links[p_node_id].output_ports) {
+ Link &link = links[p_node_id];
+
+ for (const KeyValue<int, Port> &E : link.output_ports) {
if (E.value.preview_button != nullptr) {
E.value.preview_button->set_pressed(false);
}
}
+ bool is_dirty = link.preview_pos < 0;
- if (links[p_node_id].preview_visible && !is_dirty() && links[p_node_id].preview_box != nullptr) {
- links[p_node_id].graph_node->remove_child(links[p_node_id].preview_box);
- memdelete(links[p_node_id].preview_box);
- links[p_node_id].graph_node->reset_size();
- links[p_node_id].preview_visible = false;
+ if (!is_dirty && link.preview_visible && link.preview_box != nullptr) {
+ link.graph_node->remove_child(link.preview_box);
+ memdelete(link.preview_box);
+ link.preview_box = nullptr;
+ link.graph_node->reset_size();
+ link.preview_visible = false;
}
- if (p_port_id != -1 && links[p_node_id].output_ports[p_port_id].preview_button != nullptr) {
- if (is_dirty()) {
- links[p_node_id].preview_pos = links[p_node_id].graph_node->get_child_count();
+ if (p_port_id != -1 && link.output_ports[p_port_id].preview_button != nullptr) {
+ if (is_dirty) {
+ link.preview_pos = link.graph_node->get_child_count();
}
VBoxContainer *vbox = memnew(VBoxContainer);
- links[p_node_id].graph_node->add_child(vbox);
- if (links[p_node_id].preview_pos != -1) {
- links[p_node_id].graph_node->move_child(vbox, links[p_node_id].preview_pos);
- }
- links[p_node_id].graph_node->set_slot_draw_stylebox(vbox->get_index(), false);
+ link.graph_node->add_child(vbox);
+ link.graph_node->move_child(vbox, link.preview_pos);
+ link.graph_node->set_slot_draw_stylebox(vbox->get_index(), false);
Control *offset = memnew(Control);
offset->set_custom_minimum_size(Size2(0, 5 * EDSCALE));
@@ -162,9 +164,9 @@ void VisualShaderGraphPlugin::show_port_preview(VisualShader::Type p_type, int p
port_preview->setup(visual_shader, visual_shader->get_shader_type(), p_node_id, p_port_id);
port_preview->set_h_size_flags(Control::SIZE_SHRINK_CENTER);
vbox->add_child(port_preview);
- links[p_node_id].preview_visible = true;
- links[p_node_id].preview_box = vbox;
- links[p_node_id].output_ports[p_port_id].preview_button->set_pressed(true);
+ link.preview_visible = true;
+ link.preview_box = vbox;
+ link.output_ports[p_port_id].preview_button->set_pressed(true);
}
}
}
@@ -329,14 +331,6 @@ void VisualShaderGraphPlugin::clear_links() {
links.clear();
}
-bool VisualShaderGraphPlugin::is_dirty() const {
- return dirty;
-}
-
-void VisualShaderGraphPlugin::make_dirty(bool p_enabled) {
- dirty = p_enabled;
-}
-
void VisualShaderGraphPlugin::register_link(VisualShader::Type p_type, int p_id, VisualShaderNode *p_visual_node, GraphNode *p_graph_node) {
links.insert(p_id, { p_type, p_visual_node, p_graph_node, p_visual_node->get_output_port_for_preview() != -1, -1, HashMap<int, InputPort>(), HashMap<int, Port>(), nullptr, nullptr, nullptr, { nullptr, nullptr, nullptr } });
}
@@ -426,7 +420,13 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
editor->_update_created_node(node);
if (p_just_update) {
- links[p_id].graph_node = node;
+ Link &link = links[p_id];
+
+ link.graph_node = node;
+ link.preview_box = nullptr;
+ link.preview_pos = -1;
+ link.output_ports.clear();
+ link.input_ports.clear();
} else {
register_link(p_type, p_id, vsnode.ptr(), node);
}
@@ -1861,7 +1861,7 @@ void VisualShaderEditor::_update_parameters(bool p_update_refs) {
}
void VisualShaderEditor::_update_parameter_refs(HashSet<String> &p_deleted_names) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (int i = 0; i < VisualShader::TYPE_MAX; i++) {
VisualShader::Type type = VisualShader::Type(i);
@@ -1916,15 +1916,12 @@ void VisualShaderEditor::_update_graph() {
_update_varyings();
graph_plugin->clear_links();
- graph_plugin->make_dirty(true);
graph_plugin->update_theme();
for (int n_i = 0; n_i < nodes.size(); n_i++) {
graph_plugin->add_node(type, nodes[n_i], false);
}
- graph_plugin->make_dirty(false);
-
for (const VisualShader::Connection &E : node_connections) {
int from = E.from_node;
int from_idx = E.from_port;
@@ -1961,7 +1958,7 @@ void VisualShaderEditor::_add_input_port(int p_node, int p_port, int p_port_type
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Input Port"));
undo_redo->add_do_method(node.ptr(), "add_input_port", p_port, p_port_type, p_name);
undo_redo->add_undo_method(node.ptr(), "remove_input_port", p_port);
@@ -1977,7 +1974,7 @@ void VisualShaderEditor::_add_output_port(int p_node, int p_port, int p_port_typ
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Output Port"));
undo_redo->add_do_method(node.ptr(), "add_output_port", p_port, p_port_type, p_name);
undo_redo->add_undo_method(node.ptr(), "remove_output_port", p_port);
@@ -1993,7 +1990,7 @@ void VisualShaderEditor::_change_input_port_type(int p_type, int p_node, int p_p
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Input Port Type"));
undo_redo->add_do_method(node.ptr(), "set_input_port_type", p_port, p_type);
undo_redo->add_undo_method(node.ptr(), "set_input_port_type", p_port, node->get_input_port_type(p_port));
@@ -2009,7 +2006,7 @@ void VisualShaderEditor::_change_output_port_type(int p_type, int p_node, int p_
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Output Port Type"));
undo_redo->add_do_method(node.ptr(), "set_output_port_type", p_port, p_type);
undo_redo->add_undo_method(node.ptr(), "set_output_port_type", p_port, node->get_output_port_type(p_port));
@@ -2038,7 +2035,7 @@ void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Input Port Name"));
undo_redo->add_do_method(node.ptr(), "set_input_port_name", p_port_id, validated_name);
undo_redo->add_undo_method(node.ptr(), "set_input_port_name", p_port_id, node->get_input_port_name(p_port_id));
@@ -2065,7 +2062,7 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Change Output Port Name"));
undo_redo->add_do_method(node.ptr(), "set_output_port_name", p_port_id, validated_name);
undo_redo->add_undo_method(node.ptr(), "set_output_port_name", p_port_id, prev_name);
@@ -2078,7 +2075,7 @@ void VisualShaderEditor::_expand_output_port(int p_node, int p_port, bool p_expa
Ref<VisualShaderNode> node = visual_shader->get_node(type, p_node);
ERR_FAIL_COND(!node.is_valid());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_expand) {
undo_redo->create_action(TTR("Expand Output Port"));
} else {
@@ -2176,7 +2173,7 @@ void VisualShaderEditor::_remove_input_port(int p_node, int p_port) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Input Port"));
List<VisualShader::Connection> conns;
@@ -2226,7 +2223,7 @@ void VisualShaderEditor::_remove_output_port(int p_node, int p_port) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Output Port"));
List<VisualShader::Connection> conns;
@@ -2293,7 +2290,7 @@ void VisualShaderEditor::_expression_focus_out(Object *code_edit, int p_node) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set VisualShader Expression"));
undo_redo->add_do_method(node.ptr(), "set_expression", expression_box->get_text());
undo_redo->add_undo_method(node.ptr(), "set_expression", node->get_expression());
@@ -2357,7 +2354,7 @@ void VisualShaderEditor::_node_resized(const Vector2 &p_new_size, int p_type, in
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Resize VisualShader Node"), UndoRedo::MERGE_ENDS);
undo_redo->add_do_method(this, "_set_node_size", p_type, p_node, p_new_size);
undo_redo->add_undo_method(this, "_set_node_size", p_type, p_node, node->get_size());
@@ -2374,7 +2371,7 @@ void VisualShaderEditor::_preview_select_port(int p_node, int p_port) {
if (node->get_output_port_for_preview() == p_port) {
p_port = -1; //toggle it
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(p_port == -1 ? TTR("Hide Port Preview") : TTR("Show Port Preview"));
undo_redo->add_do_method(node.ptr(), "set_output_port_for_preview", p_port);
undo_redo->add_undo_method(node.ptr(), "set_output_port_for_preview", prev_port);
@@ -2420,7 +2417,7 @@ void VisualShaderEditor::_comment_title_popup_hide() {
if (node->get_title() == comment_title_change_edit->get_text()) {
return; // nothing changed - ignored
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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());
@@ -2463,7 +2460,7 @@ void VisualShaderEditor::_comment_desc_popup_hide() {
if (node->get_description() == comment_desc_change_edit->get_text()) {
return; // nothing changed - ignored
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
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());
@@ -2484,7 +2481,7 @@ void VisualShaderEditor::_parameter_line_edit_changed(const String &p_text, int
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Parameter Name"));
undo_redo->add_do_method(node.ptr(), "set_parameter_name", validated_name);
undo_redo->add_undo_method(node.ptr(), "set_parameter_name", node->get_parameter_name());
@@ -2520,7 +2517,7 @@ void VisualShaderEditor::_port_edited(const StringName &p_property, const Varian
Ref<VisualShaderNode> vsn = visual_shader->get_node(type, editing_node);
ERR_FAIL_COND(!vsn.is_valid());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Input Default Port"));
Ref<VisualShaderNodeCustom> custom = Object::cast_to<VisualShaderNodeCustom>(vsn.ptr());
@@ -2966,7 +2963,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
int id_to_use = visual_shader->get_valid_node_id(type);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_resource_path.is_empty()) {
undo_redo->create_action(TTR("Add Node to Visual Shader"));
} else {
@@ -3133,7 +3130,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
}
void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::VaryingMode p_mode, VisualShader::VaryingType p_type) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Add Varying to Visual Shader: %s"), p_name));
undo_redo->add_do_method(visual_shader.ptr(), "add_varying", p_name, p_mode, p_type);
@@ -3168,7 +3165,7 @@ void VisualShaderEditor::_add_varying(const String &p_name, VisualShader::Varyin
}
void VisualShaderEditor::_remove_varying(const String &p_name) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Remove Varying from Visual Shader: %s"), p_name));
VisualShader::VaryingMode var_mode = visual_shader->get_varying_mode(p_name);
@@ -3256,7 +3253,7 @@ void VisualShaderEditor::_node_dragged(const Vector2 &p_from, const Vector2 &p_t
void VisualShaderEditor::_nodes_dragged() {
drag_dirty = false;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Node(s) Moved"));
for (const DragOp &E : drag_buffer) {
@@ -3280,7 +3277,7 @@ void VisualShaderEditor::_connection_request(const String &p_from, int p_from_in
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Connected"));
List<VisualShader::Connection> conns;
@@ -3312,7 +3309,7 @@ void VisualShaderEditor::_disconnection_request(const String &p_from, int p_from
int from = p_from.to_int();
int to = p_to.to_int();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Nodes Disconnected"));
undo_redo->add_do_method(visual_shader.ptr(), "disconnect_nodes", type, from, p_from_index, to, p_to_index);
undo_redo->add_undo_method(visual_shader.ptr(), "connect_nodes", type, from, p_from_index, to, p_to_index);
@@ -3352,7 +3349,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
List<VisualShader::Connection> conns;
visual_shader->get_node_connections(type, &conns);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
for (const int &F : p_nodes) {
for (const VisualShader::Connection &E : conns) {
if (E.from_node == F || E.to_node == F) {
@@ -3411,7 +3408,7 @@ void VisualShaderEditor::_delete_nodes(int p_type, const List<int> &p_nodes) {
}
void VisualShaderEditor::_replace_node(VisualShader::Type p_type_id, int p_node_id, const StringName &p_from, const StringName &p_to) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_to);
undo_redo->add_undo_method(visual_shader.ptr(), "replace_node", p_type_id, p_node_id, p_from);
}
@@ -3446,7 +3443,7 @@ void VisualShaderEditor::_update_parameter(VisualShader::Type p_type_id, int p_n
void VisualShaderEditor::_convert_constants_to_parameters(bool p_vice_versa) {
VisualShader::Type type_id = get_current_shader_type();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (!p_vice_versa) {
undo_redo->create_action(TTR("Convert Constant Node(s) To Parameter(s)"));
} else {
@@ -3645,7 +3642,7 @@ void VisualShaderEditor::_delete_node_request(int p_type, int p_node) {
List<int> to_erase;
to_erase.push_back(p_node);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete VisualShader Node"));
_delete_nodes(p_type, to_erase);
undo_redo->commit_action();
@@ -3674,7 +3671,7 @@ void VisualShaderEditor::_delete_nodes_request(const TypedArray<StringName> &p_n
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete VisualShader Node(s)"));
_delete_nodes(get_current_shader_type(), to_erase);
undo_redo->commit_action();
@@ -4087,7 +4084,7 @@ void VisualShaderEditor::_dup_copy_nodes(int p_type, List<CopyItem> &r_items, Li
}
void VisualShaderEditor::_dup_paste_nodes(int p_type, List<CopyItem> &r_items, const List<VisualShader::Connection> &p_connections, const Vector2 &p_offset, bool p_duplicate) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_duplicate) {
undo_redo->create_action(TTR("Duplicate VisualShader Node(s)"));
} else {
@@ -4206,7 +4203,7 @@ void VisualShaderEditor::_copy_nodes(bool p_cut) {
_dup_copy_nodes(get_current_shader_type(), copy_items_buffer, copy_connections_buffer);
if (p_cut) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Cut VisualShader Node(s)"));
List<int> ids;
@@ -4293,7 +4290,7 @@ void VisualShaderEditor::_input_select_item(Ref<VisualShaderNodeInput> p_input,
bool type_changed = next_input_type != prev_input_type;
- Ref<EditorUndoRedoManager> &undo_redo_man = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
undo_redo_man->create_action(TTR("Visual Shader Input Type Changed"));
undo_redo_man->add_do_method(p_input.ptr(), "set_input_name", p_name);
@@ -4362,7 +4359,7 @@ void VisualShaderEditor::_parameter_ref_select_item(Ref<VisualShaderNodeParamete
bool type_changed = p_parameter_ref->get_parameter_type_by_name(p_name) != p_parameter_ref->get_parameter_type_by_name(prev_name);
- Ref<EditorUndoRedoManager> &undo_redo_man = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
undo_redo_man->create_action(TTR("ParameterRef Name Changed"));
undo_redo_man->add_do_method(p_parameter_ref.ptr(), "set_parameter_name", p_name);
@@ -4406,7 +4403,7 @@ void VisualShaderEditor::_varying_select_item(Ref<VisualShaderNodeVarying> p_var
bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
- Ref<EditorUndoRedoManager> &undo_redo_man = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo_man = EditorUndoRedoManager::get_singleton();
undo_redo_man->create_action(TTR("Varying Name Changed"));
undo_redo_man->add_do_method(p_varying.ptr(), "set_varying_name", p_name);
@@ -4477,7 +4474,7 @@ void VisualShaderEditor::_float_constant_selected(int p_which) {
return; // same
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Set Constant: %s"), float_constant_defs[p_which].name));
undo_redo->add_do_method(node.ptr(), "set_constant", float_constant_defs[p_which].value);
undo_redo->add_undo_method(node.ptr(), "set_constant", node->get_constant());
@@ -4741,7 +4738,7 @@ void VisualShaderEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
saved_node_pos_dirty = true;
_add_node(idx, add_options[idx].ops);
} else if (d.has("files")) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Node(s) to Visual Shader"));
if (d["files"].get_type() == Variant::PACKED_STRING_ARRAY) {
@@ -4905,10 +4902,6 @@ void VisualShaderEditor::_bind_methods() {
ClassDB::bind_method("_update_options_menu_deferred", &VisualShaderEditor::_update_options_menu_deferred);
ClassDB::bind_method("_rebuild_shader_deferred", &VisualShaderEditor::_rebuild_shader_deferred);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &VisualShaderEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &VisualShaderEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &VisualShaderEditor::drop_data_fw);
-
ClassDB::bind_method("_is_available", &VisualShaderEditor::_is_available);
}
@@ -4922,7 +4915,7 @@ VisualShaderEditor::VisualShaderEditor() {
graph->set_h_size_flags(SIZE_EXPAND_FILL);
graph->set_show_zoom_label(true);
add_child(graph);
- graph->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(graph, VisualShaderEditor);
float graph_minimap_opacity = EDITOR_GET("editors/visual_editors/minimap_opacity");
graph->set_minimap_opacity(graph_minimap_opacity);
float graph_lines_curvature = EDITOR_GET("editors/visual_editors/lines_curvature");
@@ -5153,7 +5146,7 @@ VisualShaderEditor::VisualShaderEditor() {
members = memnew(Tree);
members_vb->add_child(members);
- members->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(members, VisualShaderEditor);
members->set_h_size_flags(SIZE_EXPAND_FILL);
members->set_v_size_flags(SIZE_EXPAND_FILL);
members->set_hide_root(true);
@@ -5448,11 +5441,9 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("Binormal", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "binormal", "BINORMAL"), { "binormal" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Color", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "color", "COLOR"), { "color" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("DepthTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "depth_texture", "DEPTH_TEXTURE"), { "depth_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("FragCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "fragcoord", "FRAGCOORD"), { "fragcoord" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("FrontFacing", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "front_facing", "FRONT_FACING"), { "front_facing" }, VisualShaderNode::PORT_TYPE_BOOLEAN, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
- add_options.push_back(AddOption("ScreenTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture", "SCREEN_TEXTURE"), { "screen_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Tangent", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "tangent", "TANGENT"), { "tangent" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
add_options.push_back(AddOption("Vertex", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_vertex_and_fragment_shader_modes, "vertex", "VERTEX"), { "vertex" }, VisualShaderNode::PORT_TYPE_VECTOR_3D, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
@@ -5495,7 +5486,6 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("NormalTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "normal_texture", "NORMAL_TEXTURE"), { "normal_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("PointCoord", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "point_coord", "POINT_COORD"), { "point_coord" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ScreenPixelSize", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_pixel_size", "SCREEN_PIXEL_SIZE"), { "screen_pixel_size" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
- add_options.push_back(AddOption("ScreenTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "screen_texture", "SCREEN_TEXTURE"), { "screen_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("ScreenUV", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "screen_uv", "SCREEN_UV"), { "screen_uv" }, VisualShaderNode::PORT_TYPE_VECTOR_2D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("SpecularShininess", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_and_light_shader_modes, "specular_shininess", "SPECULAR_SHININESS"), { "specular_shininess" }, VisualShaderNode::PORT_TYPE_VECTOR_4D, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
add_options.push_back(AddOption("SpecularShininessTexture", "Input/Fragment", "VisualShaderNodeInput", vformat(input_param_for_fragment_shader_mode, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE"), { "specular_shininess_texture" }, VisualShaderNode::PORT_TYPE_SAMPLER, TYPE_FLAGS_FRAGMENT, Shader::MODE_CANVAS_ITEM));
@@ -5699,7 +5689,7 @@ VisualShaderEditor::VisualShaderEditor() {
add_options.push_back(AddOption("CurveTexture", "Textures/Functions", "VisualShaderNodeCurveTexture", TTR("Perform the curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_SCALAR));
curve_xyz_node_option_idx = add_options.size();
add_options.push_back(AddOption("CurveXYZTexture", "Textures/Functions", "VisualShaderNodeCurveXYZTexture", TTR("Perform the three components curve texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_3D));
- add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value of the DEPTH_TEXTURE node in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
+ add_options.push_back(AddOption("LinearSceneDepth", "Textures/Functions", "VisualShaderNodeLinearSceneDepth", TTR("Returns the depth value obtained from the depth prepass in a linear space."), {}, VisualShaderNode::PORT_TYPE_SCALAR, TYPE_FLAGS_FRAGMENT, Shader::MODE_SPATIAL));
texture2d_node_option_idx = add_options.size();
add_options.push_back(AddOption("Texture2D", "Textures/Functions", "VisualShaderNodeTexture", TTR("Perform the 2D texture lookup."), {}, VisualShaderNode::PORT_TYPE_VECTOR_4D));
texture2d_array_node_option_idx = add_options.size();
@@ -6172,7 +6162,7 @@ public:
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
updating = true;
undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS);
@@ -6374,7 +6364,7 @@ void EditorPropertyVisualShaderMode::_option_selected(int p_which) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Visual Shader Mode Changed"));
//do is easy
undo_redo->add_do_method(visual_shader.ptr(), "set_mode", p_which);
diff --git a/editor/plugins/visual_shader_editor_plugin.h b/editor/plugins/visual_shader_editor_plugin.h
index 88f5e3359c..c4f6b4952c 100644
--- a/editor/plugins/visual_shader_editor_plugin.h
+++ b/editor/plugins/visual_shader_editor_plugin.h
@@ -95,7 +95,6 @@ private:
Ref<VisualShader> visual_shader;
HashMap<int, Link> links;
List<VisualShader::Connection> connections;
- bool dirty = false;
Color vector_expanded_color[4];
@@ -115,8 +114,6 @@ public:
void clear_links();
void set_shader_type(VisualShader::Type p_type);
bool is_preview_visible(int p_id) const;
- bool is_dirty() const;
- void make_dirty(bool p_enabled);
void update_node(VisualShader::Type p_type, int p_id);
void update_node_deferred(VisualShader::Type p_type, int p_node_id);
void add_node(VisualShader::Type p_type, int p_id, bool p_just_update);
diff --git a/editor/project_converter_3_to_4.cpp b/editor/project_converter_3_to_4.cpp
index 8396d50a0e..b5dca26c63 100644
--- a/editor/project_converter_3_to_4.cpp
+++ b/editor/project_converter_3_to_4.cpp
@@ -210,6 +210,7 @@ static const char *gdscript_function_renames[][2] = {
// { "set_v_offset", "set_drag_vertical_offset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// {"get_points","get_points_id"},// Astar, broke Line2D, Convexpolygonshape
// {"get_v_scroll","get_v_scroll_bar"},//ItemList, broke TextView
+ // { "get_stylebox", "get_theme_stylebox" }, // Control - Will rename the method in Theme as well, skipping
{ "_about_to_show", "_about_to_popup" }, // ColorPickerButton
{ "_get_configuration_warning", "_get_configuration_warnings" }, // Node
{ "_set_current", "set_current" }, // Camera2D
@@ -237,7 +238,6 @@ static const char *gdscript_function_renames[][2] = {
{ "bumpmap_to_normalmap", "bump_map_to_normal_map" }, // Image
{ "can_be_hidden", "_can_be_hidden" }, // EditorNode3DGizmoPlugin
{ "can_drop_data", "_can_drop_data" }, // Control
- { "can_drop_data_fw", "_can_drop_data_fw" }, // ScriptEditor
{ "can_generate_small_preview", "_can_generate_small_preview" }, // EditorResourcePreviewGenerator
{ "can_instance", "can_instantiate" }, // PackedScene, Script
{ "canvas_light_set_scale", "canvas_light_set_texture_scale" }, // RenderingServer
@@ -264,7 +264,6 @@ static const char *gdscript_function_renames[][2] = {
{ "deselect_items", "deselect_all" }, // FileDialog
{ "disable_plugin", "_disable_plugin" }, // EditorPlugin
{ "drop_data", "_drop_data" }, // Control
- { "drop_data_fw", "_drop_data_fw" }, // ScriptEditor
{ "exclude_polygons_2d", "exclude_polygons" }, // Geometry2D
{ "find_node", "find_child" }, // Node
{ "find_scancode_from_string", "find_keycode_from_string" }, // OS
@@ -303,7 +302,6 @@ static const char *gdscript_function_renames[][2] = {
{ "get_d", "get_distance" }, // LineShape2D
{ "get_depth_bias_enable", "get_depth_bias_enabled" }, // RDPipelineRasterizationState
{ "get_drag_data", "_get_drag_data" }, // Control
- { "get_drag_data_fw", "_get_drag_data_fw" }, // ScriptEditor
{ "get_editor_viewport", "get_editor_main_screen" }, // EditorPlugin
{ "get_enabled_focus_mode", "get_focus_mode" }, // BaseButton
{ "get_endian_swap", "is_big_endian" }, // File
@@ -668,6 +666,7 @@ static const char *csharp_function_renames[][2] = {
// { "SetVOffset", "SetDragVerticalOffset" }, // Camera2D broke Camera3D, PathFollow3D, PathFollow2D
// {"GetPoints","GetPointsId"},// Astar, broke Line2D, Convexpolygonshape
// {"GetVScroll","GetVScrollBar"},//ItemList, broke TextView
+ // { "GetStylebox", "GetThemeStylebox" }, // Control - Will rename the method in Theme as well, skipping
{ "AddSpatialGizmoPlugin", "AddNode3dGizmoPlugin" }, // EditorPlugin
{ "RenderingServer", "GetTabAlignment" }, // Tab
{ "_AboutToShow", "_AboutToPopup" }, // ColorPickerButton
@@ -1081,6 +1080,7 @@ static const char *gdscript_properties_renames[][2] = {
// { "zfar", "far" }, // Camera3D
// { "znear", "near" }, // Camera3D
// { "filename", "scene_file_path" }, // Node
+ // { "pressed", "button_pressed" }, // BaseButton - Will also rename the signal, skipping for now
{ "as_normalmap", "as_normal_map" }, // NoiseTexture
{ "bbcode_text", "text" }, // RichTextLabel
{ "bg", "panel" }, // Theme
@@ -1116,6 +1116,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "gravity_vec", "gravity_direction" }, // Area2D
{ "hint_tooltip", "tooltip_text" }, // Control
{ "hseparation", "h_separation" }, // Theme
+ { "icon_align", "icon_alignment" }, // Button
{ "iterations_per_second", "physics_ticks_per_second" }, // Engine
{ "invert_enable", "invert_enabled" }, // Polygon2D
{ "margin_bottom", "offset_bottom" }, // Control broke NinePatchRect, StyleBox
@@ -1140,7 +1141,7 @@ static const char *gdscript_properties_renames[][2] = {
{ "rect_position", "position" }, // Control
{ "rect_global_position", "global_position" }, // Control
{ "rect_size", "size" }, // Control
- { "rect_min_size", "minimum_size" }, // Control
+ { "rect_min_size", "custom_minimum_size" }, // Control
{ "rect_rotation", "rotation" }, // Control
{ "rect_scale", "scale" }, // Control
{ "rect_pivot_offset", "pivot_offset" }, // Control
@@ -1195,6 +1196,7 @@ static const char *csharp_properties_renames[][2] = {
// { "WrapEnabled", "WrapMode" }, // TextEdit
// { "Zfar", "Far" }, // Camera3D
// { "Znear", "Near" }, // Camera3D
+ // { "Pressed", "ButtonPressed" }, // BaseButton - Will also rename the signal, skipping for now
{ "AsNormalmap", "AsNormalMap" }, // NoiseTexture
{ "BbcodeText", "Text" }, // RichTextLabel
{ "CaretBlinkSpeed", "CaretBlinkInterval" }, // TextEdit, LineEdit
@@ -1224,6 +1226,7 @@ static const char *csharp_properties_renames[][2] = {
{ "GravityVec", "GravityDirection" }, // Area2D
{ "HintTooltip", "TooltipText" }, // Control
{ "Hseparation", "HSeparation" }, // Theme
+ { "IconAlign", "IconAlignment" }, // Button
{ "IterationsPerSecond", "PhysicsTicksPerSecond" }, // Engine
{ "InvertEnable", "InvertEnabled" }, // Polygon2D
{ "MarginBottom", "OffsetBottom" }, // Control broke NinePatchRect, StyleBox
@@ -1366,6 +1369,18 @@ static const char *project_settings_renames[][2] = {
{ nullptr, nullptr },
};
+static const char *input_map_renames[][2] = {
+ { ",\"alt\":", ",\"alt_pressed\":" },
+ { ",\"shift\":", ",\"shift_pressed\":" },
+ { ",\"control\":", ",\"ctrl_pressed\":" },
+ { ",\"meta\":", ",\"meta_pressed\":" },
+ { ",\"scancode\":", ",\"keycode\":" },
+ { ",\"physical_scancode\":", ",\"physical_keycode\":" },
+ { ",\"doubleclick\":", ",\"double_click\":" },
+
+ { nullptr, nullptr },
+};
+
static const char *builtin_types_renames[][2] = {
{ "PoolByteArray", "PackedByteArray" },
{ "PoolColorArray", "PackedColorArray" },
@@ -1774,6 +1789,19 @@ static const char *color_renames[][2] = {
{ nullptr, nullptr },
};
+// Find "OS.set_property(x)", capturing x into $1.
+static String make_regex_gds_os_property_set(String name_set) {
+ return String("\\bOS\\.") + name_set + "\\s*\\((.*)\\)";
+}
+// Find "OS.property = x", capturing x into $1 or $2.
+static String make_regex_gds_os_property_assign(String name) {
+ return String("\\bOS\\.") + name + "\\s*=\\s*([^#]+)";
+}
+// Find "OS.property" OR "OS.get_property()" / "OS.is_property()".
+static String make_regex_gds_os_property_get(String name, String get) {
+ return String("\\bOS\\.(") + get + "_)?" + name + "(\\s*\\(\\s*\\))?";
+}
+
class ProjectConverter3To4::RegExContainer {
public:
// Custom GDScript.
@@ -1791,8 +1819,37 @@ public:
RegEx reg_join = RegEx("([\\(\\)a-zA-Z0-9_]+)\\.join\\(([^\n^\\)]+)\\)");
RegEx reg_image_lock = RegEx("([a-zA-Z0-9_\\.]+)\\.lock\\(\\)");
RegEx reg_image_unlock = RegEx("([a-zA-Z0-9_\\.]+)\\.unlock\\(\\)");
- RegEx reg_os_fullscreen = RegEx("OS.window_fullscreen[= ]+([^#^\n]+)");
RegEx reg_instantiate = RegEx("\\.instance\\(([^\\)]*)\\)");
+ // Simple OS properties with getters/setters.
+ RegEx reg_os_current_screen = RegEx("\\bOS\\.(set_|get_)?current_screen\\b");
+ RegEx reg_os_min_window_size = RegEx("\\bOS\\.(set_|get_)?min_window_size\\b");
+ RegEx reg_os_max_window_size = RegEx("\\bOS\\.(set_|get_)?max_window_size\\b");
+ RegEx reg_os_window_position = RegEx("\\bOS\\.(set_|get_)?window_position\\b");
+ RegEx reg_os_window_size = RegEx("\\bOS\\.(set_|get_)?window_size\\b");
+ RegEx reg_os_getset_screen_orient = RegEx("\\bOS\\.(s|g)et_screen_orientation\\b");
+ // OS property getters/setters for non trivial replacements.
+ RegEx reg_os_set_window_resizable = RegEx(make_regex_gds_os_property_set("set_window_resizable"));
+ RegEx reg_os_assign_window_resizable = RegEx(make_regex_gds_os_property_assign("window_resizable"));
+ RegEx reg_os_is_window_resizable = RegEx(make_regex_gds_os_property_get("window_resizable", "is"));
+ RegEx reg_os_set_fullscreen = RegEx(make_regex_gds_os_property_set("set_window_fullscreen"));
+ RegEx reg_os_assign_fullscreen = RegEx(make_regex_gds_os_property_assign("window_fullscreen"));
+ RegEx reg_os_is_fullscreen = RegEx(make_regex_gds_os_property_get("window_fullscreen", "is"));
+ RegEx reg_os_set_maximized = RegEx(make_regex_gds_os_property_set("set_window_maximized"));
+ RegEx reg_os_assign_maximized = RegEx(make_regex_gds_os_property_assign("window_maximized"));
+ RegEx reg_os_is_maximized = RegEx(make_regex_gds_os_property_get("window_maximized", "is"));
+ RegEx reg_os_set_minimized = RegEx(make_regex_gds_os_property_set("set_window_minimized"));
+ RegEx reg_os_assign_minimized = RegEx(make_regex_gds_os_property_assign("window_minimized"));
+ RegEx reg_os_is_minimized = RegEx(make_regex_gds_os_property_get("window_minimized", "is"));
+ RegEx reg_os_set_vsync = RegEx(make_regex_gds_os_property_set("set_use_vsync"));
+ RegEx reg_os_assign_vsync = RegEx(make_regex_gds_os_property_assign("vsync_enabled"));
+ RegEx reg_os_is_vsync = RegEx(make_regex_gds_os_property_get("vsync_enabled", "is"));
+ // OS properties specific cases & specific replacements.
+ RegEx reg_os_assign_screen_orient = RegEx("^(\\s*)OS\\.screen_orientation\\s*=\\s*([^#]+)"); // $1 - indent, $2 - value
+ RegEx reg_os_set_always_on_top = RegEx(make_regex_gds_os_property_set("set_window_always_on_top"));
+ RegEx reg_os_is_always_on_top = RegEx("\\bOS\\.is_window_always_on_top\\s*\\(.*\\)");
+ RegEx reg_os_set_borderless = RegEx(make_regex_gds_os_property_set("set_borderless_window"));
+ RegEx reg_os_get_borderless = RegEx("\\bOS\\.get_borderless_window\\s*\\(\\s*\\)");
+ RegEx reg_os_screen_orient_enum = RegEx("\\bOS\\.SCREEN_ORIENTATION_(\\w+)\\b"); // $1 - constant suffix
// GDScript keywords.
RegEx keyword_gdscript_tool = RegEx("^tool");
@@ -1839,6 +1896,7 @@ public:
LocalVector<RegEx *> enum_regexes;
LocalVector<RegEx *> gdscript_function_regexes;
LocalVector<RegEx *> project_settings_regexes;
+ LocalVector<RegEx *> input_map_regexes;
LocalVector<RegEx *> gdscript_properties_regexes;
LocalVector<RegEx *> gdscript_signals_regexes;
LocalVector<RegEx *> shaders_regexes;
@@ -1862,6 +1920,10 @@ public:
for (unsigned int current_index = 0; project_settings_renames[current_index][0]; current_index++) {
project_settings_regexes.push_back(memnew(RegEx(String("\\b") + project_settings_renames[current_index][0] + "\\b")));
}
+ // Input Map.
+ for (unsigned int current_index = 0; input_map_renames[current_index][0]; current_index++) {
+ input_map_regexes.push_back(memnew(RegEx(String("\\b") + input_map_renames[current_index][0] + "\\b")));
+ }
// GDScript properties.
for (unsigned int current_index = 0; gdscript_properties_renames[current_index][0]; current_index++) {
gdscript_properties_regexes.push_back(memnew(RegEx(String("\\b") + gdscript_properties_renames[current_index][0] + "\\b")));
@@ -1933,6 +1995,9 @@ public:
for (unsigned int i = 0; i < project_settings_regexes.size(); i++) {
memdelete(project_settings_regexes[i]);
}
+ for (unsigned int i = 0; i < input_map_regexes.size(); i++) {
+ memdelete(input_map_regexes[i]);
+ }
for (unsigned int i = 0; i < gdscript_properties_regexes.size(); i++) {
memdelete(gdscript_properties_regexes[i]);
}
@@ -2084,6 +2149,7 @@ int ProjectConverter3To4::convert() {
} else if (file_name.ends_with("project.godot")) {
rename_common(project_settings_renames, reg_container.project_settings_regexes, lines);
rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines);
+ rename_common(input_map_renames, reg_container.input_map_regexes, lines);
} else if (file_name.ends_with(".csproj")) {
// TODO
} else {
@@ -2249,6 +2315,7 @@ int ProjectConverter3To4::validate_conversion() {
} else if (file_name.ends_with("project.godot")) {
changed_elements.append_array(check_for_rename_common(project_settings_renames, reg_container.project_settings_regexes, lines));
changed_elements.append_array(check_for_rename_common(builtin_types_renames, reg_container.builtin_types_regexes, lines));
+ changed_elements.append_array(check_for_rename_common(input_map_renames, reg_container.input_map_regexes, lines));
} else if (file_name.ends_with(".csproj")) {
// TODO
} else {
@@ -2385,6 +2452,8 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_basic("audio/channel_disable_threshold_db", "audio/buses/channel_disable_threshold_db", project_settings_renames, reg_container.project_settings_regexes, "project setting");
+ valid = valid && test_conversion_basic("\"device\":-1,\"alt\":false,\"shift\":false,\"control\":false,\"meta\":false,\"doubleclick\":false,\"scancode\":0,\"physical_scancode\":16777254,\"script\":null", "\"device\":-1,\"alt_pressed\":false,\"shift_pressed\":false,\"ctrl_pressed\":false,\"meta_pressed\":false,\"double_click\":false,\"keycode\":0,\"physical_keycode\":16777254,\"script\":null", input_map_renames, reg_container.input_map_regexes, "input map");
+
valid = valid && test_conversion_basic("Transform", "Transform3D", builtin_types_renames, reg_container.builtin_types_regexes, "builtin type");
// Custom Renames.
@@ -2402,8 +2471,41 @@ bool ProjectConverter3To4::test_conversion(RegExContainer &reg_container) {
valid = valid && test_conversion_with_regex("[Master]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
valid = valid && test_conversion_with_regex("[MasterSync]", "The master and mastersync rpc behavior is not officially supported anymore. Try using another keyword or making custom logic using Multiplayer.GetRemoteSenderId()\n[RPC(CallLocal = true)]", &ProjectConverter3To4::rename_csharp_attributes, "custom rename csharp", reg_container);
- valid = valid && test_conversion_gdscript_builtin("OS.window_fullscreen = Settings.fullscreen", "if Settings.fullscreen:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
- valid = valid && test_conversion_gdscript_builtin("OS.get_window_safe_area()", "DisplayServer.get_display_safe_area()", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.window_resizable: pass", "\tif (not get_window().unresizable): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_resizable(): pass", "\tif (not get_window().unresizable): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_resizable(Settings.resizable)", "\tget_window().unresizable = not (Settings.resizable)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.window_resizable = Settings.resizable", "\tget_window().unresizable = not (Settings.resizable)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.window_fullscreen: pass", "\tif ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN)): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_fullscreen(): pass", "\tif ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN)): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_fullscreen(Settings.fullscreen)", "\tget_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (Settings.fullscreen) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.window_fullscreen = Settings.fullscreen", "\tget_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (Settings.fullscreen) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.window_maximized: pass", "\tif (get_window().mode == Window.MODE_MAXIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_maximized(): pass", "\tif (get_window().mode == Window.MODE_MAXIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_maximized(Settings.maximized)", "\tget_window().mode = Window.MODE_MAXIMIZED if (Settings.maximized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.window_maximized = Settings.maximized", "\tget_window().mode = Window.MODE_MAXIMIZED if (Settings.maximized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.window_minimized: pass", "\tif (get_window().mode == Window.MODE_MINIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_minimized(): pass", "\tif (get_window().mode == Window.MODE_MINIMIZED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_minimized(Settings.minimized)", "\tget_window().mode = Window.MODE_MINIMIZED if (Settings.minimized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.window_minimized = Settings.minimized", "\tget_window().mode = Window.MODE_MINIMIZED if (Settings.minimized) else Window.MODE_WINDOWED", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.vsync_enabled: pass", "\tif (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.is_vsync_enabled(): pass", "\tif (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED): pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.set_use_vsync(Settings.vsync)", "\tDisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (Settings.vsync) else DisplayServer.VSYNC_DISABLED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.vsync_enabled = Settings.vsync", "\tDisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (Settings.vsync) else DisplayServer.VSYNC_DISABLED)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.screen_orientation = OS.SCREEN_ORIENTATION_VERTICAL: pass", "\tif DisplayServer.screen_get_orientation() = DisplayServer.SCREEN_VERTICAL: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.get_screen_orientation() = OS.SCREEN_ORIENTATION_LANDSCAPE: pass", "\tif DisplayServer.screen_get_orientation() = DisplayServer.SCREEN_LANDSCAPE: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.set_screen_orientation(Settings.orient)", "\tDisplayServer.screen_set_orientation(Settings.orient)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.screen_orientation = Settings.orient", "\tDisplayServer.screen_set_orientation(Settings.orient)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.is_window_always_on_top(): pass", "\tif get_window().always_on_top: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.set_window_always_on_top(Settings.alwaystop)", "\tget_window().always_on_top = (Settings.alwaystop)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+
+ valid = valid && test_conversion_gdscript_builtin("\tif OS.get_borderless_window(): pass", "\tif get_window().borderless: pass", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
+ valid = valid && test_conversion_gdscript_builtin("\tOS.set_borderless_window(Settings.borderless)", "\tget_window().borderless = (Settings.borderless)", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tvar aa = roman(r.move_and_slide( a, b, c, d, e, f )) # Roman", "\tr.set_velocity(a)\n\tr.set_up_direction(b)\n\tr.set_floor_stop_on_slope_enabled(c)\n\tr.set_max_slides(d)\n\tr.set_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tr.move_and_slide()\n\tvar aa = roman(r.velocity) # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
valid = valid && test_conversion_gdscript_builtin("\tmove_and_slide( a, b, c, d, e, f ) # Roman", "\tset_velocity(a)\n\tset_up_direction(b)\n\tset_floor_stop_on_slope_enabled(c)\n\tset_max_slides(d)\n\tset_floor_max_angle(e)\n\t# TODOConverter40 infinite_inertia were removed in Godot 4.0 - previous value `f`\n\tmove_and_slide() # Roman", &ProjectConverter3To4::rename_gdscript_functions, "custom rename", reg_container, false);
@@ -2740,6 +2842,7 @@ bool ProjectConverter3To4::test_array_names() {
valid = valid && test_single_array(shaders_renames, true);
valid = valid && test_single_array(gdscript_signals_renames);
valid = valid && test_single_array(project_settings_renames);
+ valid = valid && test_single_array(input_map_renames);
valid = valid && test_single_array(builtin_types_renames);
valid = valid && test_single_array(color_renames);
@@ -3166,9 +3269,96 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
line = reg_container.reg_setget_get.sub(line, "var $1$2: get = $3", true);
}
- // OS.window_fullscreen = a -> if a: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN) else: DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)
+ if (line.contains("window_resizable")) {
+ // OS.set_window_resizable(a) -> get_window().unresizable = not (a)
+ line = reg_container.reg_os_set_window_resizable.sub(line, "get_window().unresizable = not ($1)", true);
+ // OS.window_resizable = a -> same
+ line = reg_container.reg_os_assign_window_resizable.sub(line, "get_window().unresizable = not ($1)", true);
+ // OS.[is_]window_resizable() -> (not get_window().unresizable)
+ line = reg_container.reg_os_is_window_resizable.sub(line, "(not get_window().unresizable)", true);
+ }
+
if (line.contains("window_fullscreen")) {
- line = reg_container.reg_os_fullscreen.sub(line, "if $1:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_FULLSCREEN)\nelse:\n\tDisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED)", true);
+ // OS.window_fullscreen(a) -> get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if (a) else Window.MODE_WINDOWED
+ line = reg_container.reg_os_set_fullscreen.sub(line, "get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if ($1) else Window.MODE_WINDOWED", true);
+ // window_fullscreen = a -> same
+ line = reg_container.reg_os_assign_fullscreen.sub(line, "get_window().mode = Window.MODE_EXCLUSIVE_FULLSCREEN if ($1) else Window.MODE_WINDOWED", true);
+ // OS.[is_]window_fullscreen() -> ((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN))
+ line = reg_container.reg_os_is_fullscreen.sub(line, "((get_window().mode == Window.MODE_EXCLUSIVE_FULLSCREEN) or (get_window().mode == Window.MODE_FULLSCREEN))", true);
+ }
+
+ if (line.contains("window_maximized")) {
+ // OS.window_maximized(a) -> get_window().mode = Window.MODE_MAXIMIZED if (a) else Window.MODE_WINDOWED
+ line = reg_container.reg_os_set_maximized.sub(line, "get_window().mode = Window.MODE_MAXIMIZED if ($1) else Window.MODE_WINDOWED", true);
+ // window_maximized = a -> same
+ line = reg_container.reg_os_assign_maximized.sub(line, "get_window().mode = Window.MODE_MAXIMIZED if ($1) else Window.MODE_WINDOWED", true);
+ // OS.[is_]window_maximized() -> (get_window().mode == Window.MODE_MAXIMIZED)
+ line = reg_container.reg_os_is_maximized.sub(line, "(get_window().mode == Window.MODE_MAXIMIZED)", true);
+ }
+
+ if (line.contains("window_minimized")) {
+ // OS.window_minimized(a) -> get_window().mode = Window.MODE_MINIMIZED if (a) else Window.MODE_WINDOWED
+ line = reg_container.reg_os_set_minimized.sub(line, "get_window().mode = Window.MODE_MINIMIZED if ($1) else Window.MODE_WINDOWED", true);
+ // window_minimized = a -> same
+ line = reg_container.reg_os_assign_minimized.sub(line, "get_window().mode = Window.MODE_MINIMIZED if ($1) else Window.MODE_WINDOWED", true);
+ // OS.[is_]window_minimized() -> (get_window().mode == Window.MODE_MINIMIZED)
+ line = reg_container.reg_os_is_minimized.sub(line, "(get_window().mode == Window.MODE_MINIMIZED)", true);
+ }
+
+ if (line.contains("set_use_vsync")) {
+ // OS.set_use_vsync(a) -> get_window().window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (a) else DisplayServer.VSYNC_DISABLED)
+ line = reg_container.reg_os_set_vsync.sub(line, "DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if ($1) else DisplayServer.VSYNC_DISABLED)", true);
+ }
+ if (line.contains("vsync_enabled")) {
+ // vsync_enabled = a -> get_window().window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if (a) else DisplayServer.VSYNC_DISABLED)
+ line = reg_container.reg_os_assign_vsync.sub(line, "DisplayServer.window_set_vsync_mode(DisplayServer.VSYNC_ENABLED if ($1) else DisplayServer.VSYNC_DISABLED)", true);
+ // OS.[is_]vsync_enabled() -> (DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED)
+ line = reg_container.reg_os_is_vsync.sub(line, "(DisplayServer.window_get_vsync_mode() != DisplayServer.VSYNC_DISABLED)", true);
+ }
+
+ if (line.contains("OS.screen_orientation")) { // keep "OS." at start
+ // OS.screen_orientation = a -> DisplayServer.screen_set_orientation(a)
+ line = reg_container.reg_os_assign_screen_orient.sub(line, "$1DisplayServer.screen_set_orientation($2)", true); // assignment
+ line = line.replace("OS.screen_orientation", "DisplayServer.screen_get_orientation()"); // value access
+ }
+
+ if (line.contains("_window_always_on_top")) {
+ // OS.set_window_always_on_top(a) -> get_window().always_on_top = (a)
+ line = reg_container.reg_os_set_always_on_top.sub(line, "get_window().always_on_top = ($1)", true);
+ // OS.is_window_always_on_top() -> get_window().always_on_top
+ line = reg_container.reg_os_is_always_on_top.sub(line, "get_window().always_on_top", true);
+ }
+
+ if (line.contains("et_borderless_window")) {
+ // OS.set_borderless_window(a) -> get_window().borderless = (a)
+ line = reg_container.reg_os_set_borderless.sub(line, "get_window().borderless = ($1)", true);
+ // OS.get_borderless_window() -> get_window().borderless
+ line = reg_container.reg_os_get_borderless.sub(line, "get_window().borderless", true);
+ }
+
+ // OS.SCREEN_ORIENTATION_* -> DisplayServer.SCREEN_*
+ if (line.contains("OS.SCREEN_ORIENTATION_")) {
+ line = reg_container.reg_os_screen_orient_enum.sub(line, "DisplayServer.SCREEN_$1", true);
+ }
+
+ // OS -> Window simple replacements with optional set/get.
+ if (line.contains("current_screen")) {
+ line = reg_container.reg_os_current_screen.sub(line, "get_window().$1current_screen", true);
+ }
+ if (line.contains("min_window_size")) {
+ line = reg_container.reg_os_min_window_size.sub(line, "get_window().$1min_size", true);
+ }
+ if (line.contains("max_window_size")) {
+ line = reg_container.reg_os_max_window_size.sub(line, "get_window().$1max_size", true);
+ }
+ if (line.contains("window_position")) {
+ line = reg_container.reg_os_window_position.sub(line, "get_window().$1position", true);
+ }
+ if (line.contains("window_size")) {
+ line = reg_container.reg_os_window_size.sub(line, "get_window().$1size", true);
+ }
+ if (line.contains("et_screen_orientation")) {
+ line = reg_container.reg_os_getset_screen_orient.sub(line, "DisplayServer.screen_$1et_orientation", true);
}
// Instantiate
@@ -3669,11 +3859,85 @@ void ProjectConverter3To4::process_gdscript_line(String &line, const RegExContai
if (line.contains("OS.get_datetime")) {
line = line.replace("OS.get_datetime", "Time.get_datetime_dict_from_system");
}
+
+ // OS -> DisplayServer
+ if (line.contains("OS.get_display_cutouts")) {
+ line = line.replace("OS.get_display_cutouts", "DisplayServer.get_display_cutouts");
+ }
+ if (line.contains("OS.get_screen_count")) {
+ line = line.replace("OS.get_screen_count", "DisplayServer.get_screen_count");
+ }
+ if (line.contains("OS.get_screen_dpi")) {
+ line = line.replace("OS.get_screen_dpi", "DisplayServer.screen_get_dpi");
+ }
+ if (line.contains("OS.get_screen_max_scale")) {
+ line = line.replace("OS.get_screen_max_scale", "DisplayServer.screen_get_max_scale");
+ }
+ if (line.contains("OS.get_screen_position")) {
+ line = line.replace("OS.get_screen_position", "DisplayServer.screen_get_position");
+ }
+ if (line.contains("OS.get_screen_refresh_rate")) {
+ line = line.replace("OS.get_screen_refresh_rate", "DisplayServer.screen_get_refresh_rate");
+ }
+ if (line.contains("OS.get_screen_scale")) {
+ line = line.replace("OS.get_screen_scale", "DisplayServer.screen_get_scale");
+ }
+ if (line.contains("OS.get_screen_size")) {
+ line = line.replace("OS.get_screen_size", "DisplayServer.screen_get_size");
+ }
+ if (line.contains("OS.set_icon")) {
+ line = line.replace("OS.set_icon", "DisplayServer.set_icon");
+ }
+ if (line.contains("OS.set_native_icon")) {
+ line = line.replace("OS.set_native_icon", "DisplayServer.set_native_icon");
+ }
+
+ // OS -> Window
+ if (line.contains("OS.window_borderless")) {
+ line = line.replace("OS.window_borderless", "get_window().borderless");
+ }
+ if (line.contains("OS.get_real_window_size")) {
+ line = line.replace("OS.get_real_window_size", "get_window().get_size_with_decorations");
+ }
+ if (line.contains("OS.is_window_focused")) {
+ line = line.replace("OS.is_window_focused", "get_window().has_focus");
+ }
+ if (line.contains("OS.move_window_to_foreground")) {
+ line = line.replace("OS.move_window_to_foreground", "get_window().move_to_foreground");
+ }
+ if (line.contains("OS.request_attention")) {
+ line = line.replace("OS.request_attention", "get_window().request_attention");
+ }
+ if (line.contains("OS.set_window_title")) {
+ line = line.replace("OS.set_window_title", "get_window().set_title");
+ }
+
+ // get_tree().set_input_as_handled() -> get_viewport().set_input_as_handled()
+ if (line.contains("get_tree().set_input_as_handled()")) {
+ line = line.replace("get_tree().set_input_as_handled()", "get_viewport().set_input_as_handled()");
+ }
+
+ // Fix the simple case of using _unhandled_key_input
+ // func _unhandled_key_input(event: InputEventKey) -> _unhandled_key_input(event: InputEvent)
+ if (line.contains("_unhandled_key_input(event: InputEventKey)")) {
+ line = line.replace("_unhandled_key_input(event: InputEventKey)", "_unhandled_key_input(event: InputEvent)");
+ }
}
void ProjectConverter3To4::process_csharp_line(String &line, const RegExContainer &reg_container) {
line = line.replace("OS.GetWindowSafeArea()", "DisplayServer.ScreenGetUsableRect()");
+ // GetTree().SetInputAsHandled() -> GetViewport().SetInputAsHandled()
+ if (line.contains("GetTree().SetInputAsHandled()")) {
+ line = line.replace("GetTree().SetInputAsHandled()", "GetViewport().SetInputAsHandled()");
+ }
+
+ // Fix the simple case of using _UnhandledKeyInput
+ // func _UnhandledKeyInput(InputEventKey @event) -> _UnhandledKeyInput(InputEvent @event)
+ if (line.contains("_UnhandledKeyInput(InputEventKey @event)")) {
+ line = line.replace("_UnhandledKeyInput(InputEventKey @event)", "_UnhandledKeyInput(InputEvent @event)");
+ }
+
// -- Connect(,,,things) -> Connect(,Callable(,),things) Object
if (line.contains("Connect(")) {
int start = line.find("Connect(");
diff --git a/editor/project_settings_editor.cpp b/editor/project_settings_editor.cpp
index 69c21177f9..560549d249 100644
--- a/editor/project_settings_editor.cpp
+++ b/editor/project_settings_editor.cpp
@@ -114,7 +114,7 @@ void ProjectSettingsEditor::_add_setting() {
Variant value;
Variant::construct(Variant::Type(type_box->get_selected_id()), value, nullptr, 0, ce);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Project Setting"));
undo_redo->add_do_property(ps, setting, value);
undo_redo->add_undo_property(ps, setting, ps->has_setting(setting) ? ps->get(setting) : Variant());
@@ -134,7 +134,7 @@ void ProjectSettingsEditor::_delete_setting() {
Variant value = ps->get(setting);
int order = ps->get_order(setting);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Delete Item"));
undo_redo->add_do_method(ps, "clear", setting);
@@ -223,7 +223,7 @@ void ProjectSettingsEditor::_select_type(Variant::Type p_type) {
void ProjectSettingsEditor::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
const Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed()) {
@@ -345,7 +345,7 @@ void ProjectSettingsEditor::_action_added(const String &p_name) {
action["events"] = Array();
action["deadzone"] = 0.5f;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Input Action"));
undo_redo->add_do_method(ProjectSettings::get_singleton(), "set", name, action);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "clear", name);
@@ -361,7 +361,7 @@ void ProjectSettingsEditor::_action_edited(const String &p_name, const Dictionar
const String property_name = "input/" + p_name;
Dictionary old_val = GLOBAL_GET(property_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (old_val["deadzone"] != p_action["deadzone"]) {
// Deadzone Changed
undo_redo->create_action(TTR("Change Action deadzone"));
@@ -398,7 +398,7 @@ void ProjectSettingsEditor::_action_removed(const String &p_name) {
Dictionary old_val = GLOBAL_GET(property_name);
int order = ProjectSettings::get_singleton()->get_order(property_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Erase Input Action"));
undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", property_name);
undo_redo->add_undo_method(ProjectSettings::get_singleton(), "set", property_name, old_val);
@@ -421,7 +421,7 @@ void ProjectSettingsEditor::_action_renamed(const String &p_old_name, const Stri
int order = ProjectSettings::get_singleton()->get_order(old_property_name);
Dictionary action = GLOBAL_GET(old_property_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Input Action Event"));
// Do: clear old, set new
undo_redo->add_do_method(ProjectSettings::get_singleton(), "clear", old_property_name);
@@ -451,7 +451,7 @@ void ProjectSettingsEditor::_action_reordered(const String &p_action_name, const
HashMap<String, Variant> action_values;
ProjectSettings::get_singleton()->get_property_list(&props);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Update Input Action Order"));
for (const PropertyInfo &prop : props) {
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index b7b316df64..c3a99e96ef 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -583,7 +583,7 @@ void RenameDialog::rename() {
_iterate_scene(root_node, selected_node_list, &global_count);
if (!to_rename.is_empty()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Batch Rename"));
// Make sure to iterate reversed so that child nodes will find parents.
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index ac6bceaa55..733f140a56 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -231,7 +231,7 @@ void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, N
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Instantiate Scene(s)"));
for (int i = 0; i < instances.size(); i++) {
@@ -275,7 +275,7 @@ void SceneTreeDock::_replace_with_branch_scene(const String &p_file, Node *base)
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Replace with Branch Scene"));
Node *parent = base->get_parent();
@@ -540,7 +540,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Detach Script"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
undo_redo->add_do_method(EditorNode::get_singleton(), "push_item", (Script *)nullptr);
@@ -611,7 +611,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break; // one or more nodes can not be moved
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (selection.size() == 1) {
undo_redo->create_action(TTR("Move Node In Parent"));
}
@@ -661,7 +661,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
break;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Duplicate Node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
undo_redo->add_do_method(editor_selection, "clear");
@@ -778,7 +778,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Make node as Root"));
undo_redo->add_do_method(node->get_parent(), "remove_child", node);
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", node);
@@ -1023,7 +1023,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
Node *node = e->get();
if (node) {
Node *root = EditorNode::get_singleton()->get_edited_scene();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (!root) {
break;
}
@@ -1099,7 +1099,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
bool enabling = !first_selected->get()->is_unique_name_in_owner();
List<Node *> full_selection = editor_selection->get_full_selected_node_list();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (enabling) {
Vector<Node *> new_unique_nodes;
@@ -1226,7 +1226,7 @@ void SceneTreeDock::_property_selected(int p_idx) {
}
void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<Resource> p_res) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(TTR("Set %s"), p_property));
undo_redo->add_do_property(p_node, p_property, p_res);
undo_redo->add_undo_property(p_node, p_property, p_node->get(p_property));
@@ -1234,7 +1234,7 @@ void SceneTreeDock::_perform_property_drop(Node *p_node, String p_property, Ref<
}
void SceneTreeDock::add_root_node(Node *p_node) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action_for_history(TTR("New Scene Root"), editor_data->get_current_edited_scene_history_id());
undo_redo->add_do_method(EditorNode::get_singleton(), "set_edited_scene", p_node);
undo_redo->add_do_method(scene_tree, "update_tree");
@@ -1385,7 +1385,7 @@ void SceneTreeDock::_notification(int p_what) {
void SceneTreeDock::_node_replace_owner(Node *p_base, Node *p_node, Node *p_root, ReplaceOwnerMode p_mode) {
if (p_node->get_owner() == p_base && p_node != p_root) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
switch (p_mode) {
case MODE_BIDI: {
bool disable_unique = p_node->is_unique_name_in_owner() && p_root->get_node_or_null(UNIQUE_NODE_PREFIX + String(p_node->get_name())) != nullptr;
@@ -1619,7 +1619,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
Variant old_variant = p_base->get(propertyname);
Variant updated_variant = old_variant;
if (_check_node_path_recursive(p_base, updated_variant, p_renames)) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_property(p_base, propertyname, updated_variant);
undo_redo->add_undo_property(p_base, propertyname, old_variant);
p_base->set(propertyname, updated_variant);
@@ -1666,7 +1666,7 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
}
HashMap<Node *, NodePath>::Iterator found_path = p_renames->find(n);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (found_path) {
if (found_path->value == NodePath()) {
//will be erased
@@ -1833,7 +1833,7 @@ void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, V
// Sort by tree order, so re-adding is easy.
p_nodes.sort_custom<Node::Comparator>();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Reparent Node"), UndoRedo::MERGE_DISABLE, p_nodes[0]);
HashMap<Node *, NodePath> path_renames;
@@ -1968,7 +1968,7 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get());
for (Node *E : selected) {
Ref<Script> existing = E->get_script();
@@ -1994,7 +1994,7 @@ void SceneTreeDock::_shader_created(Ref<Shader> p_shader) {
Ref<Shader> existing = selected_shader_material->get_shader();
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Shader"));
undo_redo->add_do_method(selected_shader_material.ptr(), "set_shader", p_shader);
undo_redo->add_undo_method(selected_shader_material.ptr(), "set_shader", existing);
@@ -2063,7 +2063,7 @@ void SceneTreeDock::_delete_confirm(bool p_cut) {
EditorNode::get_singleton()->get_editor_plugins_over()->make_visible(false);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(p_cut ? TTR("Cut Node(s)") : TTR("Remove Node(s)"), UndoRedo::MERGE_DISABLE, remove_list.front()->get());
bool entire_scene = false;
@@ -2193,7 +2193,7 @@ void SceneTreeDock::_do_create(Node *p_parent) {
}
child->set_name(new_name);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action_for_history(TTR("Create Node"), editor_data->get_current_edited_scene_history_id());
if (edited_scene) {
@@ -2262,7 +2262,7 @@ void SceneTreeDock::_create() {
List<Node *> selection = editor_selection->get_selected_node_list();
ERR_FAIL_COND(selection.size() <= 0);
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
for (Node *n : selection) {
@@ -2396,7 +2396,7 @@ void SceneTreeDock::replace_node(Node *p_node, Node *p_by_node, bool p_keep_prop
}
//p_remove_old was added to support undo
if (p_remove_old) {
- EditorNode::get_undo_redo()->clear_history();
+ EditorUndoRedoManager::get_singleton()->clear_history();
}
newnode->set_name(newname);
@@ -2618,7 +2618,7 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
Object *obj = ClassDB::instantiate(scr->get_instance_base_type());
ERR_FAIL_NULL(obj);
@@ -3190,7 +3190,7 @@ List<Node *> SceneTreeDock::paste_nodes() {
owner = paste_parent;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Paste Node(s)"), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
ur->add_do_method(editor_selection, "clear");
diff --git a/editor/scene_tree_editor.cpp b/editor/scene_tree_editor.cpp
index b4f1ca5d0b..e0d748c478 100644
--- a/editor/scene_tree_editor.cpp
+++ b/editor/scene_tree_editor.cpp
@@ -68,7 +68,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
Node *n = get_node(np);
ERR_FAIL_COND(!n);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_id == BUTTON_SUBSCENE) {
if (n == get_scene_node()) {
if (n && n->get_scene_inherited_state().is_valid()) {
@@ -176,7 +176,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
void SceneTreeEditor::_toggle_visible(Node *p_node) {
if (p_node->has_method("is_visible") && p_node->has_method("set_visible")) {
bool v = bool(p_node->call("is_visible"));
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->add_do_method(p_node, "set_visible", !v);
undo_redo->add_undo_method(p_node, "set_visible", v);
}
@@ -1015,7 +1015,7 @@ void SceneTreeEditor::_renamed() {
which->set_metadata(0, n->get_path());
emit_signal(SNAME("node_renamed"));
} else {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Rename Node"));
emit_signal(SNAME("node_prerename"), n, new_name);
undo_redo->add_do_method(this, "_rename_node", n->get_instance_id(), new_name);
@@ -1373,10 +1373,6 @@ void SceneTreeEditor::_bind_methods() {
ClassDB::bind_method("_rename_node", &SceneTreeEditor::_rename_node);
ClassDB::bind_method("_test_update_tree", &SceneTreeEditor::_test_update_tree);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &SceneTreeEditor::get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &SceneTreeEditor::can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &SceneTreeEditor::drop_data_fw);
-
ClassDB::bind_method(D_METHOD("update_tree"), &SceneTreeEditor::update_tree);
ADD_SIGNAL(MethodInfo("node_selected"));
@@ -1419,7 +1415,7 @@ SceneTreeEditor::SceneTreeEditor(bool p_label, bool p_can_rename, bool p_can_ope
add_child(tree);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCD(tree, SceneTreeEditor);
if (p_can_rename) {
tree->set_allow_rmb_select(true);
tree->connect("item_mouse_selected", callable_mp(this, &SceneTreeEditor::_rmb_select));
diff --git a/editor/shader_globals_editor.cpp b/editor/shader_globals_editor.cpp
index 4ac0a5b672..800de431eb 100644
--- a/editor/shader_globals_editor.cpp
+++ b/editor/shader_globals_editor.cpp
@@ -70,7 +70,7 @@ class ShaderGlobalsEditorInterface : public Object {
GDCLASS(ShaderGlobalsEditorInterface, Object)
void _set_var(const StringName &p_name, const Variant &p_value, const Variant &p_prev_value) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set Shader Global Variable"));
undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_set", p_name, p_value);
@@ -399,7 +399,7 @@ void ShaderGlobalsEditor::_variable_added() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
Variant value = create_var(RS::GlobalShaderParameterType(variable_type->get_selected()));
@@ -418,7 +418,7 @@ void ShaderGlobalsEditor::_variable_added() {
}
void ShaderGlobalsEditor::_variable_deleted(const String &p_variable) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add Shader Global Parameter"));
undo_redo->add_do_method(RS::get_singleton(), "global_shader_parameter_remove", p_variable);
diff --git a/editor/translations/af.po b/editor/translations/af.po
index a705eb58fb..605b30cf67 100644
--- a/editor/translations/af.po
+++ b/editor/translations/af.po
@@ -11201,7 +11201,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/ar.po b/editor/translations/ar.po
index 204dd9a41b..327332ae18 100644
--- a/editor/translations/ar.po
+++ b/editor/translations/ar.po
@@ -70,13 +70,14 @@
# xX-Void-Xx <arandomdude75@gmail.com>, 2022.
# أحمد النور <ahmed2699@gmail.com>, 2022.
# Commander Gordon <gordoncommander@gmail.com>, 2022.
+# Abdulrahman <abdelrahman.ramadan686@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-10-29 23:55+0000\n"
-"Last-Translator: Commander Gordon <gordoncommander@gmail.com>\n"
+"PO-Revision-Date: 2022-12-21 07:01+0000\n"
+"Last-Translator: Abdulrahman <abdelrahman.ramadan686@gmail.com>\n"
"Language-Team: Arabic <https://hosted.weblate.org/projects/godot-engine/"
"godot/ar/>\n"
"Language: ar\n"
@@ -85,7 +86,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.14.2-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -877,7 +878,7 @@ msgstr "مطابقة المساÙات الطويلة"
#: core/project_settings.cpp
msgid "Compression Level"
-msgstr "ضغط المستوى"
+msgstr "مستوى الضغط"
#: core/project_settings.cpp
msgid "Window Log Size"
@@ -11177,7 +11178,7 @@ msgstr "نظر من الخلÙ"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [البوابات Ù…Ùعلة]"
@@ -28516,6 +28517,5 @@ msgid "Log Active Async Compiles Count"
msgstr ""
#: servers/visual_server.cpp
-#, fuzzy
msgid "Shader Cache Size (MB)"
-msgstr "غيّر حجم الكاميرا"
+msgstr "حجم ذاكرة التظليل المؤقتة (مب)"
diff --git a/editor/translations/az.po b/editor/translations/az.po
index b6b36d99e5..90dfffe257 100644
--- a/editor/translations/az.po
+++ b/editor/translations/az.po
@@ -10789,7 +10789,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/bg.po b/editor/translations/bg.po
index 262a6825a6..728ffabe29 100644
--- a/editor/translations/bg.po
+++ b/editor/translations/bg.po
@@ -10946,7 +10946,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/bn.po b/editor/translations/bn.po
index df79cd5d84..b601d6d668 100644
--- a/editor/translations/bn.po
+++ b/editor/translations/bn.po
@@ -13,13 +13,14 @@
# Hasibul Hasan <d1hasib@yahoo.com>, 2020.
# saitama <atik.wowspace@gmail.com>, 2022.
# Joysankar Majumdar <joymajumdar15828@gmail.com>, 2022.
+# Safuan <safuanhossain12616@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-06-29 10:04+0000\n"
-"Last-Translator: Joysankar Majumdar <joymajumdar15828@gmail.com>\n"
+"PO-Revision-Date: 2023-01-09 20:42+0000\n"
+"Last-Translator: Safuan <safuanhossain12616@gmail.com>\n"
"Language-Team: Bengali <https://hosted.weblate.org/projects/godot-engine/"
"godot/bn/>\n"
"Language: bn\n"
@@ -27,7 +28,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.13.1-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -50,14 +51,12 @@ msgid "V-Sync Enabled"
msgstr "ভি-সিঙà§à¦• সকà§à¦°à¦¿à¦¯à¦¼ করà§à¦¨"
#: core/bind/core_bind.cpp main/main.cpp
-#, fuzzy
msgid "V-Sync Via Compositor"
msgstr "কমà§à¦ªà¦¸à¦¿à¦Ÿà¦° দà§à¦¬à¦¾à¦°à¦¾ ভি-সিঙà§à¦• করা"
#: core/bind/core_bind.cpp main/main.cpp
-#, fuzzy
msgid "Delta Smoothing"
-msgstr "ডেলà§à¦Ÿà¦¾ মসৃণ করন"
+msgstr "ডেলà§à¦Ÿà¦¾ মসৃণ"
#: core/bind/core_bind.cpp
#, fuzzy
@@ -86,7 +85,6 @@ msgstr "পরà§à¦¦à¦¾ à¦à§‹à¦à¦•/ উপসà§à¦¥à¦¾à¦ªà¦¨"
#: core/bind/core_bind.cpp core/project_settings.cpp main/main.cpp
#: platform/uwp/os_uwp.cpp
-#, fuzzy
msgid "Window"
msgstr "উইনà§à¦¡à§‹"
@@ -156,9 +154,8 @@ msgid "Target FPS"
msgstr "লকà§à¦·à§à¦¯-à¦à¦«à¦ªà¦¿à¦à¦¸(ফà§à¦°à§‡à¦®-পà§à¦°à¦¤à¦¿-সেকেনà§à¦¡)"
#: core/bind/core_bind.cpp
-#, fuzzy
msgid "Time Scale"
-msgstr "টাইম-সà§à¦•à§‡à¦² নোড"
+msgstr "টাইম-সà§à¦•à§‡à¦²"
#: core/bind/core_bind.cpp main/main.cpp
#, fuzzy
@@ -11772,7 +11769,7 @@ msgstr "পরিপà§à¦°à§‡à¦•à§à¦·à¦¿à¦¤ (Perspective)"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/br.po b/editor/translations/br.po
index 0cfc29b4d1..41d6ac8ee8 100644
--- a/editor/translations/br.po
+++ b/editor/translations/br.po
@@ -10666,7 +10666,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/ca.po b/editor/translations/ca.po
index d3ced0a876..ab408a0d9f 100644
--- a/editor/translations/ca.po
+++ b/editor/translations/ca.po
@@ -11292,7 +11292,7 @@ msgstr "Perspectiva"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/cs.po b/editor/translations/cs.po
index 173d38c85c..ee5bb962be 100644
--- a/editor/translations/cs.po
+++ b/editor/translations/cs.po
@@ -32,13 +32,13 @@
# JoeMoos <josephmoose13@gmail.com>, 2022.
# Mirinek <mirek.nozicka77@gmail.com>, 2022.
# Lubomír Baloun <lubosbaloun@gmail.com>, 2022.
-# Ondřej Pavelka <flamekick97@gmail.com>, 2022.
+# Ondřej Pavelka <flamekick97@gmail.com>, 2022, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-12-12 09:46+0000\n"
+"PO-Revision-Date: 2023-01-06 09:58+0000\n"
"Last-Translator: Ondřej Pavelka <flamekick97@gmail.com>\n"
"Language-Team: Czech <https://hosted.weblate.org/projects/godot-engine/godot/"
"cs/>\n"
@@ -47,7 +47,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -251,9 +251,8 @@ msgstr "Data"
#: modules/gdscript/language_server/gdscript_language_server.cpp
#: modules/webrtc/webrtc_data_channel.h modules/websocket/websocket_macros.h
#: scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Network"
-msgstr "Síťový profiler"
+msgstr "Síť"
#: core/io/file_access_network.cpp
#, fuzzy
@@ -605,9 +604,8 @@ msgid "Application"
msgstr "Akce"
#: core/project_settings.cpp main/main.cpp
-#, fuzzy
msgid "Config"
-msgstr "Nastavení přichycení"
+msgstr "Konfigurace"
#: core/project_settings.cpp
#, fuzzy
@@ -1582,9 +1580,8 @@ msgid "Editors"
msgstr "Editory"
#: editor/animation_track_editor.cpp editor/editor_settings.cpp
-#, fuzzy
msgid "Confirm Insert Track"
-msgstr "Animace: Vložit stopu a klíÄ"
+msgstr "Potvrdit vložení stopy"
#. TRANSLATORS: %s will be replaced by a phrase describing the target of track.
#: editor/animation_track_editor.cpp
@@ -4547,17 +4544,16 @@ msgid "Version Control"
msgstr "Správa verzí"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
-#, fuzzy
msgid "Username"
-msgstr "Přejmenovat"
+msgstr "Uživatelské jméno"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "SSH Public Key Path"
-msgstr ""
+msgstr "Cesta k veÅ™ejnému klíÄi SSH"
#: editor/editor_node.cpp editor/plugins/version_control_editor_plugin.cpp
msgid "SSH Private Key Path"
-msgstr ""
+msgstr "Cesta k soukromému klíÄi SSH"
#: editor/editor_node.cpp
msgid "Dock Position"
@@ -5191,12 +5187,11 @@ msgstr "Ladicí program"
#: editor/editor_profiler.cpp
msgid "Profiler Frame History Size"
-msgstr ""
+msgstr "Velikost historie profilovacího rámce"
#: editor/editor_profiler.cpp
-#, fuzzy
msgid "Profiler Frame Max Functions"
-msgstr "Přejmenovat funkci"
+msgstr "Maximální poÄet funkcí profilovacího rámce"
#: editor/editor_properties.cpp
msgid "Edit Text:"
@@ -5723,82 +5718,78 @@ msgid "Show Members Overview"
msgstr "Zobrazit pÅ™ehled Älenů"
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Files"
-msgstr "Soubor"
+msgstr "Soubory"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Trim Trailing Whitespace On Save"
-msgstr "Osekat koncové mezery"
+msgstr "Osekat koncové mezery při uložení"
#: editor/editor_settings.cpp
msgid "Autosave Interval Secs"
-msgstr ""
+msgstr "Interval automatického ukládání v sekundách"
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
msgid "Restore Scripts On Load"
-msgstr ""
+msgstr "Obnovit skripty pÅ™i naÄtení"
#: editor/editor_settings.cpp
msgid "Auto Reload And Parse Scripts On Save"
-msgstr ""
+msgstr "Automaticky aktualizovat a parsovat skripty při uložení"
#: editor/editor_settings.cpp
msgid "Auto Reload Scripts On External Change"
-msgstr ""
+msgstr "Automaticky aktualizovat skripty při externí změně"
#: editor/editor_settings.cpp
msgid "Create Signal Callbacks"
-msgstr ""
+msgstr "Vytvořit callback signálu"
#: editor/editor_settings.cpp
msgid "Sort Members Outline Alphabetically"
-msgstr ""
+msgstr "SeÅ™adit pÅ™ehled Älenů abecednÄ›"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Cursor"
-msgstr ""
+msgstr "Kurzor"
#: editor/editor_settings.cpp
msgid "Scroll Past End Of File"
-msgstr ""
+msgstr "Skrolovat za konec souboru"
#: editor/editor_settings.cpp
msgid "Block Caret"
-msgstr ""
+msgstr "Blokovat stříšku"
#: editor/editor_settings.cpp
msgid "Caret Blink"
-msgstr ""
+msgstr "Blikání stříšky"
#: editor/editor_settings.cpp
msgid "Caret Blink Speed"
-msgstr ""
+msgstr "Rychlost blikání stříšky"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Right Click Moves Caret"
-msgstr "Pravý klik pro přidání bodu"
+msgstr "Pravý klik posune stříšku"
#: editor/editor_settings.cpp modules/gdscript/gdscript.cpp
#: modules/gdscript/gdscript_editor.cpp
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion"
-msgstr "Kopírovat výběr"
+msgstr "DokonÄování"
#: editor/editor_settings.cpp
msgid "Idle Parse Delay"
-msgstr ""
+msgstr "ZpoždÄ›ní parsování pÅ™i neÄinnosti"
#: editor/editor_settings.cpp
msgid "Auto Brace Complete"
-msgstr ""
+msgstr "Automatické doplnění závorky"
#: editor/editor_settings.cpp
msgid "Code Complete Delay"
-msgstr ""
+msgstr "ZpoždÄ›ní dokonÄení kódu"
#: editor/editor_settings.cpp
msgid "Put Callhint Tooltip Below Current Line"
@@ -5806,87 +5797,76 @@ msgstr ""
#: editor/editor_settings.cpp
msgid "Callhint Tooltip Offset"
-msgstr ""
+msgstr "Posunutí nápovědy"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Complete File Paths"
-msgstr "Kopírovat cestu k uzlu"
+msgstr "DokonÄit cestu k souboru"
#: editor/editor_settings.cpp modules/gdscript/gdscript_editor.cpp
-#, fuzzy
msgid "Add Type Hints"
-msgstr "Přidat typ"
+msgstr "Přidat nápovědy typů"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Use Single Quotes"
-msgstr "Nová dlaždice"
+msgstr "Používat jednoduché závorky"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Help Index"
-msgstr "Zobrazit pomocníky"
+msgstr "Zobrazit index nápovědy"
#: editor/editor_settings.cpp
msgid "Help Font Size"
-msgstr ""
+msgstr "Velikost fontu nápovědy"
#: editor/editor_settings.cpp
msgid "Help Source Font Size"
-msgstr ""
+msgstr "Velikost fontu zdroje nápovědy"
#: editor/editor_settings.cpp
msgid "Help Title Font Size"
-msgstr ""
+msgstr "Velikost fontu titulku nápovědy"
#: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
msgstr "Mřížková mapa"
#: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Pick Distance"
-msgstr "Vybrat vzdálenost:"
+msgstr "Výběrová vzdálenost"
#: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Preview Size"
-msgstr "Náhled"
+msgstr "Velikost náhledu"
#: editor/editor_settings.cpp
msgid "Primary Grid Color"
-msgstr ""
+msgstr "Primární barva mřížky"
#: editor/editor_settings.cpp
msgid "Secondary Grid Color"
-msgstr ""
+msgstr "Sekundární barva mřížky"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Selection Box Color"
-msgstr "Pouze výběr"
+msgstr "Barva výběrového pole"
#: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "3D Gizmos"
-msgstr "Gizma"
+msgstr "3D Rukojeti"
#: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Gizmo Colors"
-msgstr "Emisní barvy"
+msgstr "Barvy rukojetí"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Instanced"
-msgstr "Instance"
+msgstr "Instancováno"
#: editor/editor_settings.cpp modules/gltf/gltf_node.cpp
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Joint"
msgstr "Bod"
@@ -5897,12 +5877,11 @@ msgstr "Bod"
#: scene/resources/particles_material.cpp servers/physics_2d_server.cpp
#: servers/physics_server.cpp
msgid "Shape"
-msgstr ""
+msgstr "Tvar"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Primary Grid Steps"
-msgstr "Krok mřížky:"
+msgstr "Primární stupně mřížky"
#: editor/editor_settings.cpp
msgid "Grid Size"
@@ -5910,35 +5889,31 @@ msgstr "Velikost mřížky"
#: editor/editor_settings.cpp
msgid "Grid Division Level Max"
-msgstr ""
+msgstr "Maximální úroveň rozdělení mřížky"
#: editor/editor_settings.cpp
msgid "Grid Division Level Min"
-msgstr ""
+msgstr "Minimální úroveň rozdělení mřížky"
#: editor/editor_settings.cpp
msgid "Grid Division Level Bias"
-msgstr ""
+msgstr "Sklon úrovně rozdělení mřížky"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid XZ Plane"
-msgstr "Vykreslit GridMap"
+msgstr "Rovina XZ mřížky"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid XY Plane"
-msgstr "Vykreslit GridMap"
+msgstr "Rovina XY mřížky"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid YZ Plane"
-msgstr "Vykreslit GridMap"
+msgstr "Rovina YZ mřížky"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default FOV"
-msgstr "Výchozí"
+msgstr "Výchozí FOV"
#: editor/editor_settings.cpp
#, fuzzy
@@ -5946,222 +5921,194 @@ msgid "Default Z Near"
msgstr "Výchozí motiv"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default Z Far"
-msgstr "Výchozí"
+msgstr "Výchozí Z limit dálky"
#: editor/editor_settings.cpp
msgid "Lightmap Baking Number Of CPU Threads"
-msgstr ""
+msgstr "PoÄet CPU vláken pÅ™i zapékání svÄ›telných map"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Navigation Scheme"
-msgstr "NavigaÄní režim"
+msgstr "Schéma navigace"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Invert Y Axis"
-msgstr "Editovat osu Y"
+msgstr "Invertovat osu Y"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Invert X Axis"
-msgstr "Editovat osu X"
+msgstr "Invertovat osu X"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Zoom Style"
-msgstr "Zmenšit"
+msgstr "Styl přiblížení"
#: editor/editor_settings.cpp
msgid "Emulate Numpad"
-msgstr ""
+msgstr "Emulovat numerickou klávesnici"
#: editor/editor_settings.cpp
msgid "Emulate 3 Button Mouse"
-msgstr ""
+msgstr "Emulovat třítlaÄítkovou myÅ¡"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Orbit Modifier"
-msgstr "Seřadit podle první změny"
+msgstr "Modifikátor orbitu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Pan Modifier"
-msgstr "Režim posouvání"
+msgstr "Modifikátor posouvání"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Zoom Modifier"
-msgstr "Úpravy"
+msgstr "Modifikátor přiblížení"
#: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Warped Mouse Panning"
-msgstr ""
+msgstr "Zkreslené posouvání myši"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Navigation Feel"
-msgstr "NavigaÄní režim"
+msgstr "Pocit navigace"
#: editor/editor_settings.cpp
msgid "Orbit Sensitivity"
-msgstr ""
+msgstr "Citlivost orbitu"
#: editor/editor_settings.cpp
msgid "Orbit Inertia"
-msgstr ""
+msgstr "SetrvaÄnost orbitu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Translation Inertia"
-msgstr "Překlady"
+msgstr "SetrvaÄnost pÅ™ekladu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Zoom Inertia"
-msgstr "Zvětšit"
+msgstr "SetrvaÄnost pÅ™iblížení"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook"
-msgstr "Volný pohled nahoru"
+msgstr "Volný pohled"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Navigation Scheme"
-msgstr "Vytvořit Navigation Mesh"
+msgstr "NavigaÄní schéma volného pohledu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Sensitivity"
-msgstr "Volný pohled doleva"
+msgstr "Senzitivita volného pohledu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Inertia"
-msgstr "Volný pohled doleva"
+msgstr "SetrvaÄnost volného pohledu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Base Speed"
-msgstr "Rychlost volného pohledu"
+msgstr "Základní rychlost volného pohledu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Activation Modifier"
-msgstr "Zpomalení volného pohledu"
+msgstr "Modifikátor aktivace volného pohledu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Speed Zoom Link"
-msgstr "Rychlost volného pohledu"
+msgstr "Link rychlo přiblížení volného pohledu"
#: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Grid Color"
-msgstr "Vyberte barvu"
+msgstr "Barva mřížky"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Guides Color"
-msgstr "Vyberte barvu"
+msgstr "Barva vodítek"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Smart Snapping Line Color"
-msgstr "Chytré přichcování"
+msgstr "Barva linky chytrého přichycování"
#: editor/editor_settings.cpp
msgid "Bone Width"
-msgstr ""
+msgstr "Šířka kosti"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Color 1"
-msgstr "Odstranit položky třídy"
+msgstr "Barva kosti 1"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Color 2"
-msgstr "Odstranit položky třídy"
+msgstr "Barva kosti 2"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Selected Color"
-msgstr "Konfigurace vybraného profilu:"
+msgstr "Barva vybrané kosti"
#: editor/editor_settings.cpp
msgid "Bone IK Color"
-msgstr ""
+msgstr "Barva IK kosti"
#: editor/editor_settings.cpp
msgid "Bone Outline Color"
-msgstr ""
+msgstr "Barva obrysu kosti"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Outline Size"
-msgstr "Velikost obrysu:"
+msgstr "Velikost obrysu kosti"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Viewport Border Color"
-msgstr ""
+msgstr "Barva ohraniÄení výřezu"
#: editor/editor_settings.cpp
+#, fuzzy
msgid "Constrain Editor View"
-msgstr ""
+msgstr "Omezit pohled editoru"
#: editor/editor_settings.cpp
msgid "Simple Panning"
-msgstr ""
+msgstr "Jednoduché posouvání"
#: editor/editor_settings.cpp
msgid "Scroll To Pan"
-msgstr ""
+msgstr "Skrollovat pro posun"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Pan Speed"
-msgstr "Rychlost:"
+msgstr "Rychlost posunu"
#: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Poly Editor"
-msgstr "Polygon 2D UV Editor"
+msgstr "Editor polygonů"
#: editor/editor_settings.cpp
msgid "Point Grab Radius"
-msgstr ""
+msgstr "Dosah pro uchopení bodu"
#: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Show Previous Outline"
-msgstr "Předchozí rovina"
+msgstr "Zobrazit předchozí obrys"
#: editor/editor_settings.cpp editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Autorename Animation Tracks"
-msgstr "Přejmenovat animaci"
+msgstr "Automaticky pÅ™ejmenovat animaÄní stopy"
#: editor/editor_settings.cpp
msgid "Default Create Bezier Tracks"
-msgstr ""
+msgstr "Výchozí vytváření beziérových stop"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default Create Reset Tracks"
-msgstr "Vytvořit RESET stopu/stopy"
+msgstr "Výchozí vytváření resetovacích stop"
#: editor/editor_settings.cpp
msgid "Onion Layers Past Color"
-msgstr ""
+msgstr "Barva cibulových vrstev minulosti"
#: editor/editor_settings.cpp
msgid "Onion Layers Future Color"
-msgstr ""
+msgstr "Barva cibulových vrstev budoucnosti"
#: editor/editor_settings.cpp
msgid "Visual Editors"
@@ -6169,11 +6116,11 @@ msgstr "Vizuální editory"
#: editor/editor_settings.cpp
msgid "Minimap Opacity"
-msgstr ""
+msgstr "Průhlednost minimapy"
#: editor/editor_settings.cpp
msgid "Window Placement"
-msgstr ""
+msgstr "Umístění okna"
#: editor/editor_settings.cpp scene/2d/back_buffer_copy.cpp scene/2d/sprite.cpp
#: scene/2d/visibility_notifier_2d.cpp scene/3d/sprite_3d.cpp
@@ -6183,49 +6130,42 @@ msgid "Rect"
msgstr "Celý obdélník"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Rect Custom Position"
-msgstr "Nastavit bod z křivky"
+msgstr "Vlastní pozice okna"
#: editor/editor_settings.cpp platform/android/export/export_plugin.cpp
msgid "Screen"
msgstr ""
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Auto Save"
-msgstr "Automatický řez"
+msgstr "Automatické ukládání"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Save Before Running"
-msgstr "Uložit scénu před spuštěním..."
+msgstr "Uložit před spuštěním"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Font Size"
-msgstr "Pohled zepředu"
+msgstr "Velikost fontu"
#: editor/editor_settings.cpp
#: modules/gdscript/language_server/gdscript_language_server.cpp
-#, fuzzy
msgid "Remote Host"
-msgstr "Vzdálený "
+msgstr "Vzdálený host"
#: editor/editor_settings.cpp
#: modules/gdscript/language_server/gdscript_language_server.cpp
-#, fuzzy
msgid "Remote Port"
-msgstr "Odstranit bod"
+msgstr "Vzdálený port"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Editor SSL Certificates"
-msgstr "Nastavení editoru"
+msgstr "SSL certifikáty editoru"
#: editor/editor_settings.cpp
msgid "HTTP Proxy"
-msgstr ""
+msgstr "HTTP Proxy"
#: editor/editor_settings.cpp
msgid "Host"
@@ -6244,9 +6184,8 @@ msgstr "Správce projektů"
#. TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects.
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Sorting Order"
-msgstr "Přejmenování složky:"
+msgstr "Seřadit podle"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Symbol Color"
@@ -6322,11 +6261,11 @@ msgstr "Číslo řádku:"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Caret Color"
-msgstr "Barva vynechávky"
+msgstr "Barva stříšky"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Caret Background Color"
-msgstr "Barva pozadí vynechávky"
+msgstr "Barva pozadí stříšky"
#: editor/editor_settings.cpp
msgid "Text Selected Color"
@@ -7309,9 +7248,8 @@ msgid "Use Named Skins"
msgstr "Použít škálovací přichytávání"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "External Files"
-msgstr "Otevřít soubor"
+msgstr "Externí soubory"
#: editor/import/resource_importer_scene.cpp
msgid "Store In Subdir"
@@ -8293,7 +8231,7 @@ msgstr "Vynutit bílou modulaci"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Include Gizmos (3D)"
-msgstr "Zahrnout Gizmos (3D)"
+msgstr "Zahrnout rukojeti (3D)"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Pin AnimationPlayer"
@@ -8681,9 +8619,8 @@ msgid "Download Error"
msgstr "Chyba při stahování"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Available URLs"
-msgstr "Dostupné profily:"
+msgstr "Dostupné URL"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download for this asset is already in progress!"
@@ -8771,7 +8708,7 @@ msgstr "Kategorie:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Site:"
-msgstr "Web:"
+msgstr "Stránka:"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Support"
@@ -9346,7 +9283,7 @@ msgstr "Vytvořit kosti z uzlů"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Clear Custom Bones"
-msgstr "Vymazat kosti"
+msgstr "Vymazat vlastní kosti"
#. TRANSLATORS: Noun, name of the 2D/3D View menus.
#: editor/plugins/canvas_item_editor_plugin.cpp
@@ -9715,7 +9652,7 @@ msgstr "Pravý klik pro přidání bodu"
#: editor/plugins/gi_probe_editor_plugin.cpp
msgid "Bake GI Probe"
-msgstr "Zapéct GI probe"
+msgstr "Zapéct GI sondu"
#: editor/plugins/gradient_editor_plugin.cpp
msgid "Gradient Edited"
@@ -10338,7 +10275,7 @@ msgstr "Rozdělit segment (v křivce)"
#: editor/plugins/physical_bone_plugin.cpp
msgid "Move Joint"
-msgstr "Přesunout kloub"
+msgstr "Posunout bod"
#: editor/plugins/polygon_2d_editor_plugin.cpp
msgid ""
@@ -10885,14 +10822,12 @@ msgid "External"
msgstr "Externí"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Use External Editor"
-msgstr "Debugovat v externím editoru"
+msgstr "Používat externí editor"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Exec Path"
-msgstr "Exportovat cestu"
+msgstr "Cesta k spuštění"
#: editor/plugins/script_editor_plugin.cpp
msgid "Script Temperature Enabled"
@@ -10920,11 +10855,11 @@ msgstr "Seřadit skripty podle"
#: editor/plugins/script_editor_plugin.cpp
msgid "List Script Names As"
-msgstr "Zobrazit názvy seznamu skriptů jako"
+msgstr "Zobrazit seznam názvů skriptů jako"
#: editor/plugins/script_editor_plugin.cpp
msgid "Exec Flags"
-msgstr ""
+msgstr "Parametry spuštění"
#: editor/plugins/script_editor_plugin.cpp
msgid "Clear Recent Scripts"
@@ -11254,7 +11189,7 @@ msgstr "Perspektivní"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [aktivní portály]"
@@ -11462,35 +11397,35 @@ msgstr "Není k dispozici při použití vykreslovacího modulu GLES2."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
-msgstr "Volný pohled doleva"
+msgstr "Levý volný pohled"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Right"
-msgstr "Volný pohled doprava"
+msgstr "Pravý volný pohled"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Forward"
-msgstr "Volný pohled vpřed"
+msgstr "Přední volný pohled"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Backwards"
-msgstr "Volný pohled dozadu"
+msgstr "Zadní volný pohled"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Up"
-msgstr "Volný pohled nahoru"
+msgstr "Horní volný pohled"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Down"
-msgstr "Volný pohled dolů"
+msgstr "Dolní volný pohled"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Speed Modifier"
-msgstr "Rychlost volného pohledu"
+msgstr "Modifikátor rychlosti volného pohybu"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Slow Modifier"
-msgstr "Zpomalení volného pohledu"
+msgstr "Modifikátor zpomalení volného pohybu"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Toggle Camera Preview"
@@ -11756,16 +11691,15 @@ msgstr "Po"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Manipulator Gizmo Size"
-msgstr ""
+msgstr "Nastavení velikosti rukojeti"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Manipulator Gizmo Opacity"
-msgstr ""
+msgstr "Nastavení průhlednosti rukojeti"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Show Viewport Rotation Gizmo"
-msgstr "Uzamknout rotaci pohledu"
+msgstr "Zobrazit tlaÄítko rotace zobrazení"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unnamed Gizmo"
@@ -12748,55 +12682,46 @@ msgid "Clear Transform"
msgstr "Promazat transformaci"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Tile Map"
-msgstr "Nakreslit TileMap"
+msgstr "Mapa dlaždic"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Palette Min Width"
-msgstr ""
+msgstr "Minimální šířka palety"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Palette Item H Separation"
-msgstr "Nazvaný oddÄ›lovaÄ"
+msgstr "H oddělování paletových položek"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Show Tile Names"
-msgstr "Zobrazit všechny jazyky"
+msgstr "Zobrazit názvy dlaždic"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Show Tile Ids"
-msgstr "Zobrazit pravítka"
+msgstr "Zobrazit Id dlaždic"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Sort Tiles By Name"
-msgstr "Seřadit soubory"
+msgstr "Řadit dlaždice podle názvu"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Bucket Fill Preview"
-msgstr "Vyplnit barvou"
+msgstr "Náhled vyplnění kbelíkem"
#: editor/plugins/tile_map_editor_plugin.cpp
#: modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Editor Side"
-msgstr "Editor"
+msgstr "Strana editoru"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Display Grid"
-msgstr "Rentgen pohled"
+msgstr "Zobrazit mřížku"
#: editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Axis Color"
-msgstr "Vyberte barvu"
+msgstr "Barva osy"
#: editor/plugins/tile_set_editor_plugin.cpp
msgid "Add Texture(s) to TileSet."
@@ -13331,7 +13256,7 @@ msgstr "Resetovat"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Version Control System"
-msgstr "Verzování (VCS)"
+msgstr "Systémy pro správu verzí"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Initialize"
@@ -13344,11 +13269,11 @@ msgstr "Odstranit bod"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Select SSH public key path"
-msgstr ""
+msgstr "Vybrat cestu k veÅ™ejnému klíÄi SSH"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "Select SSH private key path"
-msgstr ""
+msgstr "Vybrat cestu k veÅ™ejnému klíÄi SSH"
#: editor/plugins/version_control_editor_plugin.cpp
msgid "SSH Passphrase"
@@ -16148,15 +16073,15 @@ msgstr "Filtrovat dlaždice"
#: editor/script_editor_debugger.cpp
msgid "Auto Switch To Remote Scene Tree"
-msgstr ""
+msgstr "Automaticky přepnout na vzdálený strom scén"
#: editor/script_editor_debugger.cpp
msgid "Remote Scene Tree Refresh Interval"
-msgstr ""
+msgstr "Interval obnovení vzdáleného stromu scén"
#: editor/script_editor_debugger.cpp
msgid "Remote Inspect Refresh Interval"
-msgstr ""
+msgstr "Interval obnovení vzdálené kontroly"
#: editor/script_editor_debugger.cpp
msgid "Network Profiler"
@@ -16254,7 +16179,7 @@ msgstr "Změnit rádius světla"
#: editor/spatial_editor_gizmos.cpp
msgid "Stream Player 3D"
-msgstr ""
+msgstr "Stream Player 3D"
#: editor/spatial_editor_gizmos.cpp
msgid "Change AudioStreamPlayer3D Emission Angle"
@@ -16264,7 +16189,7 @@ msgstr "Změnit úhel vysílání uzlu AudioStreamPlayer3D"
#: platform/osx/export/export.cpp
#: scene/resources/default_theme/default_theme.cpp
msgid "Camera"
-msgstr ""
+msgstr "Kamera"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Camera FOV"
@@ -16276,7 +16201,7 @@ msgstr "Změnit velikost kamery"
#: editor/spatial_editor_gizmos.cpp
msgid "Visibility Notifier"
-msgstr ""
+msgstr "Oznamovatel viditelnosti"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Notifier AABB"
@@ -16287,23 +16212,20 @@ msgid "Change Particles AABB"
msgstr "ZmÄ›nit Äástice AABB"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Reflection Probe"
-msgstr "Vybrat vlastnost"
+msgstr "Reflexní sonda"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Probe Extents"
msgstr "Změnit rozsahy Probe"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "GI Probe"
-msgstr "Zapéct GI probe"
+msgstr "GI Sonda"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Baked Indirect Light"
-msgstr "Nepřímé osvětlení"
+msgstr "ZapeÄené nepřímé osvÄ›tlení"
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
msgid "Change Sphere Shape Radius"
@@ -16334,40 +16256,36 @@ msgid "Change Ray Shape Length"
msgstr "Změnit délku Ray Shape"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Navigation Edge"
-msgstr "NavigaÄní režim"
+msgstr "Hrana navigace"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Navigation Edge Disabled"
-msgstr "NavigaÄní režim"
+msgstr "Hrana navigace vypnuta"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Navigation Solid"
-msgstr "NavigaÄní režim"
+msgstr "Pevná navigace"
#: editor/spatial_editor_gizmos.cpp
-#, fuzzy
msgid "Navigation Solid Disabled"
-msgstr "NavigaÄní režim"
+msgstr "Pevná navigace vypnuta"
#: editor/spatial_editor_gizmos.cpp
msgid "Joint Body A"
-msgstr ""
+msgstr "Kloubové tělo A"
#: editor/spatial_editor_gizmos.cpp
msgid "Joint Body B"
-msgstr ""
+msgstr "Kloubové tělo B"
#: editor/spatial_editor_gizmos.cpp
msgid "Room Edge"
-msgstr ""
+msgstr "Hrana místnosti"
#: editor/spatial_editor_gizmos.cpp
msgid "Room Overlap"
-msgstr ""
+msgstr "Překrytí místností"
#: editor/spatial_editor_gizmos.cpp
#, fuzzy
@@ -16375,17 +16293,16 @@ msgid "Set Room Point Position"
msgstr "Nastavit pozici bodu křivky"
#: editor/spatial_editor_gizmos.cpp scene/3d/portal.cpp
-#, fuzzy
msgid "Portal Margin"
-msgstr "Nastavit okraj"
+msgstr "Okraj portálu"
#: editor/spatial_editor_gizmos.cpp
msgid "Portal Edge"
-msgstr ""
+msgstr "Hrana portálu"
#: editor/spatial_editor_gizmos.cpp
msgid "Portal Arrow"
-msgstr ""
+msgstr "Šipka portálu"
#: editor/spatial_editor_gizmos.cpp
#, fuzzy
@@ -16403,9 +16320,8 @@ msgstr "Jít zpět"
#: editor/spatial_editor_gizmos.cpp scene/2d/light_occluder_2d.cpp
#: scene/2d/tile_map.cpp
-#, fuzzy
msgid "Occluder"
-msgstr "Režim okluze"
+msgstr "Okluzor"
#: editor/spatial_editor_gizmos.cpp
#, fuzzy
@@ -16849,7 +16765,7 @@ msgstr ""
#: modules/csg/csg_gizmos.cpp
msgid "CSG"
-msgstr ""
+msgstr "CSG"
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
@@ -17215,18 +17131,16 @@ msgid "Object can't provide a length."
msgstr "Objekt nemůže poskytnout délku."
#: modules/gdscript/language_server/gdscript_language_server.cpp
-#, fuzzy
msgid "Language Server"
-msgstr "Jazyk:"
+msgstr "Jazykový server"
#: modules/gdscript/language_server/gdscript_language_server.cpp
-#, fuzzy
msgid "Enable Smart Resolve"
-msgstr "Nelze vyřešit"
+msgstr "Povolit funkci chytrého řešení"
#: modules/gdscript/language_server/gdscript_language_server.cpp
msgid "Show Native Symbols In Editor"
-msgstr ""
+msgstr "Zobrazení nativních symbolů v editoru"
#: modules/gdscript/language_server/gdscript_language_server.cpp
msgid "Use Thread"
@@ -17398,9 +17312,8 @@ msgid "Children"
msgstr "Upravitelní potomci"
#: modules/gltf/gltf_skeleton.cpp modules/gltf/gltf_skin.cpp
-#, fuzzy
msgid "Joints"
-msgstr "Bod"
+msgstr "Body"
#: modules/gltf/gltf_skeleton.cpp modules/gltf/gltf_skin.cpp
msgid "Roots"
@@ -17521,7 +17434,7 @@ msgstr ""
#: modules/gltf/gltf_state.cpp
msgid "Cameras"
-msgstr ""
+msgstr "Kamery"
#: modules/gltf/gltf_state.cpp servers/visual_server.cpp
#, fuzzy
@@ -17729,7 +17642,7 @@ msgstr "Nastavení GridMap"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Pick Distance:"
-msgstr "Vybrat vzdálenost:"
+msgstr "Výběrová vzdálenost:"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Filter meshes"
@@ -18793,7 +18706,7 @@ msgstr "Prioritní mód"
#: modules/webrtc/webrtc_data_channel.h
msgid "WebRTC"
-msgstr ""
+msgstr "WebRTC"
#: modules/webrtc/webrtc_data_channel.h
msgid "Max Channel In Buffer (KB)"
@@ -18801,11 +18714,11 @@ msgstr ""
#: modules/websocket/websocket_client.cpp
msgid "Verify SSL"
-msgstr ""
+msgstr "Ověřit SSL"
#: modules/websocket/websocket_client.cpp
msgid "Trusted SSL Certificate"
-msgstr ""
+msgstr "Důvěryhodný certifikát SSL"
#: modules/websocket/websocket_macros.h
#, fuzzy
@@ -18844,7 +18757,7 @@ msgstr "Fyzická Klávesa"
#: modules/websocket/websocket_server.cpp platform/javascript/export/export.cpp
msgid "SSL Certificate"
-msgstr ""
+msgstr "Certifikát SSL"
#: modules/websocket/websocket_server.cpp
#, fuzzy
@@ -18896,28 +18809,27 @@ msgstr "Chytré přichcování"
#: platform/android/export/export.cpp
msgid "Android SDK Path"
-msgstr ""
+msgstr "Cesta k Android SDK"
#: platform/android/export/export.cpp
-#, fuzzy
msgid "Debug Keystore"
-msgstr "Ladicí program"
+msgstr "Ladění Keystore"
#: platform/android/export/export.cpp
msgid "Debug Keystore User"
-msgstr ""
+msgstr "Uživatel ladění Keystore"
#: platform/android/export/export.cpp
msgid "Debug Keystore Pass"
-msgstr ""
+msgstr "Průchod ladění Keystore"
#: platform/android/export/export.cpp
msgid "Force System User"
-msgstr ""
+msgstr "Vynutit systémového uživatele"
#: platform/android/export/export.cpp
msgid "Shutdown ADB On Exit"
-msgstr ""
+msgstr "Vypnout ADB pÅ™i ukonÄení"
#: platform/android/export/export_plugin.cpp
msgid "Launcher Icons"
@@ -19000,7 +18912,7 @@ msgstr "Ladicí program"
#: platform/android/export/export_plugin.cpp platform/uwp/export/export.cpp
msgid "Debug Password"
-msgstr ""
+msgstr "Heslo ladění"
#: platform/android/export/export_plugin.cpp
#, fuzzy
@@ -19873,7 +19785,7 @@ msgstr "Chyba při spuštění serveru HTTP:"
#: platform/javascript/export/export.cpp
msgid "Web"
-msgstr ""
+msgstr "Web"
#: platform/javascript/export/export.cpp
msgid "HTTP Host"
@@ -19884,13 +19796,12 @@ msgid "HTTP Port"
msgstr ""
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Use SSL"
-msgstr "Použít přichycení"
+msgstr "Použít SSL"
#: platform/javascript/export/export.cpp
msgid "SSL Key"
-msgstr ""
+msgstr "KlÃ­Ä SSL"
#: platform/osx/export/codesign.cpp
msgid "Can't get filesystem access."
@@ -19952,9 +19863,8 @@ msgid "Invalid entitlements file."
msgstr "Neplatná přípona."
#: platform/osx/export/codesign.cpp
-#, fuzzy
msgid "Invalid executable file."
-msgstr "Neplatná přípona."
+msgstr "Neplatný spouštěcí soubor."
#: platform/osx/export/codesign.cpp
msgid "Can't resize signature load command."
@@ -20442,7 +20352,7 @@ msgstr ""
#: platform/osx/export/export.cpp
msgid "Force Builtin Codesign"
-msgstr ""
+msgstr "Vynutit vestavěný codesign"
#: platform/uwp/export/export.cpp
#, fuzzy
@@ -20580,6 +20490,8 @@ msgid ""
"Godot's Mono version does not support the UWP platform. Use the standard "
"build (no C# support) if you wish to target UWP."
msgstr ""
+"Mono verze Godotu nepodporuje platformu UWP. Použijte standartní build (bez "
+"podpory C#) pokud chcete použít platformu UWP."
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
@@ -20635,7 +20547,7 @@ msgstr "Neplatné rozměry obrázku uvítací obrazovky (měly by být 620x300).
#: platform/uwp/export/export.cpp
msgid "UWP"
-msgstr ""
+msgstr "UWP"
#: platform/uwp/export/export.cpp platform/windows/export/export.cpp
#, fuzzy
@@ -20644,12 +20556,11 @@ msgstr "Signál"
#: platform/uwp/export/export.cpp
msgid "Debug Certificate"
-msgstr ""
+msgstr "Certifikát ladění"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Debug Algorithm"
-msgstr "Ladicí program"
+msgstr "Algoritmus ladění"
#: platform/windows/export/export.cpp
#, fuzzy
@@ -21715,9 +21626,8 @@ msgid "Capping"
msgstr ""
#: scene/2d/line_2d.cpp
-#, fuzzy
msgid "Joint Mode"
-msgstr "Režim ikony"
+msgstr "Mód bodu"
#: scene/2d/line_2d.cpp
#, fuzzy
@@ -22659,9 +22569,8 @@ msgid "Light Data"
msgstr "S daty"
#: scene/3d/bone_attachment.cpp scene/3d/physics_body.cpp
-#, fuzzy
msgid "Bone Name"
-msgstr "Název uzlu:"
+msgstr "Název kosti"
#: scene/3d/camera.cpp
msgid "Keep Aspect"
@@ -23827,18 +23736,16 @@ msgid "Overlap Warning Threshold"
msgstr ""
#: scene/3d/room_manager.cpp
-#, fuzzy
msgid "Preview Camera"
-msgstr "Náhled"
+msgstr "Náhled kamery"
#: scene/3d/room_manager.cpp
msgid "Portal Depth Limit"
msgstr ""
#: scene/3d/room_manager.cpp
-#, fuzzy
msgid "Default Portal Margin"
-msgstr "Nastavit okraj"
+msgstr "Výchozí okraj portálu"
#: scene/3d/room_manager.cpp
#, fuzzy
@@ -23875,6 +23782,9 @@ msgid ""
"Room overlap detected, cameras may work incorrectly in overlapping area.\n"
"Check output log for details."
msgstr ""
+"Bylo detekováno překrytí místností, kamery nemusí fungovat správně v "
+"překryvajících oblastech.\n"
+"Podrobnosti najdete ve výstupním protokolu."
#: scene/3d/room_manager.cpp
msgid ""
@@ -24370,14 +24280,12 @@ msgid "Zero Y"
msgstr "Nula"
#: scene/animation/skeleton_ik.cpp
-#, fuzzy
msgid "Root Bone"
-msgstr "Název kořenového uzlu"
+msgstr "Kořenová kost"
#: scene/animation/skeleton_ik.cpp
-#, fuzzy
msgid "Tip Bone"
-msgstr "Kosti"
+msgstr "Å piÄková kost"
#: scene/animation/skeleton_ik.cpp
#, fuzzy
@@ -24904,7 +24812,7 @@ msgstr ""
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Caret"
-msgstr ""
+msgstr "Stříška"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Blink"
@@ -25554,7 +25462,7 @@ msgstr "Vynásobit %s"
#: scene/main/scene_tree.cpp scene/resources/mesh_library.cpp
#: scene/resources/shape_2d.cpp
msgid "Shapes"
-msgstr ""
+msgstr "Tvary"
#: scene/main/scene_tree.cpp
msgid "Shape Color"
@@ -25721,7 +25629,7 @@ msgstr "Levé lineární"
#: scene/main/viewport.cpp
msgid "Render Direct To Screen"
-msgstr ""
+msgstr "Vykreslovat přímo na obrazovku"
#: scene/main/viewport.cpp
#, fuzzy
@@ -26519,9 +26427,8 @@ msgid "Label Width"
msgstr "Vlevo po celé výšce"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Screen Picker"
-msgstr "Operátor screen."
+msgstr "Výběr obrazovky"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -27600,9 +27507,8 @@ msgid "Bind"
msgstr "Vazba"
#: scene/resources/skin.cpp
-#, fuzzy
msgid "Bone"
-msgstr "Kosti"
+msgstr "Kost"
#: scene/resources/sky.cpp
#, fuzzy
diff --git a/editor/translations/da.po b/editor/translations/da.po
index bb158fcada..5a9e684e85 100644
--- a/editor/translations/da.po
+++ b/editor/translations/da.po
@@ -11471,7 +11471,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/de.po b/editor/translations/de.po
index 61a5a51b9c..6d1c27e5b2 100644
--- a/editor/translations/de.po
+++ b/editor/translations/de.po
@@ -23,7 +23,7 @@
# Peter Friedland <peter_friedland@gmx.de>, 2016.
# No need for a name <endoplasmatik@gmx.net>, 2016.
# Sönke <me@eknoes.de>, 2018.
-# So Wieso <sowieso@dukun.de>, 2016-2018, 2019, 2020, 2021, 2022.
+# So Wieso <sowieso@dukun.de>, 2016-2018, 2019, 2020, 2021, 2022, 2023.
# Tim Schellenberg <smwleod@gmail.com>, 2017.
# Timo Schwarzer <account@timoschwarzer.com>, 2016-2018.
# viernullvier <hannes.breul+github@gmail.com>, 2016.
@@ -87,13 +87,14 @@
# Anonynonymouse <tom.spaine60388@gmail.com>, 2022.
# Felix Bitsch <felix.a.bitsch@gmail.com>, 2022.
# miguel <miguel-gonzalez@gmx.de>, 2022.
+# Least Significant Bite <leastsignificantbite@proton.me>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-12-13 13:21+0000\n"
-"Last-Translator: ‎ <artism90@googlemail.com>\n"
+"PO-Revision-Date: 2023-01-09 20:42+0000\n"
+"Last-Translator: So Wieso <sowieso@dukun.de>\n"
"Language-Team: German <https://hosted.weblate.org/projects/godot-engine/"
"godot/de/>\n"
"Language: de\n"
@@ -101,7 +102,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -482,7 +483,7 @@ msgstr "Gedrückt"
#: core/os/input_event.cpp
msgid "Scancode"
-msgstr "Scancode"
+msgstr "Tastencode"
#: core/os/input_event.cpp
msgid "Physical Scancode"
@@ -3751,7 +3752,7 @@ msgstr "Hoch"
#: editor/editor_network_profiler.cpp editor/editor_node.cpp
#: scene/main/node.cpp scene/resources/default_theme/default_theme.cpp
msgid "Node"
-msgstr "Knoten"
+msgstr "das Node"
#: editor/editor_network_profiler.cpp
msgid "Incoming RPC"
@@ -11038,7 +11039,7 @@ msgstr "Hinten perspektivisch"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [Portale aktiv]"
@@ -14308,17 +14309,15 @@ msgid "Invalid project path (changed anything?)."
msgstr "Ungültiger Projektpfad (etwas geändert?)."
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
msgstr ""
-"Die Datei project.godot im Projektpfad konnte nicht geladen werden (Fehler "
-"%d). Sie könnte fehlen oder beschädigt sein."
+"Projekt in ‚%s‘ konnte nicht geladen werden (Fehler %d). Es ist "
+"möglicherweise nicht vorhanden oder beschädigt."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Couldn't save project at '%s' (error %d)."
-msgstr "Projekt in ‚%s‘ kann nicht geöffnet werden."
+msgstr "Projekt konnte nicht in ‚%s‘ gespeichert werden (Fehler %d)."
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
@@ -23255,14 +23254,12 @@ msgid "AABB"
msgstr "AABB"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Sorting"
-msgstr "Sortiere"
+msgstr "Sortierung"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Use AABB Center"
-msgstr "Ambient verwenden"
+msgstr "AABB-Mittelpunkt verwenden"
#: scene/3d/visual_instance.cpp scene/resources/navigation_mesh.cpp
msgid "Geometry"
diff --git a/editor/translations/editor.pot b/editor/translations/editor.pot
index 7b7bfd71cc..964eb46175 100644
--- a/editor/translations/editor.pot
+++ b/editor/translations/editor.pot
@@ -1,6 +1,6 @@
# LANGUAGE translation of the Godot Engine editor.
-# Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.
-# Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).
+# Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md).
+# Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur.
# This file is distributed under the same license as the Godot source code.
#
# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
@@ -10564,7 +10564,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/el.po b/editor/translations/el.po
index 98873c7d40..fe89b69334 100644
--- a/editor/translations/el.po
+++ b/editor/translations/el.po
@@ -18,13 +18,14 @@
# JessicaLukatz <jessicalukatz32038@gmail.com>, 2022.
# Anthony V. <batmanplayer123@gmail.com>, 2022.
# Anthony V. <anthonyv156@outlook.com>, 2022.
+# Ilias Vasilakis <vaselas99@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-05-20 11:17+0000\n"
-"Last-Translator: Anthony V. <anthonyv156@outlook.com>\n"
+"PO-Revision-Date: 2023-01-15 13:34+0000\n"
+"Last-Translator: Ilias Vasilakis <vaselas99@gmail.com>\n"
"Language-Team: Greek <https://hosted.weblate.org/projects/godot-engine/godot/"
"el/>\n"
"Language: el\n"
@@ -32,7 +33,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.13-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -622,7 +623,7 @@ msgstr "Εμφάνιση όλων"
#: modules/opensimplex/noise_texture.cpp scene/2d/line_2d.cpp
#: scene/3d/label_3d.cpp scene/gui/text_edit.cpp scene/resources/texture.cpp
msgid "Width"
-msgstr ""
+msgstr "Πλάτος"
#: core/project_settings.cpp main/main.cpp modules/csg/csg_shape.cpp
#: modules/gltf/gltf_node.cpp modules/opensimplex/noise_texture.cpp
@@ -636,7 +637,7 @@ msgstr "Φως"
#: core/project_settings.cpp
msgid "Always On Top"
-msgstr ""
+msgstr "Πάντα στο επάνω μέÏος"
#: core/project_settings.cpp
#, fuzzy
@@ -804,7 +805,7 @@ msgstr "Απόδοση"
#: scene/resources/multimesh.cpp servers/visual/visual_server_scene.cpp
#: servers/visual_server.cpp
msgid "Quality"
-msgstr ""
+msgstr "Ποιότητα"
#: core/project_settings.cpp scene/gui/file_dialog.cpp
#: scene/main/scene_tree.cpp scene/resources/navigation_mesh.cpp
@@ -863,7 +864,7 @@ msgstr ""
#: core/project_settings.cpp
msgid "Compression Level"
-msgstr ""
+msgstr "Βαθμός Συμπίεσης"
#: core/project_settings.cpp
msgid "Window Log Size"
@@ -1034,11 +1035,11 @@ msgstr ""
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Renderable Elements"
-msgstr ""
+msgstr "Μέγιστος αÏιθμός οπτικοποιήσημων στοιχείων"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Renderable Lights"
-msgstr ""
+msgstr "Μέγιστος αÏιθμός Οπτικοποιήσημων Φωτών"
#: drivers/gles3/rasterizer_scene_gles3.cpp
#, fuzzy
@@ -1081,7 +1082,7 @@ msgstr ""
#: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp
msgid "High Quality"
-msgstr ""
+msgstr "Υψηλή Ποιότητα"
#: drivers/gles3/rasterizer_storage_gles3.cpp
msgid "Blend Shape Max Buffer Size (KB)"
@@ -1196,7 +1197,7 @@ msgstr "Ποσότητα:"
#: editor/animation_track_editor.cpp main/main.cpp
#: modules/mono/mono_gd/gd_mono.cpp
msgid "Args"
-msgstr ""
+msgstr "ΟÏίσματα"
#: editor/animation_track_editor.cpp editor/editor_settings.cpp
#: editor/script_editor_debugger.cpp modules/gltf/gltf_accessor.cpp
@@ -2474,7 +2475,7 @@ msgstr ""
#: editor/editor_asset_installer.cpp
msgid "Contents of asset \"%s\" - No files conflict with your project:"
-msgstr ""
+msgstr "ΠεÏιεχόμενα ΠόÏου \"%s\" - Καμία ΣÏγκÏουση αÏχείων στο ΈÏγο σου:"
#: editor/editor_asset_installer.cpp
msgid "Uncompressing Assets"
@@ -2486,9 +2487,8 @@ msgid "The following files failed extraction from asset \"%s\":"
msgstr "Η εξαγωγή των ακόλουθων αÏχείων από το πακέτο απέτυχε:"
#: editor/editor_asset_installer.cpp
-#, fuzzy
msgid "(and %s more files)"
-msgstr "Και %s αÏχεία ακόμα."
+msgstr "Και %s αÏχεία ακόμα"
#: editor/editor_asset_installer.cpp
#, fuzzy
@@ -2837,22 +2837,19 @@ msgstr "Επιλέξτε"
#: editor/editor_export.cpp
msgid "Project export for platform:"
-msgstr ""
+msgstr "Εξαγωγή ΈÏγου για πλατφόÏμα:"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Completed with warnings."
-msgstr "ΑντιγÏαφή διαδÏομής κόμβου"
+msgstr "ΟλοκληÏώθηκε με ΠÏοειδοποιήσεις."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Completed successfully."
-msgstr "Το πακέτο εγκαταστάθηκε επιτυχώς!"
+msgstr "Επιτυχής ΟλοκλήÏωση."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Failed."
-msgstr "Απέτυχε:"
+msgstr "Απέτυχε."
#: editor/editor_export.cpp
msgid "Storing File:"
@@ -2877,14 +2874,12 @@ msgid "Cannot create file \"%s\"."
msgstr "ΑδÏνατη η δημιουÏγία φακέλου."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Failed to export project files."
-msgstr "Απέτυχε η εγγÏαφή σε αÏχείο:"
+msgstr "Απέτυχε η εξαγωγή αÏχείων έÏγου."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Can't open file to read from path \"%s\"."
-msgstr "ΑδÏνατο το άνοιγμα αÏχείου για εγγÏαφή:"
+msgstr "ΑδÏνατο το άνοιγμα αÏχείου για ανάγνωση απο το μονοπάτι \"%s\"."
#: editor/editor_export.cpp
#, fuzzy
@@ -2962,9 +2957,8 @@ msgid "Release"
msgstr "ΕλευθέÏωση"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Binary Format"
-msgstr "Τελεστής χÏώματος."
+msgstr "Δυαδική ΜοÏφή"
#: editor/editor_export.cpp
msgid "64 Bits"
@@ -3017,14 +3011,12 @@ msgid "Prepare Template"
msgstr "ΔιαχείÏιση ΠÏοτÏπων"
#: editor/editor_export.cpp platform/osx/export/export.cpp
-#, fuzzy
msgid "The given export path doesn't exist."
-msgstr "Η δεδομένη διαδÏομή εξαγωγής δεν υπάÏχει:"
+msgstr "Η δεδομένη διαδÏομή εξαγωγής δεν υπάÏχει."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
-#, fuzzy
msgid "Template file not found: \"%s\"."
-msgstr "Δεν βÏέθηκε αÏχείο Ï€ÏοτÏπου:"
+msgstr "Δεν βÏέθηκε το αÏχείο Ï€ÏοτÏπου: \"%s\"."
#: editor/editor_export.cpp
#, fuzzy
@@ -3077,7 +3069,7 @@ msgstr "ΠλατφόÏμα Εισαγωγής"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "ΕπιτÏέπει την Ï€Ïοβολή και επεξεÏγασία Ï„Ïισδιάστατων σκηνών."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
@@ -6103,9 +6095,8 @@ msgid "Bone Outline Color"
msgstr ""
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Outline Size"
-msgstr "Μέγεθος πεÏιγÏάμματος:"
+msgstr "Μέγεθος πεÏιγÏάμματος Κοκάλου"
#: editor/editor_settings.cpp
msgid "Viewport Border Color"
@@ -10857,7 +10848,7 @@ msgstr "ΠÏοηγοÏμενη Δέσμη ΕνεÏγειών"
#: editor/plugins/script_editor_plugin.cpp
#: scene/resources/default_theme/default_theme.cpp
msgid "File"
-msgstr "ΑÏχείο"
+msgstr "Φάκελος"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open..."
@@ -11366,7 +11357,7 @@ msgstr "ΠÏοοπτική"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
@@ -16732,15 +16723,15 @@ msgstr "ΧÏήση κουμπώματος"
#: main/main.cpp
msgid "Per Pixel Transparency"
-msgstr ""
+msgstr "Διαφάνεια ανα Πίξελ"
#: main/main.cpp
msgid "Allowed"
-msgstr ""
+msgstr "ΕπιτÏεπτό"
#: main/main.cpp
msgid "Intended Usage"
-msgstr ""
+msgstr "ΠÏοβλεπόμενη ΧÏήση"
#: main/main.cpp
#, fuzzy
@@ -16754,7 +16745,7 @@ msgstr "Σφάλμα αποθήκευσης"
#: main/main.cpp
msgid "Threads"
-msgstr ""
+msgstr "Îήματα"
#: main/main.cpp servers/physics_2d/physics_2d_server_wrap_mt.h
#, fuzzy
@@ -16767,7 +16758,7 @@ msgstr ""
#: main/main.cpp
msgid "Handheld"
-msgstr ""
+msgstr "ΧειÏός"
#: main/main.cpp platform/javascript/export/export.cpp
#: platform/uwp/export/export.cpp
@@ -16799,7 +16790,7 @@ msgstr ""
#: scene/gui/scroll_container.cpp scene/gui/text_edit.cpp scene/gui/tree.cpp
#: scene/main/viewport.cpp scene/register_scene_types.cpp
msgid "GUI"
-msgstr ""
+msgstr "ΓÏαφική Διεπαφή ΧÏήσης"
#: main/main.cpp
msgid "Drop Mouse On GUI Input Disabled"
@@ -16811,7 +16802,7 @@ msgstr ""
#: main/main.cpp
msgid "Print FPS"
-msgstr ""
+msgstr "Δείξε ΚαÏέ ανα ΔευτεÏόλεπτο"
#: main/main.cpp
msgid "Verbose stdout"
@@ -16834,7 +16825,7 @@ msgstr "ΚαÏέ Επιλογής"
#: main/main.cpp
msgid "Low Processor Mode"
-msgstr ""
+msgstr "ΛειτουÏγεία Χαμηλής ΧÏήσης ΕπεξεÏγαστή"
#: main/main.cpp
msgid "Delta Sync After Draw"
@@ -16860,7 +16851,7 @@ msgstr "Σημείο"
#: main/main.cpp
msgid "Touch Delay"
-msgstr ""
+msgstr "ΚαθυστέÏηση Επαφής"
#: main/main.cpp servers/visual_server.cpp
msgid "GLES3"
@@ -16884,7 +16875,7 @@ msgstr "Εμφάνιση πεÏιβάλλοντος"
#: main/main.cpp
msgid "Default Clear Color"
-msgstr ""
+msgstr "ΠÏοκαθοÏισμένο ΧÏώμα ΚαθαÏίσματος"
#: main/main.cpp
msgid "Boot Splash"
@@ -16897,11 +16888,11 @@ msgstr "Εμφάνιση Οστών"
#: main/main.cpp
msgid "Image"
-msgstr ""
+msgstr "Εικόνα"
#: main/main.cpp
msgid "Fullsize"
-msgstr ""
+msgstr "ΠλήÏης Μέγεθος"
#: main/main.cpp scene/resources/dynamic_font.cpp
#, fuzzy
@@ -16932,11 +16923,11 @@ msgstr ""
#: main/main.cpp
msgid "Emulate Touch From Mouse"
-msgstr ""
+msgstr "ΠÏοσομοίωση Αφής απο το Ποντίκι"
#: main/main.cpp
msgid "Emulate Mouse From Touch"
-msgstr ""
+msgstr "ΠÏοσομοίωση Î Î¿Î½Ï„Î¹ÎºÎ¹Î¿Ï Î±Ï€Î¿ Αφή"
#: main/main.cpp
#, fuzzy
@@ -16974,11 +16965,11 @@ msgstr "Λήξη χÏÎ¿Î½Î¹ÎºÎ¿Ï Î¿Ïίου."
#: main/main.cpp
msgid "Runtime"
-msgstr ""
+msgstr "ΧÏόνος Εκτέλεσης"
#: main/main.cpp
msgid "Unhandled Exception Policy"
-msgstr ""
+msgstr "Πολιτική μη-χειÏιζόμενων ΕξαίÏεσεων"
#: main/main.cpp
#, fuzzy
@@ -16988,7 +16979,7 @@ msgstr "ΕÏÏεση είδους κόμβου"
#: main/main.cpp scene/gui/texture_progress.cpp
#: scene/gui/viewport_container.cpp
msgid "Stretch"
-msgstr ""
+msgstr "Τέντωμα"
#: main/main.cpp
#, fuzzy
@@ -16997,11 +16988,11 @@ msgstr "ΕπιθεωÏητής"
#: main/main.cpp
msgid "Shrink"
-msgstr ""
+msgstr "Συστολή"
#: main/main.cpp scene/main/scene_tree.cpp
msgid "Auto Accept Quit"
-msgstr ""
+msgstr "Αυτόματη Αποδοχή Εξόδου"
#: main/main.cpp scene/main/scene_tree.cpp
#, fuzzy
@@ -17015,11 +17006,11 @@ msgstr "ΠÏοσκόλληση σε ΠλευÏές Κόμβου"
#: main/main.cpp
msgid "Dynamic Fonts"
-msgstr ""
+msgstr "Δυναμικές ΓÏαμματοσειÏές"
#: main/main.cpp
msgid "Use Oversampling"
-msgstr ""
+msgstr "ΧÏήση ΥπεÏδειγματοληψίας"
#: modules/bullet/register_types.cpp modules/bullet/space_bullet.cpp
msgid "Active Soft World"
@@ -17052,7 +17043,7 @@ msgstr "Επιλογές"
#: modules/csg/csg_shape.cpp
msgid "Calculate Tangents"
-msgstr ""
+msgstr "Υπολογεισμός Καθέτων"
#: modules/csg/csg_shape.cpp
#, fuzzy
@@ -17110,7 +17101,7 @@ msgstr "Εμφάνιση Οδηγιών"
#: modules/csg/csg_shape.cpp
msgid "Cone"
-msgstr ""
+msgstr "Κώνος"
#: modules/csg/csg_shape.cpp
#, fuzzy
@@ -17135,11 +17126,11 @@ msgstr "ΠολÏγωνα"
#: modules/csg/csg_shape.cpp
msgid "Spin Degrees"
-msgstr ""
+msgstr "Βαθμοί ΠεÏιστοφικής Κίνησης"
#: modules/csg/csg_shape.cpp
msgid "Spin Sides"
-msgstr ""
+msgstr "ΠλευÏές ΠεÏιστÏοφικής Κίνησης"
#: modules/csg/csg_shape.cpp
#, fuzzy
@@ -17337,7 +17328,7 @@ msgstr "Δέσμες ΕνεÏγειών"
#: modules/gdscript/editor/gdscript_highlighter.cpp
msgid "Function Definition Color"
-msgstr ""
+msgstr "ΧÏώμα Δήλωσης ΣυνάÏτησης"
#: modules/gdscript/editor/gdscript_highlighter.cpp
#, fuzzy
@@ -17350,7 +17341,7 @@ msgstr ""
#: modules/gdscript/gdscript.cpp
msgid "Treat Warnings As Errors"
-msgstr ""
+msgstr "ΣυμπεÏιφοÏά σε Ï€Ïοειδοποιήσεις ως σφάλματα"
#: modules/gdscript/gdscript.cpp
msgid "Exclude Addons"
@@ -17414,7 +17405,7 @@ msgstr ""
#: modules/gdscript/language_server/gdscript_language_server.cpp
msgid "Use Thread"
-msgstr ""
+msgstr "ΧÏήση Îήματος"
#: modules/gltf/editor_scene_exporter_gltf_plugin.cpp
#, fuzzy
@@ -17639,11 +17630,11 @@ msgstr ""
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Diffuse Factor"
-msgstr ""
+msgstr "Βαθμός Διάχυσης"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Gloss Factor"
-msgstr ""
+msgstr "Βαθμός Γυαλάδας"
#: modules/gltf/gltf_spec_gloss.cpp
#, fuzzy
@@ -17704,11 +17695,11 @@ msgstr "Δυνατότητες"
#: modules/gltf/gltf_state.cpp platform/uwp/export/export.cpp
msgid "Images"
-msgstr ""
+msgstr "Εικόνες"
#: modules/gltf/gltf_state.cpp
msgid "Cameras"
-msgstr ""
+msgstr "ΚάμεÏες"
#: modules/gltf/gltf_state.cpp servers/visual_server.cpp
#, fuzzy
@@ -17782,7 +17773,7 @@ msgstr "ΚέντÏο"
#: scene/2d/tile_map.cpp scene/3d/collision_object.cpp scene/3d/soft_body.cpp
#: scene/resources/material.cpp
msgid "Mask"
-msgstr ""
+msgstr "Μάσκα"
#: modules/gridmap/grid_map.cpp scene/2d/tile_map.cpp
#, fuzzy
@@ -17932,7 +17923,7 @@ msgstr ""
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
msgid "Preparing data structures"
-msgstr ""
+msgstr "ΠÏοετοιμασία δομών δεδομένων"
#: modules/lightmapper_cpu/lightmapper_cpu.cpp
#, fuzzy
@@ -17966,19 +17957,19 @@ msgstr "ΠÏοετοιμασία Lightmaps"
#: modules/lightmapper_cpu/register_types.cpp
msgid "Low Quality Ray Count"
-msgstr ""
+msgstr "ΑÏιθμός Ακτινών Χαμηλής Ποιότητας"
#: modules/lightmapper_cpu/register_types.cpp
msgid "Medium Quality Ray Count"
-msgstr ""
+msgstr "ΑÏιθμός Ακτινών ΜέτÏιας Ποιότητας"
#: modules/lightmapper_cpu/register_types.cpp
msgid "High Quality Ray Count"
-msgstr ""
+msgstr "ΑÏιθμός Ακτινών Υψηλής Ποιότητας"
#: modules/lightmapper_cpu/register_types.cpp
msgid "Ultra Quality Ray Count"
-msgstr ""
+msgstr "ΑÏιθμός Ακτινών Ύψιστης Ποιότητας"
#: modules/minimp3/audio_stream_mp3.cpp
#: modules/minimp3/resource_importer_mp3.cpp
@@ -17990,7 +17981,7 @@ msgstr "Μετατόπιση:"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "Eye Height"
-msgstr ""
+msgstr "Ύψος Ματιών"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "IOD"
@@ -18133,7 +18124,7 @@ msgstr ""
#: modules/opensimplex/noise_texture.cpp
msgid "Noise"
-msgstr ""
+msgstr "ΘόÏυβος"
#: modules/opensimplex/noise_texture.cpp
#, fuzzy
@@ -18142,11 +18133,11 @@ msgstr "Μετατόπιση Πλέγματος:"
#: modules/opensimplex/open_simplex_noise.cpp
msgid "Octaves"
-msgstr ""
+msgstr "Οκτάβες"
#: modules/opensimplex/open_simplex_noise.cpp
msgid "Period"
-msgstr ""
+msgstr "ΠεÏίοδος"
#: modules/opensimplex/open_simplex_noise.cpp
#, fuzzy
@@ -18155,7 +18146,7 @@ msgstr "ΠÏοοπτική"
#: modules/opensimplex/open_simplex_noise.cpp
msgid "Lacunarity"
-msgstr ""
+msgstr "Κενότητα"
#: modules/regex/regex.cpp
msgid "Subject"
@@ -18177,7 +18168,7 @@ msgstr ""
#: modules/upnp/upnp.cpp
msgid "Discover Local Port"
-msgstr ""
+msgstr "ΕÏÏεση Τοπικής ΘÏÏας"
#: modules/upnp/upnp.cpp
msgid "Discover IPv6"
@@ -18740,26 +18731,24 @@ msgid "Mod %s"
msgstr "ΠÏόσθεσε %s"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "ShiftLeft %s"
-msgstr "Θέσε %s"
+msgstr "ΑÏιστεÏή μετατόπιση %s"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "ShiftRight %s"
-msgstr ""
+msgstr "Δεξιά μετατόπιση %s"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "BitAnd %s"
-msgstr "ΠÏόσθεσε %s"
+msgstr "Λογικό Και %s"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "BitOr %s"
-msgstr ""
+msgstr "ΛογικόΗ %s"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "BitXor %s"
-msgstr ""
+msgstr "Î›Î¿Î³Î¹ÎºÏŒÎžÎ¿Ï %s"
#: modules/visual_script/visual_script_func_nodes.cpp
#, fuzzy
@@ -18895,9 +18884,8 @@ msgid "Get Self"
msgstr "Εαυτός"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "CustomNode"
-msgstr "Αποκοπή κόμβων"
+msgstr ""
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
@@ -18955,7 +18943,7 @@ msgstr "εσοδεία"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "Wait"
-msgstr ""
+msgstr "ΠεÏίμενε"
#: modules/visual_script/visual_script_yield_nodes.cpp
#, fuzzy
@@ -19605,10 +19593,11 @@ msgstr ""
#: platform/android/export/export_plugin.cpp
msgid "Invalid filename! Android APK requires the *.apk extension."
msgstr ""
+"Μή ΈγκυÏο όνομα αÏχείου! Το Android APK δέχεται μόνο την .apk κατάληξη."
#: platform/android/export/export_plugin.cpp
msgid "Unsupported export format!"
-msgstr ""
+msgstr "Μη αποδεκτή μοÏφή εξαγωγής!"
#: platform/android/export/export_plugin.cpp
msgid ""
@@ -19661,7 +19650,7 @@ msgstr ""
#: platform/android/export/export_plugin.cpp
msgid "Moving output"
-msgstr ""
+msgstr "Μετακίνηση της εξόδου"
#: platform/android/export/export_plugin.cpp
msgid ""
@@ -21362,7 +21351,7 @@ msgstr "ΣυμπλήÏωση"
#: scene/2d/canvas_item.cpp
msgid "Show Behind Parent"
-msgstr ""
+msgstr "Δείξε πίσω απο τον Γωνέα"
#: scene/2d/canvas_item.cpp
#, fuzzy
@@ -21377,7 +21366,7 @@ msgstr "Φως"
#: scene/2d/canvas_item.cpp
msgid "Use Parent Material"
-msgstr ""
+msgstr "ΧÏησιμποίησε το Υλικό του Γονέα"
#: scene/2d/canvas_modulate.cpp
msgid ""
@@ -21422,6 +21411,8 @@ msgstr "Ένα άδειο ColisionPollygon2D δεν επηÏεάζει τη σÏ
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 3 points are needed in 'Solids' build mode."
msgstr ""
+"Μή έγκυÏο πολÏγωνο. ΠÏέπει να Ï€ÏοσδιοÏιστοÏν τουλάχιστον Ï„Ïία (3) σημεία για "
+"τη δημιουÏγία στεÏÎµÎ¿Ï Î±Î½Ï„Î¹ÎºÎµÎ¹Î¼Î­Î½Î¿Ï…."
#: scene/2d/collision_polygon_2d.cpp
msgid "Invalid polygon. At least 2 points are needed in 'Segments' build mode."
@@ -21499,7 +21490,7 @@ msgstr "Ρυθμίσεις:"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
msgid "Lifetime"
-msgstr ""
+msgstr "ΔιάÏκεια Ζωής"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp scene/main/timer.cpp
@@ -21516,7 +21507,7 @@ msgstr "ΜετεπεξεÏγασία"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
msgid "Explosiveness"
-msgstr ""
+msgstr "ΕκÏηκτικότητα"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
@@ -21527,7 +21518,7 @@ msgstr "Τυχαία επανεκκίνηση (δευτεÏόλεπτα):"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Lifetime Randomness"
-msgstr ""
+msgstr "Τυχαιότητα ΔιάÏκειας Ζωής"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
@@ -21543,7 +21534,7 @@ msgstr ""
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
msgid "Drawing"
-msgstr ""
+msgstr "Σχεδίαση"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
@@ -21554,7 +21545,7 @@ msgstr "ΈÏγα"
#: scene/2d/cpu_particles_2d.cpp scene/2d/particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/particles.cpp
msgid "Draw Order"
-msgstr ""
+msgstr "ΣειÏά Σχεδίασης"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21594,7 +21585,7 @@ msgstr "Κατευθήνσεις"
#: scene/resources/particles_material.cpp
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Spread"
-msgstr ""
+msgstr "ΕÏÏος"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21612,7 +21603,7 @@ msgstr "ΑÏχικοποιήστε"
#: scene/resources/particles_material.cpp servers/physics_2d_server.cpp
#: servers/physics_server.cpp
msgid "Angular Velocity"
-msgstr ""
+msgstr "Γωνιακή ταχÏτητα"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21623,7 +21614,7 @@ msgstr "ΑÏχικοποιήστε"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Orbit Velocity"
-msgstr ""
+msgstr "ΤÏοχιακή ταχÏτητα"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21651,12 +21642,12 @@ msgstr "ΔιαίÏεση ΚαμπÏλης"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Radial Accel"
-msgstr ""
+msgstr "ΤÏοχιακή επιτάχυνση"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Tangential Accel"
-msgstr ""
+msgstr "Γωνιακή επιτάχυνση"
#: scene/2d/cpu_particles_2d.cpp scene/2d/joints_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/physics_body.cpp
@@ -21664,12 +21655,12 @@ msgstr ""
#: scene/resources/particles_material.cpp
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Damping"
-msgstr ""
+msgstr "Απόσβεση"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Damping Random"
-msgstr ""
+msgstr "Τυχαιότητα Απόσβεσης"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21680,12 +21671,12 @@ msgstr "ΔιαίÏεση ΚαμπÏλης"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp scene/3d/light.cpp
#: scene/resources/particles_material.cpp
msgid "Angle"
-msgstr ""
+msgstr "Γωνία"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
msgid "Angle Random"
-msgstr ""
+msgstr "Τυχαιότητα Γωνίας"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/particles_material.cpp
@@ -21700,7 +21691,7 @@ msgstr "Ποσότητα:"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
msgid "Scale Amount Random"
-msgstr ""
+msgstr "Τυχαιότητα ΠοσoÏ ÎšÎ»Î¹Î¼Î¬ÎºÏ‰ÏƒÎ·Ï‚"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#, fuzzy
@@ -21768,15 +21759,15 @@ msgstr "κλείσιμο καμπÏλης"
#: scene/2d/joints_2d.cpp
msgid "Node A and Node B must be PhysicsBody2Ds"
-msgstr ""
+msgstr "Ο Κόμβος Α και ο Κόμβος Î’ Ï€Ïέπει να είναι του Ï„Ïπου PhysicsBody2Ds"
#: scene/2d/joints_2d.cpp
msgid "Node A must be a PhysicsBody2D"
-msgstr ""
+msgstr "Ο Κόμβος Α Ï€Ïέπει να είναι του Ï„Ïπου PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Node B must be a PhysicsBody2D"
-msgstr ""
+msgstr "Ο κόμβος Î’ Ï€Ïέπει να είναι του Ï„Ïπου PhysicsBody2D"
#: scene/2d/joints_2d.cpp
msgid "Joint is not connected to two PhysicsBody2Ds"
@@ -22206,7 +22197,7 @@ msgstr "ΛειτουÏγία ΠÏοτεÏαιότητας"
#: scene/2d/particles_2d.cpp scene/3d/particles.cpp
msgid "Process Material"
-msgstr ""
+msgstr "ΕπεξεÏγασία ΥλικοÏ"
#: scene/2d/path_2d.cpp scene/3d/path.cpp scene/resources/sky.cpp
#: scene/resources/texture.cpp
@@ -22269,7 +22260,7 @@ msgstr ""
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
msgid "Physics Material Override"
-msgstr ""
+msgstr "ΠαÏάκαμψη Î¥Î»Î¹ÎºÎ¿Ï Î¦Ï…ÏƒÎ¹ÎºÎ®Ï‚"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
#: scene/resources/world.cpp scene/resources/world_2d.cpp
@@ -22460,11 +22451,11 @@ msgstr ""
#: scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp scene/3d/ray_cast.cpp
msgid "Areas"
-msgstr ""
+msgstr "Τοποθεσίες"
#: scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp scene/3d/ray_cast.cpp
msgid "Bodies"
-msgstr ""
+msgstr "Σώματα"
#: scene/2d/remote_transform_2d.cpp
msgid "Path property must point to a valid Node2D node to work."
@@ -22511,11 +22502,11 @@ msgstr ""
#: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
msgid "Hframes"
-msgstr ""
+msgstr "ΟÏιζόντια ΚαÏέ"
#: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
msgid "Vframes"
-msgstr ""
+msgstr "Κάθετα ΚαÏέ"
#: scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
#, fuzzy
@@ -22594,7 +22585,7 @@ msgstr "ΛειτουÏγία ΣÏγκÏουσης"
#: scene/2d/tile_map.cpp
msgid "Use Kinematic"
-msgstr ""
+msgstr "ΧÏήση ΚινηματικοÏ"
#: scene/2d/touch_screen_button.cpp
#, fuzzy
@@ -22630,7 +22621,7 @@ msgstr "Επικόλληση κίνησης"
#: scene/2d/visibility_notifier_2d.cpp scene/3d/visibility_notifier.cpp
msgid "Freeze Bodies"
-msgstr ""
+msgstr "Πάγωμα Σωμάτων"
#: scene/2d/visibility_notifier_2d.cpp
#, fuzzy
@@ -22666,11 +22657,11 @@ msgstr "Η ARVRCamera απαιτεί γονικό κόμβο ARVROrigin."
#: scene/3d/arvr_nodes.cpp
msgid "Controller ID"
-msgstr ""
+msgstr "ΑναγνωÏηστικό ΧειÏιστηÏίου"
#: scene/3d/arvr_nodes.cpp servers/arvr/arvr_positional_tracker.cpp
msgid "Rumble"
-msgstr ""
+msgstr "Δώνηση"
#: scene/3d/arvr_nodes.cpp
msgid "ARVRController must have an ARVROrigin node as its parent."
@@ -22729,7 +22720,7 @@ msgstr ""
#: scene/3d/audio_stream_player_3d.cpp
msgid "Out Of Range Mode"
-msgstr ""
+msgstr "ΑπομακÏισμένη ΛειτουÏγεία"
#: scene/3d/audio_stream_player_3d.cpp
#, fuzzy
@@ -22748,7 +22739,7 @@ msgstr "Κίνηση"
#: scene/3d/audio_stream_player_3d.cpp
msgid "Attenuation Filter"
-msgstr ""
+msgstr "ΦίλτÏο Απόσβεσης"
#: scene/3d/audio_stream_player_3d.cpp
#: servers/audio/effects/audio_effect_chorus.cpp
@@ -22775,11 +22766,11 @@ msgstr "ΠακετάÏισμα"
#: scene/3d/baked_lightmap.cpp scene/3d/gi_probe.cpp
#: scene/3d/reflection_probe.cpp
msgid "Interior"
-msgstr ""
+msgstr "ΕσωτεÏικό"
#: scene/3d/baked_lightmap.cpp
msgid "Finding meshes and lights"
-msgstr ""
+msgstr "Î’Ïίσκοντας πλέγματα και φώτα"
#: scene/3d/baked_lightmap.cpp
msgid "Preparing geometry (%d/%d)"
@@ -22813,11 +22804,11 @@ msgstr "ΜαÏαφέτια"
#: scene/3d/baked_lightmap.cpp
msgid "Tweaks"
-msgstr ""
+msgstr "ΜικÏοδιοÏθώσεις"
#: scene/3d/baked_lightmap.cpp
msgid "Bounces"
-msgstr ""
+msgstr "Πηδήματα"
#: scene/3d/baked_lightmap.cpp
msgid "Bounce Indirect Energy"
@@ -22907,7 +22898,7 @@ msgstr ""
#: scene/3d/camera.cpp scene/3d/light.cpp scene/3d/reflection_probe.cpp
msgid "Cull Mask"
-msgstr ""
+msgstr "Μάσκα Αποκοπής"
#: scene/3d/camera.cpp
#, fuzzy
@@ -22921,7 +22912,7 @@ msgstr "ΈÏγο"
#: scene/3d/camera.cpp
msgid "FOV"
-msgstr ""
+msgstr "Οπτικό Πεδίο"
#: scene/3d/camera.cpp
#, fuzzy
@@ -22935,7 +22926,7 @@ msgstr "ΠλησιέστεÏη"
#: scene/3d/camera.cpp
msgid "Far"
-msgstr ""
+msgstr "ΜακÏιά"
#: scene/3d/camera.cpp scene/3d/collision_polygon.cpp scene/3d/spring_arm.cpp
#: scene/gui/control.cpp scene/resources/default_theme/default_theme.cpp
@@ -22952,7 +22943,7 @@ msgstr "ΠεÏικοπή πάνω"
#: scene/3d/collision_object.cpp scene/3d/soft_body.cpp
msgid "Ray Pickable"
-msgstr ""
+msgstr "Επιλέξημη Ακτίνα"
#: scene/3d/collision_object.cpp
#, fuzzy
@@ -23068,7 +23059,7 @@ msgstr "ΑπενεÏγοποιημένο Στοιχείο"
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
msgid "Flatness"
-msgstr ""
+msgstr "Ομαλότητα"
#: scene/3d/cull_instance.cpp servers/visual_server.cpp
#, fuzzy
@@ -23086,7 +23077,7 @@ msgstr ""
#: scene/3d/cull_instance.cpp
msgid "Allow Merging"
-msgstr ""
+msgstr "ΕπίτÏεψε Συγχώνευση"
#: scene/3d/cull_instance.cpp
#, fuzzy
@@ -23118,7 +23109,7 @@ msgstr ""
#: scene/3d/gi_probe.cpp
msgid "Subdiv"
-msgstr ""
+msgstr "ΥποδιαίÏεση"
#: scene/3d/gi_probe.cpp
#, fuzzy
@@ -23137,7 +23128,7 @@ msgstr "ΚοÏμπωμα στα εικονοστοιχεία"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp
msgid "Billboard"
-msgstr ""
+msgstr "Πινακίδα"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp
#, fuzzy
@@ -23146,11 +23137,11 @@ msgstr "ΠÏόγÏαμμα Σκίασης"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp
msgid "Double Sided"
-msgstr ""
+msgstr "ΔÏο Όψεων"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp scene/resources/material.cpp
msgid "No Depth Test"
-msgstr ""
+msgstr "ΧωÏίς Έλεγχο Βάθους"
#: scene/3d/label_3d.cpp scene/3d/sprite_3d.cpp scene/resources/material.cpp
#, fuzzy
@@ -23289,7 +23280,7 @@ msgstr ""
#: scene/3d/light.cpp
msgid "Spot"
-msgstr ""
+msgstr "ΠÏοβολέας"
#: scene/3d/light.cpp
#, fuzzy
@@ -23349,7 +23340,7 @@ msgstr ""
#: scene/3d/occluder.cpp
msgid "No shape is set."
-msgstr ""
+msgstr "Δεν έχει επιλεχθεί Σχήμα."
#: scene/3d/occluder.cpp
msgid "Only uniform scales are supported."
@@ -23452,15 +23443,15 @@ msgstr "ΓÏαμμική"
#: scene/3d/physics_body.cpp
msgid "Angular X"
-msgstr ""
+msgstr "Γωνιώδης Χ"
#: scene/3d/physics_body.cpp
msgid "Angular Y"
-msgstr ""
+msgstr "Γωνιώδης Υ"
#: scene/3d/physics_body.cpp
msgid "Angular Z"
-msgstr ""
+msgstr "Γωνιώδης Ζ"
#: scene/3d/physics_body.cpp
#, fuzzy
@@ -23568,15 +23559,15 @@ msgstr "Κίνηση"
#: scene/3d/physics_body.cpp
msgid "X"
-msgstr ""
+msgstr "Χ"
#: scene/3d/physics_body.cpp
msgid "Y"
-msgstr ""
+msgstr "Î¥"
#: scene/3d/physics_body.cpp
msgid "Z"
-msgstr ""
+msgstr "Ζ"
#: scene/3d/physics_body.cpp
#, fuzzy
@@ -23685,7 +23676,7 @@ msgstr "Αλλαγη ΠαÏαμέτÏου"
#: scene/3d/physics_joint.cpp
msgid "Angular Limit"
-msgstr ""
+msgstr "Γωνιώδης ÎÏιο"
#: scene/3d/physics_joint.cpp
#, fuzzy
@@ -23699,7 +23690,7 @@ msgstr "Πεζά"
#: scene/3d/physics_joint.cpp
msgid "Motor"
-msgstr ""
+msgstr "ΜοτέÏ"
#: scene/3d/physics_joint.cpp
#, fuzzy
@@ -23783,19 +23774,19 @@ msgstr "ΓÏαμμική"
#: scene/3d/physics_joint.cpp
msgid "Equilibrium Point"
-msgstr ""
+msgstr "ΜέÏος ΙσοÏÏοπείας"
#: scene/3d/physics_joint.cpp
msgid "Angular Limit X"
-msgstr ""
+msgstr "Γωνιώδης ÎÏιο Χ"
#: scene/3d/physics_joint.cpp
msgid "Angular Motor X"
-msgstr ""
+msgstr "Γωνιώδης ÎœÎ¿Ï„Î­Ï Î§"
#: scene/3d/physics_joint.cpp
msgid "Angular Spring X"
-msgstr ""
+msgstr "Γωνιώδης ΕλατήÏιο Χ"
#: scene/3d/physics_joint.cpp
#, fuzzy
@@ -23814,15 +23805,15 @@ msgstr "ΓÏαμμική"
#: scene/3d/physics_joint.cpp
msgid "Angular Limit Y"
-msgstr ""
+msgstr "Γωνιώδης ÎÏιο Î¥"
#: scene/3d/physics_joint.cpp
msgid "Angular Motor Y"
-msgstr ""
+msgstr "Γωνιώδης ÎœÎ¿Ï„Î­Ï Î¥"
#: scene/3d/physics_joint.cpp
msgid "Angular Spring Y"
-msgstr ""
+msgstr "Γωνιώδης ΕλατήÏιο Î¥"
#: scene/3d/physics_joint.cpp
#, fuzzy
@@ -23841,15 +23832,15 @@ msgstr "ΓÏαμμική"
#: scene/3d/physics_joint.cpp
msgid "Angular Limit Z"
-msgstr ""
+msgstr "Γωνιώδης ÎÏιο Ζ"
#: scene/3d/physics_joint.cpp
msgid "Angular Motor Z"
-msgstr ""
+msgstr "Γωνιώδης ÎœÎ¿Ï„Î­Ï Î–"
#: scene/3d/physics_joint.cpp
msgid "Angular Spring Z"
-msgstr ""
+msgstr "Γωνιώδης ΕλατήÏιο Ζ"
#: scene/3d/portal.cpp
msgid "The RoomManager should not be a child or grandchild of a Portal."
@@ -23870,7 +23861,7 @@ msgstr "ΕπιστÏοφή"
#: scene/3d/portal.cpp scene/resources/occluder_shape_polygon.cpp
msgid "Two Way"
-msgstr ""
+msgstr "Διπλής ΚατεÏθυνσης"
#: scene/3d/portal.cpp
#, fuzzy
@@ -23903,7 +23894,7 @@ msgstr "Αποσφαλματωτής"
#: scene/3d/ray_cast.cpp scene/resources/style_box.cpp
msgid "Thickness"
-msgstr ""
+msgstr "Πάχος"
#: scene/3d/reflection_probe.cpp scene/main/viewport.cpp
#, fuzzy
@@ -23950,7 +23941,7 @@ msgstr ""
#: scene/3d/room.cpp
msgid "A Room cannot have another Room as a child or grandchild."
-msgstr ""
+msgstr "Ενα δωμάτιο δεν μποÏεί να έχει άλλο δωμάτιο ως παιδί ή εγγόνι."
#: scene/3d/room.cpp
msgid "The RoomManager should not be placed inside a Room."
@@ -23976,7 +23967,7 @@ msgstr ""
#: scene/3d/room.cpp
msgid "Bound"
-msgstr ""
+msgstr "ÎŒÏιο"
#: scene/3d/room_group.cpp
#, fuzzy
@@ -24019,7 +24010,7 @@ msgstr "ΕνέÏγεια"
#: scene/3d/room_manager.cpp
msgid "Roomlist"
-msgstr ""
+msgstr "Λίστα Δωματίων"
#: scene/3d/room_manager.cpp servers/visual_server.cpp
#, fuzzy
@@ -24038,7 +24029,7 @@ msgstr "ΑÏχείο ZIP"
#: scene/3d/room_manager.cpp servers/visual_server.cpp
msgid "Gameplay"
-msgstr ""
+msgstr "Παιχνίδι"
#: scene/3d/room_manager.cpp
#, fuzzy
@@ -25147,7 +25138,7 @@ msgstr ""
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Caret"
-msgstr ""
+msgstr "ΚαÏέ"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
msgid "Blink"
@@ -26123,7 +26114,7 @@ msgstr ""
#: scene/resources/default_theme/default_theme.cpp
msgid "Panel"
-msgstr ""
+msgstr "Πλαίσιο"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -26162,7 +26153,7 @@ msgstr "Επανάληψη κίνησης"
#: scene/resources/default_theme/default_theme.cpp
msgid "Arrow"
-msgstr ""
+msgstr "Βέλος"
#: scene/resources/default_theme/default_theme.cpp
#, fuzzy
@@ -27148,7 +27139,7 @@ msgstr "Αποσφαλμάτωση ÎšÎ±Î½Î±Î»Î¹Î¿Ï UV"
#: scene/resources/environment.cpp
msgid "Blur"
-msgstr ""
+msgstr "Θόλωση"
#: scene/resources/environment.cpp
msgid "Edge Sharpness"
@@ -27770,7 +27761,7 @@ msgstr ""
#: scene/resources/physics_material.cpp
msgid "Absorbent"
-msgstr ""
+msgstr "ΑποÏÏοφητικός"
#: scene/resources/plane_shape.cpp
#, fuzzy
@@ -27815,7 +27806,7 @@ msgstr "Πάνω Δεξιά"
#: scene/resources/primitive_meshes.cpp
msgid "Is Hemisphere"
-msgstr ""
+msgstr "Είναι ΗμισφαίÏιο"
#: scene/resources/primitive_meshes.cpp
#, fuzzy
@@ -27824,11 +27815,11 @@ msgstr "ΔιαίÏεση ΚαμπÏλης"
#: scene/resources/ray_shape.cpp scene/resources/segment_shape_2d.cpp
msgid "Slips On Slope"
-msgstr ""
+msgstr "ΓλυστÏάει σε Κλίση"
#: scene/resources/segment_shape_2d.cpp
msgid "A"
-msgstr ""
+msgstr "Α"
#: scene/resources/shape_2d.cpp
msgid "Custom Solver Bias"
@@ -27856,7 +27847,7 @@ msgstr "Μέγεθος πεÏιγÏάμματος:"
#: scene/resources/sky.cpp
msgid "Panorama"
-msgstr ""
+msgstr "ΠανόÏαμα"
#: scene/resources/sky.cpp
#, fuzzy
@@ -27890,15 +27881,15 @@ msgstr "Αντικατάσταση"
#: scene/resources/sky.cpp
msgid "Longitude"
-msgstr ""
+msgstr "ΓεωγÏαφικό Μήκος"
#: scene/resources/sky.cpp
msgid "Angle Min"
-msgstr ""
+msgstr "Ελάχιστη Γωνία"
#: scene/resources/sky.cpp
msgid "Angle Max"
-msgstr ""
+msgstr "Μέγιστη Γωνία"
#: scene/resources/style_box.cpp
#, fuzzy
@@ -27912,7 +27903,7 @@ msgstr "Ανάπτυξη Όλων"
#: scene/resources/style_box.cpp
msgid "Skew"
-msgstr ""
+msgstr "Λοξότητα"
#: scene/resources/style_box.cpp
#, fuzzy
@@ -27921,7 +27912,7 @@ msgstr "Αλλαγή ΕσωτεÏική Ακτίνας ΤόÏου"
#: scene/resources/style_box.cpp
msgid "Corner Detail"
-msgstr ""
+msgstr "ΛεπτομέÏεια Γωνίας"
#: scene/resources/style_box.cpp
msgid "Anti Aliasing"
@@ -28024,9 +28015,8 @@ msgid "Depth Draw"
msgstr "Μέθοδος παÏεμβολής"
#: scene/resources/visual_shader.cpp
-#, fuzzy
msgid "Cull"
-msgstr "ΛειτουÏγία ΧάÏακα"
+msgstr "Αποκοπή"
#: scene/resources/visual_shader.cpp
#, fuzzy
@@ -28260,11 +28250,11 @@ msgstr ""
#: servers/audio/effects/audio_effect_delay.cpp
msgid "Tap 1"
-msgstr ""
+msgstr "Πάτησε 1"
#: servers/audio/effects/audio_effect_delay.cpp
msgid "Tap 2"
-msgstr ""
+msgstr "Πάτησε 2"
#: servers/audio/effects/audio_effect_delay.cpp
#: servers/audio/effects/audio_effect_phaser.cpp
@@ -28326,7 +28316,7 @@ msgstr ""
#: servers/audio/effects/audio_effect_pitch_shift.cpp
msgid "Oversampling"
-msgstr ""
+msgstr "ΥπεÏδειγματοληψία"
#: servers/audio/effects/audio_effect_pitch_shift.cpp
#: servers/audio/effects/audio_effect_spectrum_analyzer.cpp
diff --git a/editor/translations/en_Shaw.po b/editor/translations/en_Shaw.po
index 60caed0d9d..16e474d82d 100644
--- a/editor/translations/en_Shaw.po
+++ b/editor/translations/en_Shaw.po
@@ -10615,7 +10615,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/eo.po b/editor/translations/eo.po
index 04205e10d6..4ed8103686 100644
--- a/editor/translations/eo.po
+++ b/editor/translations/eo.po
@@ -11199,7 +11199,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/es.po b/editor/translations/es.po
index 5d683058c3..9e1868e4f9 100644
--- a/editor/translations/es.po
+++ b/editor/translations/es.po
@@ -14,7 +14,7 @@
# Diego López <diegodario21@gmail.com>, 2017.
# eon-s <emanuel.segretin@gmail.com>, 2018, 2019, 2020.
# Gustavo Leon <gleondiaz@gmail.com>, 2017-2018.
-# Javier Ocampos <xavier.ocampos@gmail.com>, 2018, 2019, 2020, 2021, 2022.
+# Javier Ocampos <xavier.ocampos@gmail.com>, 2018, 2019, 2020, 2021, 2022, 2023.
# Jose Maria Martinez <josemar1992@hotmail.com>, 2018.
# Juan Quiroga <juanquiroga9@gmail.com>, 2017.
# Kiji Pixel <raccoon.fella@gmail.com>, 2017.
@@ -90,14 +90,15 @@
# M3CG <cgmario1999@gmail.com>, 2022.
# Chalan <Valentin06ch@outlook.com>, 2022.
# Luis Miguel Soto Sánchez <luismiguelsoto@jerez.es>, 2022.
-# Victor Stancioiu <victorstancioiu@gmail.com>, 2022.
+# Victor Stancioiu <victorstancioiu@gmail.com>, 2022, 2023.
+# Daniel Miranda <danmiranda@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-11-16 22:47+0000\n"
-"Last-Translator: Javier Ocampos <xavier.ocampos@gmail.com>\n"
+"PO-Revision-Date: 2023-01-20 10:19+0000\n"
+"Last-Translator: Daniel Miranda <danmiranda@gmail.com>\n"
"Language-Team: Spanish <https://hosted.weblate.org/projects/godot-engine/"
"godot/es/>\n"
"Language: es\n"
@@ -105,7 +106,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.15-dev\n"
+"X-Generator: Weblate 4.15.1\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -11041,7 +11042,7 @@ msgstr "Perspectiva Trasera"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portales activos]"
@@ -14308,17 +14309,15 @@ msgid "Invalid project path (changed anything?)."
msgstr "La ruta del proyecto no es correcta (¿has cambiado algo?)."
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
msgstr ""
-"No se pudo cargar project.godot desde la ruta de proyecto (error %d). La "
-"ruta no existe o está corrupta."
+"No se pudo cargar el proyecto desde la ruta '%s' (error %d). La ruta no "
+"existe o está corrupta."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Couldn't save project at '%s' (error %d)."
-msgstr "No se puede abrir el proyecto en '%s'."
+msgstr "No se pudo guardar el proyecto en '%s' (error %d)."
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
@@ -22304,7 +22303,7 @@ msgstr ""
#: scene/3d/mesh_instance.cpp
msgid "Transform Normals"
-msgstr "Transformar Normales"
+msgstr "Normales de Transformación"
#: scene/3d/navigation.cpp
msgid ""
@@ -23243,14 +23242,12 @@ msgid "AABB"
msgstr "AABB"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Sorting"
msgstr "Ordenar"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Use AABB Center"
-msgstr "Usar Ambiente"
+msgstr "Usar Centro de AABB"
#: scene/3d/visual_instance.cpp scene/resources/navigation_mesh.cpp
msgid "Geometry"
@@ -25064,7 +25061,7 @@ msgstr "Marcar"
#: scene/resources/default_theme/default_theme.cpp
msgid "Updown"
-msgstr ""
+msgstr "Reducción"
#: scene/resources/default_theme/default_theme.cpp
msgid "Scaleborder Size"
@@ -25544,11 +25541,11 @@ msgstr "Grados de Rotación del Cielo"
#: scene/resources/environment.cpp
msgid "Canvas Max Layer"
-msgstr ""
+msgstr "Max de Capas del Lienzo"
#: scene/resources/environment.cpp scene/resources/texture.cpp
msgid "Camera Feed ID"
-msgstr ""
+msgstr "Feed ID de la Cámara"
#: scene/resources/environment.cpp
msgid "Ambient Light"
@@ -25688,7 +25685,7 @@ msgstr "Nitidez de Borde"
#: scene/resources/environment.cpp
msgid "DOF Far Blur"
-msgstr ""
+msgstr "DOF Desenfoque Lejano"
#: scene/resources/environment.cpp scene/resources/material.cpp
msgid "Distance"
@@ -25700,7 +25697,7 @@ msgstr "Transición"
#: scene/resources/environment.cpp
msgid "DOF Near Blur"
-msgstr ""
+msgstr "DOF Desenfoque Cercano"
#: scene/resources/environment.cpp
msgid "Glow"
@@ -25760,7 +25757,7 @@ msgstr "Escala HDR"
#: scene/resources/environment.cpp
msgid "Bicubic Upscale"
-msgstr ""
+msgstr "Escala Bicúbica Superior"
#: scene/resources/environment.cpp
msgid "Adjustments"
@@ -25816,7 +25813,7 @@ msgstr "Siguiente Paso"
#: scene/resources/material.cpp
msgid "Use Shadow To Opacity"
-msgstr ""
+msgstr "Usar Sombra para Opacidad"
#: scene/resources/material.cpp
msgid "Unshaded"
@@ -26655,15 +26652,15 @@ msgstr "Mezcla"
#: servers/audio/effects/audio_effect_compressor.cpp
msgid "Sidechain"
-msgstr ""
+msgstr "Sidechain"
#: servers/audio/effects/audio_effect_delay.cpp
msgid "Tap 1"
-msgstr "Toque 1"
+msgstr "Tap 1"
#: servers/audio/effects/audio_effect_delay.cpp
msgid "Tap 2"
-msgstr "Toque 2"
+msgstr "Tap 2"
#: servers/audio/effects/audio_effect_delay.cpp
#: servers/audio/effects/audio_effect_phaser.cpp
@@ -26681,7 +26678,7 @@ msgstr "Pre-Ganancia"
#: servers/audio/effects/audio_effect_distortion.cpp
msgid "Keep Hf Hz"
-msgstr "Mantener Hz Altas"
+msgstr "Mantener Hf Hz"
#: servers/audio/effects/audio_effect_distortion.cpp
msgid "Drive"
@@ -26697,19 +26694,19 @@ msgstr "Resonancia"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Ceiling dB"
-msgstr "dB Tope"
+msgstr "Límite de dB"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Threshold dB"
-msgstr "Umbral dB"
+msgstr "Umbral de dB"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Soft Clip dB"
-msgstr ""
+msgstr "Soft Clip dB"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Soft Clip Ratio"
-msgstr ""
+msgstr "Soft Clip Ratio"
#: servers/audio/effects/audio_effect_phaser.cpp
msgid "Range Min Hz"
@@ -26721,7 +26718,7 @@ msgstr "Rango Hz Máximo"
#: servers/audio/effects/audio_effect_pitch_shift.cpp
msgid "Oversampling"
-msgstr "Sobremuestreo"
+msgstr "Oversampling"
#: servers/audio/effects/audio_effect_pitch_shift.cpp
#: servers/audio/effects/audio_effect_spectrum_analyzer.cpp
@@ -26730,7 +26727,7 @@ msgstr "Tamaño de FFT"
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Predelay"
-msgstr ""
+msgstr "Retraso"
#: servers/audio/effects/audio_effect_reverb.cpp
msgid "Msec"
@@ -27050,7 +27047,7 @@ msgstr ""
#: servers/visual_server.cpp
msgid "Disable For Vendors"
-msgstr ""
+msgstr "Deshabilitar para Proveedores"
#: servers/visual_server.cpp
msgid "Anisotropic Filter Level"
@@ -27182,7 +27179,7 @@ msgstr "Usar PVS Simple"
#: servers/visual_server.cpp
msgid "PVS Logging"
-msgstr ""
+msgstr "Registro de PVS"
#: servers/visual_server.cpp
msgid "Use Signals"
diff --git a/editor/translations/es_AR.po b/editor/translations/es_AR.po
index fdb6b4f00d..24d38e14a7 100644
--- a/editor/translations/es_AR.po
+++ b/editor/translations/es_AR.po
@@ -22,13 +22,14 @@
# emnrx <emanuelermancia@gmail.com>, 2022.
# Mau_Restor <restor@gmail.com>, 2022.
# Leonardo Martínez <leonardomartinez85@gmail.com>, 2022.
+# LR <nancok@tuta.io>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-11-26 14:36+0000\n"
-"Last-Translator: emnrx <emanuelermancia@gmail.com>\n"
+"PO-Revision-Date: 2023-01-01 05:48+0000\n"
+"Last-Translator: LR <nancok@tuta.io>\n"
"Language-Team: Spanish (Argentina) <https://hosted.weblate.org/projects/"
"godot-engine/godot/es_AR/>\n"
"Language: es_AR\n"
@@ -36,7 +37,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -286,11 +287,11 @@ msgstr ""
#: core/io/packet_peer.cpp
msgid "Input Buffer Max Size"
-msgstr ""
+msgstr "Tamaño maximo del bufer de entrada"
#: core/io/packet_peer.cpp
msgid "Output Buffer Max Size"
-msgstr ""
+msgstr "Tamaño maximo del buffer de salida"
#: core/io/packet_peer.cpp
msgid "Stream Peer"
@@ -505,8 +506,9 @@ msgid "Strength"
msgstr "Fuerza"
#: core/os/input_event.cpp
+#, fuzzy
msgid "Delta"
-msgstr ""
+msgstr "Delta"
#: core/os/input_event.cpp
msgid "Channel"
@@ -721,7 +723,7 @@ msgstr "Superior Derecha"
#: core/project_settings.cpp
msgid "UI Up"
-msgstr ""
+msgstr "Interfaz Arriba"
#: core/project_settings.cpp
#, fuzzy
@@ -735,7 +737,7 @@ msgstr "Página: "
#: core/project_settings.cpp
msgid "UI Page Down"
-msgstr ""
+msgstr "Interfaz Bajar Pagina"
#: core/project_settings.cpp
msgid "UI Home"
@@ -1013,7 +1015,7 @@ msgstr "Usar Muestreo Bicúbico"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Renderable Elements"
-msgstr ""
+msgstr "Cantidad Maxima de Elementos Renderizables"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Renderable Lights"
@@ -11251,7 +11253,7 @@ msgstr "Perspectiva Trasera"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portales activos]"
diff --git a/editor/translations/et.po b/editor/translations/et.po
index dc36ae0b94..c08335ed4f 100644
--- a/editor/translations/et.po
+++ b/editor/translations/et.po
@@ -8,19 +8,20 @@
# René <renepiik@gmail.com>, 2020.
# Kritzmensch <streef.gtx@gmail.com>, 2021, 2022.
# dogyx <aaronloit@zohomail.eu>, 2022.
+# Oskar U <oskar.unn2003@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-09-16 07:12+0000\n"
-"Last-Translator: dogyx <aaronloit@zohomail.eu>\n"
+"PO-Revision-Date: 2023-01-08 09:47+0000\n"
+"Last-Translator: Oskar U <oskar.unn2003@gmail.com>\n"
"Language-Team: Estonian <https://hosted.weblate.org/projects/godot-engine/"
"godot/et/>\n"
"Language: et\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.14.1-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -9377,18 +9378,18 @@ msgstr "Lülita jagamisrežiim sisse/välja"
#: scene/gui/rich_text_label.cpp scene/gui/text_edit.cpp
#: scene/resources/primitive_meshes.cpp
msgid "Text"
-msgstr ""
+msgstr "Tekst"
#: editor/plugins/item_list_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp main/main.cpp
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
#: scene/gui/button.cpp scene/gui/item_list.cpp
msgid "Icon"
-msgstr ""
+msgstr "Ikoon"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "ID"
-msgstr ""
+msgstr "ID"
#: editor/plugins/item_list_editor_plugin.cpp
#: scene/resources/default_theme/default_theme.cpp
@@ -10857,7 +10858,7 @@ msgstr "Perspektiiv"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/eu.po b/editor/translations/eu.po
index 79da3d56fb..bfd4302fa8 100644
--- a/editor/translations/eu.po
+++ b/editor/translations/eu.po
@@ -10820,7 +10820,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/fa.po b/editor/translations/fa.po
index ad2a56e408..eb6c113057 100644
--- a/editor/translations/fa.po
+++ b/editor/translations/fa.po
@@ -28,7 +28,7 @@
# Aryan Azadeh <aryan@azadeh.email>, 2022.
# Mitsuha Miamizu <mitsuha.miamizu4444@gmail.com>, 2022.
# LordProfo <nimaentity30@gmail.com>, 2022.
-# LordProfo (Nima) <nimaentity30@gmail.com>, 2022.
+# LordProfo (Nima) <nimaentity30@gmail.com>, 2022, 2023.
# John Smith <pkafsharix@gmail.com>, 2022.
# Ali Jafari <ali.jafari.sn@gmail.com>, 2022.
# Ali Almasi <A710almasi@gmail.com>, 2022.
@@ -38,8 +38,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-11-16 22:47+0000\n"
-"Last-Translator: 2g.2d.2t <2g.2d.2t@gmail.com>\n"
+"PO-Revision-Date: 2023-01-01 05:48+0000\n"
+"Last-Translator: LordProfo (Nima) <nimaentity30@gmail.com>\n"
"Language-Team: Persian <https://hosted.weblate.org/projects/godot-engine/"
"godot/fa/>\n"
"Language: fa\n"
@@ -47,7 +47,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -2901,7 +2901,7 @@ msgstr "انتخاب حالت"
#: editor/editor_export.cpp
msgid "BPTC"
-msgstr ""
+msgstr "بی‌پی‌تی‌سی (BPTC)"
#: editor/editor_export.cpp platform/osx/export/export.cpp
msgid "S3TC"
@@ -2909,11 +2909,11 @@ msgstr "S3TC"
#: editor/editor_export.cpp platform/osx/export/export.cpp
msgid "ETC"
-msgstr "ای‌تی‌سی"
+msgstr "ئی‌تی‌سی (ETC)"
#: editor/editor_export.cpp platform/osx/export/export.cpp
msgid "ETC2"
-msgstr "ای‌تی‌سی‌۲"
+msgstr "ئی‌تی‌سی‌۲ (ETC2)"
#: editor/editor_export.cpp
msgid "No BPTC Fallbacks"
@@ -2964,7 +2964,7 @@ msgstr "تبدیل منابع متنی به دوتایی هنگام خروجی"
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
-msgstr "ویرایشگر 3بعدی"
+msgstr "ویرایشگر ۳بعدی"
#: editor/editor_feature_profile.cpp
msgid "Script Editor"
@@ -3801,13 +3801,15 @@ msgstr "ایجاد بند انگشتی"
#: editor/editor_node.cpp
msgid "This operation can't be done without a tree root."
-msgstr ""
+msgstr "این عمل را نمی‌توان بدون tree root انجام داد."
#: 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 ""
+"این صحنه را نمی‌توان ذخیره کرد زیرا یک شامل نمونه‌سازی چرخه‌ای وجود دارد.\n"
+" لطÙاً آن را حل کنید Ùˆ سپس دوباره سعی کنید ذخیره کنید."
#: editor/editor_node.cpp
msgid ""
@@ -3873,6 +3875,9 @@ msgid ""
"Please read the documentation relevant to importing scenes to better "
"understand this workflow."
msgstr ""
+"این منبع متعلق به صحنه‌ای است که ایمپورت شده است، بنابراین قابل ویرایش نیست.\n"
+" لطÙاً اسناد مربوط به وارد کردن صحنه‌ها را بخوانید تا این گردش کار را بهتر درک "
+"کنید."
#: editor/editor_node.cpp
msgid ""
@@ -6913,7 +6918,7 @@ msgstr ""
#: editor/import/editor_import_collada.cpp
msgid "Collada"
-msgstr ""
+msgstr "کولادا"
#: editor/import/editor_import_collada.cpp
msgid "Use Ambient"
@@ -11203,7 +11208,7 @@ msgstr ""
msgid " [auto]"
msgstr " [خودکار]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
@@ -17129,9 +17134,8 @@ msgid "Add an architecture entry"
msgstr ""
#: modules/gdnative/gdnative_library_editor_plugin.cpp
-#, fuzzy
msgid "GDNativeLibrary"
-msgstr "صادکردن Ùایل کتابخانه ای"
+msgstr "کتابخانهٔ جی‌دی‌نÙیتیو"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Enabled GDNative Singleton"
@@ -18580,25 +18584,24 @@ msgid "Mod %s"
msgstr ""
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "ShiftLeft %s"
-msgstr "تنظیم %s"
+msgstr "ShiftLeft %s"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "ShiftRight %s"
-msgstr ""
+msgstr "ShiftRight %s"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "BitAnd %s"
-msgstr ""
+msgstr "BitAnd %s"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "BitOr %s"
-msgstr ""
+msgstr "BitOr %s"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "BitXor %s"
-msgstr ""
+msgstr "BitXor %s"
#: modules/visual_script/visual_script_func_nodes.cpp
#, fuzzy
@@ -18730,9 +18733,8 @@ msgid "Get Self"
msgstr ""
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "CustomNode"
-msgstr "ساختن گره"
+msgstr "نود سÙارشی"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
@@ -18748,9 +18750,8 @@ msgstr ""
"(error) باشد."
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "SubCall"
-msgstr "Ùراخوانی"
+msgstr "ساب‌کال"
#: modules/visual_script/visual_script_nodes.cpp scene/gui/graph_node.cpp
msgid "Title"
@@ -18791,7 +18792,7 @@ msgstr ""
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "Wait"
-msgstr ""
+msgstr "صبرکردن"
#: modules/visual_script/visual_script_yield_nodes.cpp
#, fuzzy
@@ -20516,7 +20517,7 @@ msgstr "انتقال را در انیمیشن تغییر بده"
#: platform/uwp/export/export.cpp
msgid "Landscape"
-msgstr ""
+msgstr "چشم‌انداز"
#: platform/uwp/export/export.cpp
msgid "Portrait"
@@ -20826,7 +20827,7 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid "Wine"
-msgstr ""
+msgstr "شراب"
#: platform/x11/export/export.cpp
msgid "32-bit executables cannot have embedded data >= 4 GiB."
@@ -22586,7 +22587,7 @@ msgstr ""
#: scene/3d/camera.cpp scene/3d/light.cpp scene/3d/reflection_probe.cpp
msgid "Cull Mask"
-msgstr ""
+msgstr "Cull Mask"
#: scene/3d/camera.cpp
#, fuzzy
@@ -26677,7 +26678,7 @@ msgstr ""
#: scene/resources/environment.cpp
msgid "Blur"
-msgstr ""
+msgstr "بلوری"
#: scene/resources/environment.cpp
msgid "Edge Sharpness"
@@ -27530,9 +27531,8 @@ msgid "Depth Draw"
msgstr "حالت درون یابی(درون‌یابی روشی است برای یاÙتن مقدار تابع درون یک بازه)"
#: scene/resources/visual_shader.cpp
-#, fuzzy
msgid "Cull"
-msgstr "انتخاب حالت"
+msgstr "Cull"
#: scene/resources/visual_shader.cpp
#, fuzzy
@@ -27735,9 +27735,8 @@ msgstr "سطح دسی‌بل"
#: servers/audio/effects/audio_effect_chorus.cpp
#: servers/audio/effects/audio_effect_delay.cpp
#: servers/audio/effects/audio_effect_panner.cpp
-#, fuzzy
msgid "Pan"
-msgstr "بسته بندی"
+msgstr "Pan"
#: servers/audio/effects/audio_effect_compressor.cpp
#: servers/audio/effects/audio_effect_filter.cpp
diff --git a/editor/translations/fi.po b/editor/translations/fi.po
index 8aeba71bff..96267c77e3 100644
--- a/editor/translations/fi.po
+++ b/editor/translations/fi.po
@@ -11269,7 +11269,7 @@ msgstr "Takaperspektiivi"
msgid " [auto]"
msgstr " [automaattinen]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portaalit aktiivisia]"
diff --git a/editor/translations/fil.po b/editor/translations/fil.po
index 71673d8255..2b6aa3a671 100644
--- a/editor/translations/fil.po
+++ b/editor/translations/fil.po
@@ -10674,7 +10674,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/fr.po b/editor/translations/fr.po
index 17063caae8..f6b1b5d1c9 100644
--- a/editor/translations/fr.po
+++ b/editor/translations/fr.po
@@ -105,14 +105,17 @@
# SCHUTZ Lucas <lucas.schutz0954@gmail.com>, 2022.
# EGuillemot <Elouen.Guillemot@gmail.com>, 2022.
# Entiz <maxime.salido@gmail.com>, 2022.
-# Callim Ethee <callimethee@gmail.com>, 2022.
+# Callim Ethee <callimethee@gmail.com>, 2022, 2023.
+# Hugo Berthet-Rambaud <hugoberthetrambaud@outlook.com>, 2023.
+# Nathan Chambrette <n.chambrette@gmail.com>, 2023.
+# slundi <slundi@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-10-10 18:06+0000\n"
-"Last-Translator: Helix Sir <vincentbarkmann@gmail.com>\n"
+"PO-Revision-Date: 2023-01-14 00:01+0000\n"
+"Last-Translator: slundi <slundi@gmail.com>\n"
"Language-Team: French <https://hosted.weblate.org/projects/godot-engine/"
"godot/fr/>\n"
"Language: fr\n"
@@ -120,7 +123,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.14.1\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -325,7 +328,7 @@ msgstr "Pré-lecture de page"
#: core/io/http_client.cpp
msgid "Blocking Mode Enabled"
-msgstr "Mode De Blocage Activé"
+msgstr "Mode de blocage activé"
#: core/io/http_client.cpp
msgid "Connection"
@@ -333,11 +336,11 @@ msgstr "Connexion"
#: core/io/http_client.cpp
msgid "Read Chunk Size"
-msgstr "Taile des tronçons de lecture"
+msgstr "Lire la taille des fragment(s)"
#: core/io/marshalls.cpp
msgid "Object ID"
-msgstr "ID de l'Objet"
+msgstr "Identifiant de l'Objet"
#: core/io/multiplayer_api.cpp core/io/packet_peer.cpp
msgid "Allow Object Decoding"
@@ -596,7 +599,7 @@ msgstr "Message"
#: core/os/input_event.cpp
msgid "Pitch"
-msgstr "Pitch"
+msgstr "Angle d'attaque"
#: core/os/input_event.cpp scene/2d/cpu_particles_2d.cpp
#: scene/2d/physics_body_2d.cpp scene/3d/cpu_particles.cpp
@@ -606,7 +609,7 @@ msgstr "Vélocité"
#: core/os/input_event.cpp
msgid "Instrument"
-msgstr "Instrument"
+msgstr "Appareil"
#: core/os/input_event.cpp
msgid "Controller Number"
@@ -5904,7 +5907,6 @@ msgid "Zoom Modifier"
msgstr "Touche de combinaison : Zoom"
#: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Warped Mouse Panning"
msgstr "Panoramique déformé de la souris"
@@ -8843,15 +8845,15 @@ msgstr "Centré à Gauche"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Top"
-msgstr "Centrée en Haut"
+msgstr "Centré en Haut"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Right"
-msgstr "Centrée à droite"
+msgstr "Centré à droite"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Bottom"
-msgstr "Centrée en bas"
+msgstr "Centré en bas"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center"
@@ -11083,7 +11085,7 @@ msgstr "Perspective arrière"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portails actifs]"
@@ -16833,7 +16835,7 @@ msgstr "Ajouter une entrée architecture"
#: modules/gdnative/gdnative_library_editor_plugin.cpp
msgid "GDNativeLibrary"
-msgstr "GDNativeLibrary"
+msgstr "Bibliothèque Native GD"
#: modules/gdnative/gdnative_library_singleton_editor.cpp
msgid "Enabled GDNative Singleton"
@@ -17153,7 +17155,6 @@ msgid "Specular Factor"
msgstr "Facteur Spéculaire"
#: modules/gltf/gltf_spec_gloss.cpp
-#, fuzzy
msgid "Spec Gloss Img"
msgstr "Img Spéculaire Brillante"
@@ -18172,23 +18173,23 @@ msgstr "Module de %s"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "ShiftLeft %s"
-msgstr "Décalage %s vers la gauche"
+msgstr "Déplacer Vers la Gauche"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "ShiftRight %s"
-msgstr "Décaler %s vers la droite"
+msgstr "Déplacer vers la Droite"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "BitAnd %s"
-msgstr "Et par bit %s"
+msgstr "ET Binaire"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "BitOr %s"
-msgstr "Ou par bit %s"
+msgstr "OU Binaire"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "BitXor %s"
-msgstr "Ou-exclusif par bit %s"
+msgstr "OU Exclusif Binaire"
#: modules/visual_script/visual_script_func_nodes.cpp
msgid "Set Mode"
@@ -18303,7 +18304,7 @@ msgstr "Récupérer Self"
#: modules/visual_script/visual_script_nodes.cpp
msgid "CustomNode"
-msgstr "Nœud Personnalisé"
+msgstr "Noeud Personalisé"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
@@ -18357,7 +18358,7 @@ msgstr "Yield"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "Wait"
-msgstr "Wait"
+msgstr "Attente/Attendre"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "Next Frame"
@@ -19267,7 +19268,7 @@ msgstr "Projecteur 80 X 80"
#: platform/iphone/export/export.cpp
msgid "Storyboard"
-msgstr "Storyboard"
+msgstr "Story-board"
#: platform/iphone/export/export.cpp
msgid "Use Launch Screen Storyboard"
@@ -20272,15 +20273,14 @@ msgid "Could not find wine executable at \"%s\"."
msgstr "Impossible de trouver wine à l'emplacement \"%s\"."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid ""
"Could not start rcedit executable. Configure rcedit path in the Editor "
"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
"Resources\" in the export preset."
msgstr ""
-"L'outil « rcedit » doit être configuré dans les préférences de l'éditeur "
-"(Exporter > Windows > Rcedit) for modifier l'icône ou les informations de "
-"l'application."
+"Impossible de démarrer l'exécutable rcedit. Configurez le chemin vers rcedit "
+"dans les réglages de l'éditeur (Exporter > Windows > Rcedit), ou désactivez "
+"\"Application > Modifier les Ressources\" dans les préréglages de l'export."
#: platform/windows/export/export.cpp
msgid "rcedit failed to modify executable: %s."
@@ -20303,15 +20303,14 @@ msgid "Invalid timestamp server."
msgstr "Server d'horodatage invalide."
#: platform/windows/export/export.cpp
-#, fuzzy
msgid ""
"Could not start signtool executable. Configure signtool path in the Editor "
"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
"export preset."
msgstr ""
-"L'outil « rcedit » doit être configuré dans les préférences de l'éditeur "
-"(Exporter > Windows > Rcedit) for modifier l'icône ou les informations de "
-"l'application."
+"Impossible de démarrer l'exécutable signtool. Configurez le chemin vers "
+"signtool dans les réglages de l'éditeur (Exporter > Windows > Signtool) ou "
+"désactivez \"Codesign\" dans les préréglages de l'export."
#: platform/windows/export/export.cpp
msgid "Signtool failed to sign executable: %s."
@@ -20567,14 +20566,12 @@ msgid "Draw Margin"
msgstr "Afficher les marges"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Drag Margin H Enabled"
-msgstr "Définir la marge"
+msgstr "Marge de tirage H activée"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Drag Margin V Enabled"
-msgstr "Définir la marge"
+msgstr "Marge de tirage V activée"
#: scene/2d/camera_2d.cpp
msgid "Smoothing"
@@ -20589,9 +20586,8 @@ msgid "V"
msgstr "V"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Drag Margin"
-msgstr "Tirer la marge"
+msgstr "Marge Tirage"
#: scene/2d/camera_2d.cpp
msgid "Draw Screen"
@@ -20602,9 +20598,8 @@ msgid "Draw Limits"
msgstr "Afficher les limites"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Draw Drag Margin"
-msgstr "Définir la marge"
+msgstr "Dessiner la marge de tirage"
#: scene/2d/canvas_item.cpp scene/resources/environment.cpp
#: scene/resources/material.cpp
@@ -21633,9 +21628,8 @@ msgid "Internal Vertex Count"
msgstr "Nombre de Sommet Interne"
#: scene/2d/position_2d.cpp
-#, fuzzy
msgid "Gizmo Extents"
-msgstr "Gadgets"
+msgstr "Etendues des Gadgets"
#: scene/2d/ray_cast_2d.cpp scene/3d/ray_cast.cpp
msgid "Exclude Parent"
@@ -23258,9 +23252,8 @@ msgid "Gizmo"
msgstr "Gizmo"
#: scene/3d/spatial_velocity_tracker.cpp
-#, fuzzy
msgid "Track Physics Step"
-msgstr "Image physique %"
+msgstr "Suivre les Etapes Physiques"
#: scene/3d/spring_arm.cpp
msgid "Spring Length"
@@ -23682,9 +23675,8 @@ msgid "Group"
msgstr "Groupe"
#: scene/gui/button.cpp scene/gui/label.cpp
-#, fuzzy
msgid "Clip Text"
-msgstr "Copier le texte"
+msgstr "Découper le texte"
#: scene/gui/button.cpp scene/gui/label.cpp scene/gui/line_edit.cpp
#: scene/gui/spin_box.cpp
@@ -23696,9 +23688,8 @@ msgid "Icon Align"
msgstr "Aligner l'icône"
#: scene/gui/button.cpp
-#, fuzzy
msgid "Expand Icon"
-msgstr "Développer tout"
+msgstr "Développer l'icône"
#: scene/gui/center_container.cpp
msgid "Use Top Left"
@@ -23795,9 +23786,8 @@ msgid "Pivot Offset"
msgstr "Décalage du Pivot"
#: scene/gui/control.cpp
-#, fuzzy
msgid "Clip Content"
-msgstr "Constante de classe"
+msgstr "Découper le contenu"
#: scene/gui/control.cpp scene/resources/visual_shader_nodes.cpp
msgid "Hint"
@@ -23845,7 +23835,7 @@ msgstr "Forme de Curseur par Défaut"
#: scene/gui/control.cpp
msgid "Pass On Modal Close Click"
-msgstr ""
+msgstr "Transmettre Clic de Fermeture du Mode"
#: scene/gui/control.cpp
msgid "Size Flags"
@@ -23856,9 +23846,8 @@ msgid "Stretch Ratio"
msgstr "Ratio d’étirement"
#: scene/gui/control.cpp
-#, fuzzy
msgid "Theme Type Variation"
-msgstr "Propriétés du thème"
+msgstr "Variation du Type du Thème"
#: scene/gui/dialogs.cpp
msgid "Window Title"
@@ -23881,18 +23870,16 @@ msgid "Please Confirm..."
msgstr "Veuillez confirmer…"
#: scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Mode Overrides Title"
-msgstr "Remplacer l'item"
+msgstr "Le Mode remplace le Titre"
#: scene/gui/file_dialog.cpp
msgid "Must use a valid extension."
msgstr "Utilisez une extension valide."
#: scene/gui/graph_edit.cpp
-#, fuzzy
msgid "Right Disconnects"
-msgstr "Déconnecter"
+msgstr "La droite déconnecte"
#: scene/gui/graph_edit.cpp
msgid "Scroll Offset"
@@ -23928,9 +23915,8 @@ msgid "Enable grid minimap."
msgstr "Activer l'alignement."
#: scene/gui/graph_node.cpp
-#, fuzzy
msgid "Show Close"
-msgstr "Afficher les os"
+msgstr "Afficher la Fermeture"
#: scene/gui/graph_node.cpp scene/gui/option_button.cpp
#: scene/resources/default_theme/default_theme.cpp
@@ -23959,23 +23945,20 @@ msgid "Incremental Search Max Interval Msec"
msgstr "Intervalle max de recherche incrémentale (ms)"
#: scene/gui/item_list.cpp scene/gui/tree.cpp
-#, fuzzy
msgid "Allow Reselect"
-msgstr "Appliquer la réinitialisation"
+msgstr "Autoriser la Resélection"
#: scene/gui/item_list.cpp scene/gui/tree.cpp
-#, fuzzy
msgid "Allow RMB Select"
-msgstr "Remplir la sélection"
+msgstr "Autoriser la sélection par click droit"
#: scene/gui/item_list.cpp
msgid "Max Text Lines"
msgstr "Lignes de texte max"
#: scene/gui/item_list.cpp
-#, fuzzy
msgid "Auto Height"
-msgstr "En période de test"
+msgstr "Hauteur Auto"
#: scene/gui/item_list.cpp
msgid "Max Columns"
@@ -23994,23 +23977,20 @@ msgid "Icon Scale"
msgstr "Échelle de l'Icône"
#: scene/gui/item_list.cpp
-#, fuzzy
msgid "Fixed Icon Size"
-msgstr "Vue de devant"
+msgstr "Taille d'Icône Fixe"
#: scene/gui/label.cpp
-#, fuzzy
msgid "V Align"
-msgstr "Assigner"
+msgstr "Alignement V"
#: scene/gui/label.cpp scene/gui/rich_text_label.cpp
msgid "Visible Characters"
msgstr "Caractères visibles"
#: scene/gui/label.cpp scene/gui/rich_text_label.cpp
-#, fuzzy
msgid "Percent Visible"
-msgstr "Rendre visible"
+msgstr "Pourcentage visible"
#: scene/gui/label.cpp
msgid "Lines Skipped"
@@ -24037,34 +24017,28 @@ msgid "Expand To Text Length"
msgstr "Etendre à la longueur du texte"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Context Menu Enabled"
-msgstr "Aide contextuelle"
+msgstr "Menu Contextuel Activé"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Virtual Keyboard Enabled"
-msgstr "Filtrer les signaux"
+msgstr "Clavier Virtuel Activé"
#: scene/gui/line_edit.cpp
-#, fuzzy
msgid "Clear Button Enabled"
-msgstr "Filtrer les signaux"
+msgstr "Bouton de Nettoyage Activé"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Shortcut Keys Enabled"
-msgstr "Raccourcis"
+msgstr "Raccourcis activés"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Middle Mouse Paste Enabled"
-msgstr "Filtrer les signaux"
+msgstr "Collage avec le bouton central de la souris activé"
#: scene/gui/line_edit.cpp scene/gui/text_edit.cpp
-#, fuzzy
msgid "Selecting Enabled"
-msgstr "Sélection uniquement"
+msgstr "Sélection Activée"
#: scene/gui/line_edit.cpp scene/gui/rich_text_label.cpp
#: scene/gui/text_edit.cpp
@@ -24072,14 +24046,12 @@ msgid "Deselect On Focus Loss Enabled"
msgstr "Déselection à la perte de focus activée"
#: scene/gui/line_edit.cpp
-#, fuzzy
msgid "Right Icon"
-msgstr "Bouton droit"
+msgstr "Icône droite"
#: scene/gui/line_edit.cpp
-#, fuzzy
msgid "Placeholder"
-msgstr "Charger en tant qu'instance temporaire"
+msgstr "Substitut temporaire"
#: scene/gui/line_edit.cpp
msgid "Alpha"
@@ -24102,24 +24074,20 @@ msgid "Underline"
msgstr "Souligner"
#: scene/gui/menu_button.cpp
-#, fuzzy
msgid "Switch On Hover"
-msgstr "Switch"
+msgstr "Chnager au Survol"
#: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "Draw Center"
-msgstr "Centre"
+msgstr "Dessiner le Centre"
#: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "Region Rect"
-msgstr "Définir région rectangulaire"
+msgstr "Zone Rectangulaire"
#: scene/gui/nine_patch_rect.cpp
-#, fuzzy
msgid "Patch Margin"
-msgstr "Définir la marge"
+msgstr "Marge de patch"
#: scene/gui/nine_patch_rect.cpp scene/resources/style_box.cpp
msgid "Axis Stretch"
@@ -24138,7 +24106,6 @@ msgstr ""
"un étirement."
#: scene/gui/popup.cpp
-#, fuzzy
msgid "Popup"
msgstr "Fenêtre contextuelle"
@@ -24170,9 +24137,8 @@ msgid "Hide On State Item Selection"
msgstr "Cacher lors de la sélection de l'élément d'état"
#: scene/gui/popup_menu.cpp
-#, fuzzy
msgid "Submenu Popup Delay"
-msgstr "Délai du pop-up du sous-menu"
+msgstr "Délai de pop-up du sous-menu"
#: scene/gui/popup_menu.cpp
msgid "Allow Search"
@@ -24205,9 +24171,8 @@ msgid "Exp Edit"
msgstr "Édition Exponentielle"
#: scene/gui/range.cpp
-#, fuzzy
msgid "Rounded"
-msgstr "Arrondir"
+msgstr "Arrondi"
#: scene/gui/range.cpp
msgid "Allow Greater"
@@ -24238,9 +24203,8 @@ msgid "Elapsed Time"
msgstr "Temps Écoulé"
#: scene/gui/rich_text_effect.cpp
-#, fuzzy
msgid "Env"
-msgstr "Fin"
+msgstr "Alentours"
#: scene/gui/rich_text_effect.cpp
msgid "Character"
@@ -24298,18 +24262,16 @@ msgstr ""
"définissez manuellement la taille minimale personnalisée."
#: scene/gui/scroll_container.cpp
-#, fuzzy
msgid "Follow Focus"
-msgstr "Remplir la surface"
+msgstr "Suivre le focus"
#: scene/gui/scroll_container.cpp
msgid "Horizontal Enabled"
msgstr "Horizontal Activé"
#: scene/gui/scroll_container.cpp
-#, fuzzy
msgid "Vertical Enabled"
-msgstr "Filtrer les signaux"
+msgstr "Vertical Activé"
#: scene/gui/scroll_container.cpp
msgid "Default Scroll Deadzone"
@@ -24320,9 +24282,8 @@ msgid "Scrollable"
msgstr "Défilant"
#: scene/gui/slider.cpp
-#, fuzzy
msgid "Tick Count"
-msgstr "Prélever une couleur"
+msgstr "Compte des Tics"
#: scene/gui/slider.cpp
msgid "Ticks On Borders"
@@ -24341,14 +24302,12 @@ msgid "Split Offset"
msgstr "Décalage des écarts"
#: scene/gui/split_container.cpp scene/gui/tree.cpp
-#, fuzzy
msgid "Collapsed"
-msgstr "Réduire tout"
+msgstr "Réduit"
#: scene/gui/split_container.cpp
-#, fuzzy
msgid "Dragger Visibility"
-msgstr "Basculer la visibilité"
+msgstr "Visibilité du Tireur"
#: scene/gui/tab_container.cpp scene/gui/tabs.cpp
msgid "Tab Align"
@@ -24359,9 +24318,8 @@ msgid "Current Tab"
msgstr "Onglet actuel"
#: scene/gui/tab_container.cpp
-#, fuzzy
msgid "Tabs Visible"
-msgstr "Rendre visible"
+msgstr "Onglets Visibles"
#: scene/gui/tab_container.cpp
msgid "All Tabs In Front"
@@ -24388,33 +24346,28 @@ msgid "Readonly"
msgstr "Lecture Seule"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Bookmark Gutter"
-msgstr "Signets"
+msgstr "Bandeau à Marque-pages"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Breakpoint Gutter"
-msgstr "Passer les points d'arrêt"
+msgstr "Bandeau à points d'arrêt"
#: scene/gui/text_edit.cpp
msgid "Fold Gutter"
msgstr "Replier le bandeau"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Drag And Drop Selection Enabled"
-msgstr "Sélection uniquement"
+msgstr "Sélection en Glisser-déposer Activée"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Hiding Enabled"
-msgstr "Activer"
+msgstr "Cacher Activé"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Wrap Enabled"
-msgstr "Activer"
+msgstr "Déformation Activée"
#: scene/gui/text_edit.cpp
msgid "Scroll Vertical"
@@ -24429,9 +24382,8 @@ msgid "Draw"
msgstr "Dessiner"
#: scene/gui/text_edit.cpp
-#, fuzzy
msgid "Block Mode"
-msgstr "Déverrouiller le nœud"
+msgstr "Mode Bloc"
#: scene/gui/text_edit.cpp
msgid "Moving By Right Click"
@@ -24451,34 +24403,29 @@ msgid "Hover"
msgstr "Survoler"
#: scene/gui/texture_button.cpp
-#, fuzzy
msgid "Focused"
-msgstr "Focaliser le chemin"
+msgstr "Focalisé"
#: scene/gui/texture_button.cpp
-#, fuzzy
msgid "Click Mask"
-msgstr "Mode collision"
+msgstr "Masque de Clic"
#: scene/gui/texture_button.cpp scene/gui/texture_rect.cpp
#: scene/gui/video_player.cpp
-#, fuzzy
msgid "Expand"
-msgstr "Développer tout"
+msgstr "Développer"
#: scene/gui/texture_progress.cpp
msgid "Under"
msgstr "Sous"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Over"
-msgstr "Écraser"
+msgstr "Par-dessus"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Progress"
-msgstr "Propriétés du thème"
+msgstr "Progrès"
#: scene/gui/texture_progress.cpp
msgid "Progress Offset"
@@ -24497,43 +24444,36 @@ msgid "Radial Fill"
msgstr "Remplissage Radial"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Initial Angle"
-msgstr "Initialiser"
+msgstr "Angle Initial"
#: scene/gui/texture_progress.cpp
msgid "Fill Degrees"
msgstr "Degrés remplis"
#: scene/gui/texture_progress.cpp scene/resources/primitive_meshes.cpp
-#, fuzzy
msgid "Center Offset"
-msgstr "Centré à Gauche"
+msgstr "Décalage du Centre"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Nine Patch Stretch"
-msgstr "Mode d’interpolation"
+msgstr "Etirement à Neuf Patchs"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Stretch Margin Left"
-msgstr "Définir la marge"
+msgstr "Etirer la marge à gauche"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Stretch Margin Top"
-msgstr "Définir la marge"
+msgstr "Etirer la marge en haut"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Stretch Margin Right"
-msgstr "Définir la marge"
+msgstr "Etirer la marge à droite"
#: scene/gui/texture_progress.cpp
-#, fuzzy
msgid "Stretch Margin Bottom"
-msgstr "Mode sélection"
+msgstr "Etirer la marge en bas"
#: scene/gui/tree.cpp
msgid "Custom Minimum Height"
@@ -24544,14 +24484,12 @@ msgid "(Other)"
msgstr "(Autre)"
#: scene/gui/tree.cpp
-#, fuzzy
msgid "Column Titles Visible"
-msgstr "Rendre visible"
+msgstr "Titres des colonnes visibles"
#: scene/gui/tree.cpp
-#, fuzzy
msgid "Hide Folding"
-msgstr "Bouton désactivé"
+msgstr "Cacher les plis"
#: scene/gui/tree.cpp
msgid "Hide Root"
@@ -24562,43 +24500,36 @@ msgid "Drop Mode Flags"
msgstr "Options du Mode Abandon"
#: scene/gui/video_player.cpp
-#, fuzzy
msgid "Audio Track"
-msgstr "Ajouter une piste"
+msgstr "Piste Audio"
#: scene/gui/video_player.cpp scene/main/scene_tree.cpp scene/main/timer.cpp
msgid "Paused"
msgstr "En Pause"
#: scene/gui/video_player.cpp
-#, fuzzy
msgid "Buffering Msec"
-msgstr "Vue de derrière"
+msgstr "Mise en mémoire tampon ms"
#: scene/gui/video_player.cpp
-#, fuzzy
msgid "Stream Position"
-msgstr "Définir position d'entrée de la courbe"
+msgstr "Position Flux"
#: scene/gui/viewport_container.cpp
-#, fuzzy
msgid "Stretch Shrink"
-msgstr "Actualiser"
+msgstr "Etirer-Réduire"
#: scene/main/canvas_layer.cpp
-#, fuzzy
msgid "Follow Viewport"
-msgstr "Afficher le Viewport"
+msgstr "Suivre la fenêtre d'affichage"
#: scene/main/http_request.cpp
-#, fuzzy
msgid "Download File"
-msgstr "Télécharger"
+msgstr "Télécharger le Fichier"
#: scene/main/http_request.cpp
-#, fuzzy
msgid "Download Chunk Size"
-msgstr "Téléchargement en cours"
+msgstr "Taille des Blocs de Téléchargement"
#: scene/main/http_request.cpp
msgid "Body Size Limit"
@@ -24621,80 +24552,68 @@ msgstr ""
"'%s', car ce nom est déjà attribué à '%s'. Ce nœud n'est donc plus unique."
#: scene/main/node.cpp
-#, fuzzy
msgid "Name Num Separator"
-msgstr "Séparateur nommé"
+msgstr "Nom des séparateurs numériques"
#: scene/main/node.cpp
msgid "Name Casing"
msgstr "Convention de Nommage"
#: scene/main/node.cpp
-#, fuzzy
msgid "Editor Description"
-msgstr "Description"
+msgstr "Description de l'Editeur"
#: scene/main/node.cpp
-#, fuzzy
msgid "Pause Mode"
-msgstr "Mode navigation"
+msgstr "Mode Pause"
#: scene/main/node.cpp
-#, fuzzy
msgid "Physics Interpolation Mode"
-msgstr "Mode d’interpolation"
+msgstr "Mode d’interpolation physique"
#: scene/main/node.cpp
-#, fuzzy
msgid "Display Folded"
-msgstr "Afficher sans ombrage"
+msgstr "Afficher les repliés"
#: scene/main/node.cpp
-#, fuzzy
msgid "Filename"
-msgstr "Renommer"
+msgstr "Nom de fichier"
#: scene/main/node.cpp
msgid "Owner"
msgstr "Propriétaire"
#: scene/main/node.cpp scene/main/scene_tree.cpp
-#, fuzzy
msgid "Multiplayer"
-msgstr "Multiplier %s"
+msgstr "Multijoueur"
#: scene/main/node.cpp
msgid "Custom Multiplayer"
msgstr "Multijoueur Personnalisé"
#: scene/main/node.cpp
-#, fuzzy
msgid "Process Priority"
-msgstr "Activer la priorité"
+msgstr "Priorité de processus"
#: scene/main/scene_tree.cpp scene/main/timer.cpp
-#, fuzzy
msgid "Time Left"
-msgstr "En haut à gauche"
+msgstr "Temps restant"
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Debug Collisions Hint"
-msgstr "Mode collision"
+msgstr "Déboguer les indices de collision"
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Debug Navigation Hint"
-msgstr "Mode Navigation"
+msgstr "Déboguer les indices de navigation"
#: scene/main/scene_tree.cpp
msgid "Use Font Oversampling"
msgstr "Utiliser le Suréchantillonnage de Police"
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Edited Scene Root"
-msgstr "Nouvelle racine de scène"
+msgstr "Racine de scène modifiée"
#: scene/main/scene_tree.cpp
msgid "Root"
@@ -24778,9 +24697,8 @@ msgstr ""
"Environnement -> Environnement par défaut) ne peut pas être chargé."
#: scene/main/scene_tree.cpp
-#, fuzzy
msgid "Enable Object Picking"
-msgstr "Activer l'effet « pelure d'oignon »"
+msgstr "Activer la sélection d'objet"
#: scene/main/timer.cpp
msgid ""
@@ -24829,14 +24747,12 @@ msgid "ARVR"
msgstr "ARVR"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Size Override Stretch"
-msgstr "Remplacer l'item"
+msgstr "La taille passe outre l'étirement"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Own World"
-msgstr "Propre Monde"
+msgstr "Monde Propre"
#: scene/main/viewport.cpp scene/resources/world_2d.cpp
msgid "World"
@@ -24859,9 +24775,8 @@ msgid "FXAA"
msgstr "FXAA"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Debanding"
-msgstr "Liaison"
+msgstr "Dé-banding"
#: scene/main/viewport.cpp
msgid "Disable 3D"
@@ -24888,9 +24803,8 @@ msgid "V Flip"
msgstr "Miroir V"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Clear Mode"
-msgstr "Mode Règle"
+msgstr "Mode Nettoyage"
#: scene/main/viewport.cpp
msgid "Enable 2D"
@@ -24901,18 +24815,16 @@ msgid "Enable 3D"
msgstr "Activer 3D"
#: scene/main/viewport.cpp
-#, fuzzy
msgid "Object Picking"
-msgstr "Activer l'effet « pelure d'oignon »"
+msgstr "Sélection d'objet"
#: scene/main/viewport.cpp
msgid "Disable Input"
msgstr "Désactiver entrées"
#: scene/main/viewport.cpp servers/visual_server.cpp
-#, fuzzy
msgid "Shadow Atlas"
-msgstr "Nouvel Atlas"
+msgstr "Atlas d'ombres"
#: scene/main/viewport.cpp
msgid "Quad 0"
@@ -25000,9 +24912,8 @@ msgid "Segments"
msgstr "Segments"
#: scene/resources/curve.cpp
-#, fuzzy
msgid "Bake Resolution"
-msgstr "Demi résolution"
+msgstr "Précalculer la résolution"
#: scene/resources/curve.cpp
msgid "Bake Interval"
@@ -25133,19 +25044,16 @@ msgid "Cursor Color"
msgstr "Couleur du curseur"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Clear Button Color"
-msgstr "Filtrer les signaux"
+msgstr "Couleur du bouton de nettoyage"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Clear Button Color Pressed"
-msgstr "Filtrer les signaux"
+msgstr "Couleur du bouton de nettoyage appuyé"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Minimum Spaces"
-msgstr "Scène principale"
+msgstr "Espacement Minimum"
#: scene/resources/default_theme/default_theme.cpp
msgid "BG"
@@ -25251,12 +25159,11 @@ msgstr "Signet"
#: scene/resources/default_theme/default_theme.cpp
msgid "Updown"
-msgstr ""
+msgstr "Haut/Bas"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Scaleborder Size"
-msgstr "Pixels de bordure"
+msgstr "Taille de la bordure du cadre"
#: scene/resources/default_theme/default_theme.cpp
msgid "Title Font"
@@ -25307,9 +25214,8 @@ msgid "Font Separator"
msgstr "Séparateur de police"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color Accel"
-msgstr "Renommer l'item de couleur"
+msgstr "Accélération de la couleur de police"
#: scene/resources/default_theme/default_theme.cpp
msgid "Font Color Separator"
@@ -25328,14 +25234,12 @@ msgid "Default Frame"
msgstr "Trame par défaut"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Default Focus"
-msgstr "Défaut"
+msgstr "Focalisation par défaut"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Comment Focus"
-msgstr "Enregistrer"
+msgstr "Focalisation des commentaires"
#: scene/resources/default_theme/default_theme.cpp
msgid "Breakpoint"
@@ -25366,14 +25270,12 @@ msgid "Port Offset"
msgstr "Décalage du port"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "BG Focus"
-msgstr "Focaliser le chemin"
+msgstr "Focalisation de l'arrière-plan"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Selected Focus"
-msgstr "Sélectionner"
+msgstr "Focalisation de la sélection"
#: scene/resources/default_theme/default_theme.cpp
msgid "Cursor Unfocused"
@@ -25384,19 +25286,16 @@ msgid "Button Pressed"
msgstr "Bouton quand pressé"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Title Button Normal"
-msgstr "Bouton à bascule (toggle)"
+msgstr "Bouton de titre normal"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Title Button Pressed"
-msgstr "Bouton à bascule (toggle)"
+msgstr "Bouton de titre appuyé"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Title Button Hover"
-msgstr "Bouton à bascule (toggle)"
+msgstr "Bouton de titre survolé"
#: scene/resources/default_theme/default_theme.cpp
msgid "Custom Button"
@@ -25411,33 +25310,28 @@ msgid "Custom Button Hover"
msgstr "Bouton personnalisé au survol"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Select Arrow"
-msgstr "Tout sélectionner"
+msgstr "Flèche de sélection"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Arrow Collapsed"
-msgstr "Réduire tout"
+msgstr "Flèche réduite"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Title Button Font"
-msgstr "Bouton à bascule (toggle)"
+msgstr "Police du bouton de titre"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Title Button Color"
-msgstr "Couleur de la Sélection"
+msgstr "Couleur du bouton de titre"
#: scene/resources/default_theme/default_theme.cpp
msgid "Guide Color"
msgstr "Couleur des guides"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Drop Position Color"
-msgstr "Position du dock"
+msgstr "Couleur de position du dépôt"
#: scene/resources/default_theme/default_theme.cpp
msgid "Relationship Line Color"
@@ -25500,14 +25394,12 @@ msgid "Menu Highlight"
msgstr "Menu au survol"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color FG"
-msgstr "Renommer l'item de couleur"
+msgstr "Couleur de police premier plan"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Font Color BG"
-msgstr "Renommer l'item de couleur"
+msgstr "Couleur de police arrière-plan"
#: scene/resources/default_theme/default_theme.cpp
msgid "Side Margin"
@@ -25519,11 +25411,11 @@ msgstr "Marge en haut"
#: scene/resources/default_theme/default_theme.cpp
msgid "Label V Align FG"
-msgstr ""
+msgstr "Alignement Vertical du Label Premier Plan"
#: scene/resources/default_theme/default_theme.cpp
msgid "Label V Align BG"
-msgstr ""
+msgstr "Alignement Vertical du Label Arrière-plan"
#: scene/resources/default_theme/default_theme.cpp
msgid "Large"
@@ -25546,19 +25438,16 @@ msgid "Files Disabled"
msgstr "Fichiers désactivés"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "SV Width"
-msgstr "Étendu à Gauche"
+msgstr "Largeur SV"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "SV Height"
-msgstr "Lumière"
+msgstr "Hauteur SV"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "H Width"
-msgstr "Étendu à Gauche"
+msgstr "Largeur H"
#: scene/resources/default_theme/default_theme.cpp
msgid "Label Width"
@@ -25673,9 +25562,8 @@ msgid "Activity"
msgstr "Activité"
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Bezier Len Pos"
-msgstr "Déplacer des points de Bézier"
+msgstr "Position de longueur de Bézier"
#: scene/resources/default_theme/default_theme.cpp
msgid "Bezier Len Neg"
@@ -25842,9 +25730,8 @@ msgid "Max Luma"
msgstr "Lumen maximum"
#: scene/resources/environment.cpp
-#, fuzzy
msgid "SS Reflections"
-msgstr "Mettre à l'échelle la sélection"
+msgstr "Reflets SS"
#: scene/resources/environment.cpp
msgid "Max Steps"
@@ -25879,14 +25766,12 @@ msgid "Intensity 2"
msgstr "Intensité 2"
#: scene/resources/environment.cpp scene/resources/material.cpp
-#, fuzzy
msgid "Light Affect"
-msgstr "Étendu à Droite"
+msgstr "Influence de la lumière"
#: scene/resources/environment.cpp
-#, fuzzy
msgid "AO Channel Affect"
-msgstr "Débogage du canal UV"
+msgstr "Influence du canal AO"
#: scene/resources/environment.cpp
msgid "Blur"
@@ -26158,12 +26043,11 @@ msgstr "NormalMap"
#: scene/resources/material.cpp
msgid "Rim"
-msgstr "Bord"
+msgstr "Bordure"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Clearcoat"
-msgstr "Effacer"
+msgstr "Coucheclaire"
#: scene/resources/material.cpp
msgid "Gloss"
@@ -26175,7 +26059,7 @@ msgstr "Anisotropie"
#: scene/resources/material.cpp
msgid "Flowmap"
-msgstr ""
+msgstr "Organigramme"
#: scene/resources/material.cpp
msgid "Ambient Occlusion"
@@ -26186,23 +26070,20 @@ msgid "Deep Parallax"
msgstr "Parallaxe Profonde"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Min Layers"
-msgstr "Calque"
+msgstr "Calques min"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Max Layers"
-msgstr "Calque"
+msgstr "Calques max"
#: scene/resources/material.cpp
msgid "Flip Tangent"
msgstr "Inverser la Tangente"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Flip Binormal"
-msgstr "Retourner le Portal"
+msgstr "Inversion Bi-normale"
#: scene/resources/material.cpp
msgid "Subsurf Scatter"
@@ -26241,9 +26122,8 @@ msgid "UV2"
msgstr "UV2"
#: scene/resources/material.cpp
-#, fuzzy
msgid "Proximity Fade"
-msgstr "Mode prioritaire"
+msgstr "Fondu de proximité"
#: scene/resources/material.cpp
msgid "Distance Fade"
@@ -26254,9 +26134,8 @@ msgid "Async Mode"
msgstr "Mode asynchrone"
#: scene/resources/mesh.cpp
-#, fuzzy
msgid "Lightmap Size Hint"
-msgstr "LightMap Bake"
+msgstr "Indice de taille de la texture de lumière"
#: scene/resources/mesh.cpp scene/resources/primitive_meshes.cpp
msgid "Custom AABB"
@@ -26307,9 +26186,8 @@ msgid "Source Geometry Mode"
msgstr "Mode Géométrie Source"
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Source Group Name"
-msgstr "Source"
+msgstr "Nom du groupe source"
#: scene/resources/navigation_mesh.cpp
msgid "Cells"
@@ -26332,18 +26210,16 @@ msgid "Regions"
msgstr "Régions"
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Merge Size"
-msgstr "Fusionner depuis la scène"
+msgstr "Taille de la fusion"
#: scene/resources/navigation_mesh.cpp
msgid "Edges"
msgstr "Arêtes"
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Max Error"
-msgstr "Erreur"
+msgstr "Erreur max"
#: scene/resources/navigation_mesh.cpp
msgid "Verts Per Poly"
@@ -26358,9 +26234,8 @@ msgid "Sample Distance"
msgstr "Échantillonner la distance"
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Sample Max Error"
-msgstr "Échantillonneur"
+msgstr "Échantillon erreur max"
#: scene/resources/navigation_mesh.cpp
msgid "Low Hanging Obstacles"
@@ -26375,14 +26250,12 @@ msgid "Walkable Low Height Spans"
msgstr "Etendues de faible hauteur praticables"
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Baking AABB"
-msgstr "Générer AABB"
+msgstr "Précalcul AABB"
#: scene/resources/navigation_mesh.cpp
-#, fuzzy
msgid "Baking AABB Offset"
-msgstr "Décalage :"
+msgstr "Décalage du Précalcul AABB"
#: scene/resources/occluder_shape.cpp
msgid "Spheres"
@@ -26413,14 +26286,12 @@ msgid "Divisor"
msgstr "Diviseur"
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Size Modifier"
-msgstr "Modificateur de vitesse de la vue libre"
+msgstr "Modificateur de taille"
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Color Modifier"
-msgstr "Ralentissement de la vue libre"
+msgstr "Modificateur de couleur"
#: scene/resources/particles_material.cpp
msgid "Point Texture"
@@ -26431,9 +26302,8 @@ msgid "Normal Texture"
msgstr "Texture Normale"
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Color Texture"
-msgstr "Thème de l'éditeur"
+msgstr "Texture de couleur"
#: scene/resources/particles_material.cpp
msgid "Point Count"
@@ -26444,9 +26314,8 @@ msgid "Scale Random"
msgstr "Échelle Aléatoire"
#: scene/resources/particles_material.cpp
-#, fuzzy
msgid "Scale Curve"
-msgstr "Fermer la courbe"
+msgstr "Courbe d'échelle"
#: scene/resources/physics_material.cpp
msgid "Rough"
@@ -26485,9 +26354,8 @@ msgid "Top Radius"
msgstr "Rayon Supérieur"
#: scene/resources/primitive_meshes.cpp
-#, fuzzy
msgid "Bottom Radius"
-msgstr "En bas à droite"
+msgstr "Rayon bas"
#: scene/resources/primitive_meshes.cpp
msgid "Left To Right"
@@ -26574,18 +26442,16 @@ msgid "Content Margin"
msgstr "Marge de contenu"
#: scene/resources/style_box.cpp
-#, fuzzy
msgid "Expand Margin"
-msgstr "Développer tout"
+msgstr "Développer la marge"
#: scene/resources/style_box.cpp
msgid "Skew"
msgstr "Biseau"
#: scene/resources/style_box.cpp
-#, fuzzy
msgid "Corner Radius"
-msgstr "Changer le rayon intérieur de la tour"
+msgstr "Rayon de coin"
#: scene/resources/style_box.cpp
msgid "Corner Detail"
@@ -26604,9 +26470,8 @@ msgid "Grow End"
msgstr "Fin d'Expansion"
#: scene/resources/texture.cpp
-#, fuzzy
msgid "Load Path"
-msgstr "Charger un préréglage"
+msgstr "Charger chemin"
#: scene/resources/texture.cpp
msgid "Base Texture"
@@ -26673,14 +26538,12 @@ msgid "Output Port For Preview"
msgstr "Port de sortie de l'aperçu"
#: scene/resources/visual_shader.cpp
-#, fuzzy
msgid "Depth Draw"
-msgstr "Mode d’interpolation"
+msgstr "Dessin en profondeur"
#: scene/resources/visual_shader.cpp
-#, fuzzy
msgid "Cull"
-msgstr "Mode Règle"
+msgstr "élaguer/élagage"
#: scene/resources/visual_shader.cpp
msgid "Diffuse"
@@ -26727,9 +26590,8 @@ msgid "Cube Map"
msgstr "Textures en cube"
#: scene/resources/visual_shader_nodes.cpp
-#, fuzzy
msgid "Default Value Enabled"
-msgstr "Profil des fonctionnalités de Godot"
+msgstr "Valeur par défaut activée"
#: scene/resources/visual_shader_nodes.cpp
msgid "Default Value"
@@ -26757,25 +26619,23 @@ msgstr "Carte de navigation"
#: scene/resources/world.cpp scene/resources/world_2d.cpp
msgid "Direct Space State"
-msgstr ""
+msgstr "Etat de l'espace direct"
#: scene/resources/world.cpp scene/resources/world_2d.cpp
msgid "Default Gravity Vector"
msgstr "Vecteur de gravité par défaut"
#: scene/resources/world.cpp scene/resources/world_2d.cpp
-#, fuzzy
msgid "Default Linear Damp"
-msgstr "Linéaire gauche"
+msgstr "Amorti linéaire par défaut"
#: scene/resources/world.cpp scene/resources/world_2d.cpp
msgid "Default Angular Damp"
-msgstr ""
+msgstr "Amorti Angulaire par Défaut"
#: scene/resources/world.cpp
-#, fuzzy
msgid "Default Map Up"
-msgstr "Défaut"
+msgstr "Haut de carte par défaut"
#: scene/resources/world.cpp scene/resources/world_2d.cpp
msgid "Default Cell Size"
@@ -26807,7 +26667,7 @@ msgstr "AR"
#: servers/arvr/arvr_interface.cpp
msgid "Is Anchor Detection Enabled"
-msgstr ""
+msgstr "La détection d'ancre est-elle activée"
#: servers/arvr_server.cpp
msgid "Primary Interface"
@@ -26869,7 +26729,7 @@ msgstr "Niveau (dB)"
#: servers/audio/effects/audio_effect_delay.cpp
#: servers/audio/effects/audio_effect_panner.cpp
msgid "Pan"
-msgstr "Pan"
+msgstr "Panoramique/faire un panoramique"
#: servers/audio/effects/audio_effect_compressor.cpp
#: servers/audio/effects/audio_effect_filter.cpp
@@ -26890,15 +26750,15 @@ msgstr "Mixer"
#: servers/audio/effects/audio_effect_compressor.cpp
msgid "Sidechain"
-msgstr ""
+msgstr "Sidechain"
#: servers/audio/effects/audio_effect_delay.cpp
msgid "Tap 1"
-msgstr ""
+msgstr "Tap 1"
#: servers/audio/effects/audio_effect_delay.cpp
msgid "Tap 2"
-msgstr ""
+msgstr "Tap 2"
#: servers/audio/effects/audio_effect_delay.cpp
#: servers/audio/effects/audio_effect_phaser.cpp
@@ -26920,7 +26780,7 @@ msgstr "Garder haute fréquences (Hz)"
#: servers/audio/effects/audio_effect_distortion.cpp
msgid "Drive"
-msgstr ""
+msgstr "Elan"
#: servers/audio/effects/audio_effect_distortion.cpp
msgid "Post Gain"
@@ -26940,11 +26800,11 @@ msgstr "Seuil de dB"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Soft Clip dB"
-msgstr ""
+msgstr "dB de Coupure Douce"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Soft Clip Ratio"
-msgstr ""
+msgstr "Ratio de Coupure Douce"
#: servers/audio/effects/audio_effect_phaser.cpp
msgid "Range Min Hz"
@@ -26956,7 +26816,7 @@ msgstr "Borne supérieure de la plage (Hz)"
#: servers/audio/effects/audio_effect_pitch_shift.cpp
msgid "Oversampling"
-msgstr "Suréchantillonnage"
+msgstr "Sur-échantillonnage"
#: servers/audio/effects/audio_effect_pitch_shift.cpp
#: servers/audio/effects/audio_effect_spectrum_analyzer.cpp
@@ -26981,11 +26841,11 @@ msgstr "Passe-haut"
#: servers/audio/effects/audio_effect_spectrum_analyzer.cpp
msgid "Tap Back Pos"
-msgstr ""
+msgstr "Tap Position Arrière"
#: servers/audio/effects/audio_effect_stereo_enhance.cpp
msgid "Pan Pullout"
-msgstr ""
+msgstr "Retrait du Panoramique"
#: servers/audio/effects/audio_effect_stereo_enhance.cpp
msgid "Time Pullout (ms)"
@@ -27008,9 +26868,8 @@ msgid "Channel Disable Threshold dB"
msgstr "Désactiver le seuil de dB du canal"
#: servers/audio_server.cpp
-#, fuzzy
msgid "Channel Disable Time"
-msgstr "Changer le temps de mélange"
+msgstr "Temps de désactivation de canal"
#: servers/audio_server.cpp
msgid "Video Delay Compensation (ms)"
@@ -27054,7 +26913,7 @@ msgstr "Taille de la Table de Hachage BP"
#: servers/physics_2d/physics_2d_server_sw.cpp
msgid "Large Object Surface Threshold In Cells"
-msgstr ""
+msgstr "Seuil de Surface des Grands Objets dans les Cellules"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
msgid "Inverse Mass"
@@ -27113,14 +26972,12 @@ msgid "Collision Depth"
msgstr "Profondeur de collision"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Collision Safe Fraction"
-msgstr "Mode collision"
+msgstr "Fraction anti-collisions"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Collision Unsafe Fraction"
-msgstr "Mode collision"
+msgstr "Fraction avec collisions potentielles"
#: servers/physics_2d_server.cpp servers/physics_server.cpp
msgid "Physics Engine"
@@ -27139,22 +26996,20 @@ msgid "Varying may not be assigned in the '%s' function."
msgstr "Varying ne peut pas être assigné dans la fonction '%s'."
#: servers/visual/shader_language.cpp
-#, fuzzy
msgid ""
"Varyings which were assigned in 'vertex' function may not be reassigned in "
"'fragment' or 'light'."
msgstr ""
-"Les Varyings assignées dans la fonction \"vertex\" ne peuvent pas être "
-"réassignées dans 'fragment' ou 'light'."
+"Les variations assignées dans la fonction \"sommet/vertex\" ne peuvent pas "
+"être réassignées dans \"fragment\" ou \"lumière/light\"."
#: servers/visual/shader_language.cpp
-#, fuzzy
msgid ""
"Varyings which were assigned in 'fragment' function may not be reassigned in "
"'vertex' or 'light'."
msgstr ""
-"Les Varyings attribuées dans la fonction 'fragment' ne peuvent pas être "
-"réattribuées dans 'vertex' ou 'light'."
+"Les variations attribuées dans la fonction \"fragment\" ne peuvent pas être "
+"réattribuées dans \"sommet/vertex\" ou \"lumière/light\"."
#: servers/visual/shader_language.cpp
msgid "Assignment to function."
@@ -27173,9 +27028,8 @@ msgid "Spatial Partitioning"
msgstr "Partitionnement Spatial"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Render Loop Enabled"
-msgstr "Filtrer les signaux"
+msgstr "Boucle de rendu activée"
#: servers/visual_server.cpp
msgid "VRAM Compression"
@@ -27215,28 +27069,27 @@ msgstr "Niveau de compression WebP"
#: servers/visual_server.cpp
msgid "Time Rollover Secs"
-msgstr ""
+msgstr "Temps de Roulement en Secondes"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Cubemap Size"
-msgstr "Changer la taille d'une caméra"
+msgstr "Taille de la Cubemap"
#: servers/visual_server.cpp
msgid "Quadrant 0 Subdiv"
-msgstr ""
+msgstr "Subdivisions Quadrant 0"
#: servers/visual_server.cpp
msgid "Quadrant 1 Subdiv"
-msgstr ""
+msgstr "Subdivision Quadrant 1"
#: servers/visual_server.cpp
msgid "Quadrant 2 Subdiv"
-msgstr ""
+msgstr "Subdivision Quadrant 2"
#: servers/visual_server.cpp
msgid "Quadrant 3 Subdiv"
-msgstr ""
+msgstr "Subdivision Quadrant 3"
#: servers/visual_server.cpp
msgid "Shadows"
@@ -27247,9 +27100,8 @@ msgid "Filter Mode"
msgstr "Mode de filtrage"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Texture Array Reflections"
-msgstr "Centrer sur la sélection"
+msgstr "Refléxions de la liste de textures"
#: servers/visual_server.cpp
msgid "High Quality GGX"
@@ -27257,7 +27109,7 @@ msgstr "GGX haute qualité"
#: servers/visual_server.cpp
msgid "Irradiance Max Size"
-msgstr ""
+msgstr "Taille Max Irradiance"
#: servers/visual_server.cpp
msgid "Shading"
@@ -27265,7 +27117,7 @@ msgstr "Ombrage"
#: servers/visual_server.cpp
msgid "Force Vertex Shading"
-msgstr ""
+msgstr "Forcer l'Ombrage des Sommets"
#: servers/visual_server.cpp
msgid "Force Lambert Over Burley"
@@ -27277,24 +27129,23 @@ msgstr "Forcer Blinn au lieu de GGX"
#: servers/visual_server.cpp
msgid "Mesh Storage"
-msgstr ""
+msgstr "Stockage de Maillage"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Split Stream"
-msgstr "Scinder la courbe"
+msgstr "Séparer flux"
#: servers/visual_server.cpp
msgid "Use Physical Light Attenuation"
-msgstr ""
+msgstr "Utiliser l'Atténuation Lumineuse Physique"
#: servers/visual_server.cpp
msgid "Depth Prepass"
-msgstr ""
+msgstr "Pré-passe de Profondeur"
#: servers/visual_server.cpp
msgid "Disable For Vendors"
-msgstr ""
+msgstr "Désactiver pour les Vendeurs"
#: servers/visual_server.cpp
msgid "Anisotropic Filter Level"
@@ -27310,15 +27161,15 @@ msgstr "Enveloppement"
#: servers/visual_server.cpp
msgid "Software Skinning Fallback"
-msgstr ""
+msgstr "Dépouillement Logiciel de Repli"
#: servers/visual_server.cpp
msgid "Force Software Skinning"
-msgstr ""
+msgstr "Forcer le Dépouillement Logiciel"
#: servers/visual_server.cpp
msgid "Use Software Skinning"
-msgstr ""
+msgstr "Utiliser Dépouillement Logiciel"
#: servers/visual_server.cpp
msgid "Ninepatch Mode"
@@ -27330,7 +27181,7 @@ msgstr "OpenGL"
#: servers/visual_server.cpp
msgid "Batching Send Null"
-msgstr ""
+msgstr "Traitement en Lot - Envoyer Null"
#: servers/visual_server.cpp
msgid "Batching Stream"
@@ -27338,11 +27189,11 @@ msgstr "Flux de traitement en lot"
#: servers/visual_server.cpp
msgid "Legacy Orphan Buffers"
-msgstr ""
+msgstr "Anciens Tampons Orphelins"
#: servers/visual_server.cpp
msgid "Legacy Stream"
-msgstr ""
+msgstr "Ancien Flux"
#: servers/visual_server.cpp
msgid "Batching"
@@ -27358,19 +27209,19 @@ msgstr "Utiliser le traitement en lot dans l'éditeur"
#: servers/visual_server.cpp
msgid "Single Rect Fallback"
-msgstr ""
+msgstr "Rectangle Unique de Repli"
#: servers/visual_server.cpp
msgid "Max Join Item Commands"
-msgstr ""
+msgstr "Commandes Max de Jointure d'Elements"
#: servers/visual_server.cpp
msgid "Colored Vertex Format Threshold"
-msgstr ""
+msgstr "Seuil de Format des Sommets Colorés"
#: servers/visual_server.cpp
msgid "Scissor Area Threshold"
-msgstr ""
+msgstr "Seuil d'Aire de Cisaillement"
#: servers/visual_server.cpp
msgid "Max Join Items"
@@ -27386,7 +27237,7 @@ msgstr "Anticipation de réorganisation d’éléments"
#: servers/visual_server.cpp
msgid "Flash Batching"
-msgstr ""
+msgstr "Traitement en Lot Flash"
#: servers/visual_server.cpp
msgid "Diagnose Frame"
@@ -27405,9 +27256,8 @@ msgid "Disable Half Float"
msgstr "Désactiver les demi Float"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Enable High Float"
-msgstr "Activer la priorité"
+msgstr "Activer les grands flottants"
#: servers/visual_server.cpp
msgid "Precision"
@@ -27434,19 +27284,16 @@ msgid "Use Signals"
msgstr "Utiliser les signaux"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Remove Danglers"
-msgstr "Supprimer la tuile"
+msgstr "Supprimer les pendouillants"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Flip Imported Portals"
-msgstr "Retourner les Portals"
+msgstr "Retourner les portails importés"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Occlusion Culling"
-msgstr "Voir la suppression de l'occlusion"
+msgstr "Elagage de l'occlusion"
#: servers/visual_server.cpp
msgid "Max Active Spheres"
diff --git a/editor/translations/ga.po b/editor/translations/ga.po
index 01810bb059..eea95f8656 100644
--- a/editor/translations/ga.po
+++ b/editor/translations/ga.po
@@ -10649,7 +10649,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/gl.po b/editor/translations/gl.po
index 1d2fbb333a..9bfb2b9309 100644
--- a/editor/translations/gl.po
+++ b/editor/translations/gl.po
@@ -11231,7 +11231,7 @@ msgstr "Perspetiva"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/he.po b/editor/translations/he.po
index 57b2386570..7458eedd15 100644
--- a/editor/translations/he.po
+++ b/editor/translations/he.po
@@ -26,13 +26,14 @@
# Tomer Ben Rachel <tomerpacific@gmail.com>, 2022.
# moshe mil <milgmoshe@gmail.com>, 2022.
# Blawnode <blawnode@gmail.com>, 2022.
+# Yoni m <yoni.meirov08@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-11-23 20:47+0000\n"
-"Last-Translator: Blawnode <blawnode@gmail.com>\n"
+"PO-Revision-Date: 2023-01-01 05:48+0000\n"
+"Last-Translator: Yoni m <yoni.meirov08@gmail.com>\n"
"Language-Team: Hebrew <https://hosted.weblate.org/projects/godot-engine/"
"godot/he/>\n"
"Language: he\n"
@@ -41,7 +42,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -274,9 +275,8 @@ msgid "Network Peer"
msgstr "מ×פיין\\עמית רשת"
#: core/io/multiplayer_api.cpp scene/animation/animation_player.cpp
-#, fuzzy
msgid "Root Node"
-msgstr "שינוי ×©× ×ž×¤×¨×§ השורש"
+msgstr "מפרק השורש"
#: core/io/networked_multiplayer_peer.cpp
msgid "Refuse New Connections"
@@ -300,11 +300,11 @@ msgstr "פלוט גודל מירבי של החוצץ"
#: core/io/packet_peer.cpp
msgid "Stream Peer"
-msgstr ""
+msgstr "×–×¨× ×¢×ž×™×ª×™×"
#: core/io/stream_peer.cpp
msgid "Big Endian"
-msgstr ""
+msgstr "×נדי×ן גדול"
#: core/io/stream_peer.cpp
#, fuzzy
@@ -395,18 +395,16 @@ msgid "Device"
msgstr "מכשיר"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Alt"
-msgstr "הכל"
+msgstr "×לט"
#: core/os/input_event.cpp
msgid "Shift"
msgstr "הסט"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Control"
-msgstr "בקרת גירס×ות"
+msgstr "לשלוט"
#: core/os/input_event.cpp
msgid "Meta"
@@ -417,9 +415,8 @@ msgid "Command"
msgstr "פקודה"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Physical"
-msgstr "פיזיקה"
+msgstr "פיזי"
#: core/os/input_event.cpp scene/2d/touch_screen_button.cpp
#: scene/gui/base_button.cpp scene/gui/texture_button.cpp
@@ -428,9 +425,8 @@ msgid "Pressed"
msgstr "לחוץ"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Scancode"
-msgstr "סריקת מקורות"
+msgstr "קוד סריקה"
#: core/os/input_event.cpp
msgid "Physical Scancode"
@@ -442,26 +438,23 @@ msgstr "יוניקוד"
#: core/os/input_event.cpp
msgid "Echo"
-msgstr ""
+msgstr "הד"
#: core/os/input_event.cpp scene/gui/base_button.cpp
-#, fuzzy
msgid "Button Mask"
-msgstr "כפתור"
+msgstr "מסכת כפתור"
#: core/os/input_event.cpp scene/2d/node_2d.cpp scene/gui/control.cpp
-#, fuzzy
msgid "Global Position"
-msgstr "קבוע"
+msgstr "×ž×™×§×•× ×’×œ×•×‘×œ×™"
#: core/os/input_event.cpp
msgid "Factor"
msgstr "פקטור"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Button Index"
-msgstr "מפתח כפתורי עכבר:"
+msgstr "×ינדקס הכפתורי×"
#: core/os/input_event.cpp
msgid "Doubleclick"
@@ -477,12 +470,11 @@ msgstr "לחץ"
#: core/os/input_event.cpp
msgid "Pen Inverted"
-msgstr ""
+msgstr "עט הפוך"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Relative"
-msgstr "GDNative"
+msgstr "קרוב משפחה"
#: core/os/input_event.cpp scene/2d/camera_2d.cpp scene/2d/cpu_particles_2d.cpp
#: scene/3d/cpu_particles.cpp scene/3d/interpolated_camera.cpp
@@ -497,9 +489,8 @@ msgid "Axis"
msgstr "ציר"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Axis Value"
-msgstr "(ערך)"
+msgstr "ערך ציר"
#: core/os/input_event.cpp modules/visual_script/visual_script_func_nodes.cpp
msgid "Index"
@@ -529,16 +520,14 @@ msgid "Message"
msgstr "מסר"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Pitch"
-msgstr "גובה צליל"
+msgstr "גובה הצליל"
#: core/os/input_event.cpp scene/2d/cpu_particles_2d.cpp
#: scene/2d/physics_body_2d.cpp scene/3d/cpu_particles.cpp
#: scene/3d/physics_body.cpp scene/resources/particles_material.cpp
-#, fuzzy
msgid "Velocity"
-msgstr "הגדלת ×ות ר×שונה"
+msgstr "מְהִירוּת"
#: core/os/input_event.cpp
msgid "Instrument"
@@ -559,14 +548,12 @@ msgid "Application"
msgstr "×פליקציה"
#: core/project_settings.cpp main/main.cpp
-#, fuzzy
msgid "Config"
-msgstr "הגדרת הצמדה"
+msgstr "הקונפדרציה"
#: core/project_settings.cpp
-#, fuzzy
msgid "Project Settings Override"
-msgstr "הגדרות מיז×..."
+msgstr "עקיפת הגדרות פרוייקט"
#: core/project_settings.cpp core/resource.cpp
#: editor/animation_track_editor.cpp editor/editor_autoload_settings.cpp
@@ -597,7 +584,7 @@ msgstr "הרצה"
#: core/project_settings.cpp editor/editor_node.cpp
#: editor/run_settings_dialog.cpp main/main.cpp
msgid "Main Scene"
-msgstr ""
+msgstr "סצנה ר×שית"
#: core/project_settings.cpp
msgid "Disable stdout"
@@ -609,22 +596,21 @@ msgstr "השבת stderr"
#: core/project_settings.cpp
msgid "Use Hidden Project Data Directory"
-msgstr ""
+msgstr "שימוש בספריית נתוני פרוייקט מוסתרי×"
#: core/project_settings.cpp
msgid "Use Custom User Dir"
-msgstr ""
+msgstr "השתמש ב- Dir משתמש מות×× ×ישית"
#: core/project_settings.cpp
msgid "Custom User Dir Name"
-msgstr ""
+msgstr "×©× ×ª×™×§×™×™×ª משתמש מות×× ×ישית"
#: core/project_settings.cpp main/main.cpp
#: platform/javascript/export/export.cpp platform/osx/export/export.cpp
#: platform/uwp/os_uwp.cpp
-#, fuzzy
msgid "Display"
-msgstr "הצג הכל"
+msgstr "הצג"
#: core/project_settings.cpp main/main.cpp modules/csg/csg_shape.cpp
#: modules/opensimplex/noise_texture.cpp scene/2d/line_2d.cpp
@@ -643,7 +629,7 @@ msgstr "גבה"
#: core/project_settings.cpp
msgid "Always On Top"
-msgstr ""
+msgstr "תמיד עליון"
#: core/project_settings.cpp
msgid "Test Width"
@@ -672,30 +658,27 @@ msgstr "עורך"
#: core/project_settings.cpp
msgid "Main Run Args"
-msgstr ""
+msgstr "×¤×¨×ž×˜×¨×™× ×¨××©×™×™× ×œ×¨×™×¦×”"
#: core/project_settings.cpp
-#, fuzzy
msgid "Scene Naming"
-msgstr "נתיב סצנות:"
+msgstr "מתן שמות לסצינה"
#: core/project_settings.cpp
msgid "Search In File Extensions"
-msgstr ""
+msgstr "חיפוש בסיומות קבצי×"
#: core/project_settings.cpp
msgid "Script Templates Search Path"
-msgstr ""
+msgstr "נתיב חיפוש של תבניות סקריפט"
#: core/project_settings.cpp
-#, fuzzy
msgid "Version Control Autoload On Startup"
-msgstr "בקרת גירס×ות"
+msgstr "טעינה ×וטומטית של בקרת גירס×ות בעת ×”×תחול"
#: core/project_settings.cpp
-#, fuzzy
msgid "Version Control Plugin Name"
-msgstr "בקרת גירס×ות"
+msgstr "×©× ×ª×•×¡×£ בקרת גרס×ות"
#: core/project_settings.cpp scene/2d/collision_object_2d.cpp
#: scene/3d/collision_object.cpp scene/gui/control.cpp
@@ -704,62 +687,55 @@ msgstr "קלט"
#: core/project_settings.cpp
msgid "UI Accept"
-msgstr ""
+msgstr "ממשק משתמש - ×ישור"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Select"
-msgstr "בחירה"
+msgstr "בחירת ממשק משתמש"
#: core/project_settings.cpp
msgid "UI Cancel"
-msgstr ""
+msgstr "ביטול ממשק משתמש"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Focus Next"
-msgstr "מיקוד נתיב"
+msgstr "מיקוד ממשק המשתמש הב×"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Focus Prev"
-msgstr "מיקוד נתיב"
+msgstr "מיקוד ממשק משתמש קוד×"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Left"
-msgstr "שמ×ל"
+msgstr "ממשק משתמש שמ×ל"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Right"
-msgstr "ימין"
+msgstr "ממשק משתמש ימין"
#: core/project_settings.cpp
msgid "UI Up"
-msgstr ""
+msgstr "ממשק משתמש למעלה"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Down"
-msgstr "הורדה"
+msgstr "ממשק משתמש למטה"
#: core/project_settings.cpp
msgid "UI Page Up"
-msgstr ""
+msgstr "עמוד למעלה ממשק המשתמש"
#: core/project_settings.cpp
msgid "UI Page Down"
-msgstr ""
+msgstr "עמוד למטה ממשק משתמש"
#: core/project_settings.cpp
msgid "UI Home"
-msgstr ""
+msgstr "ממשק משתמש בית"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI End"
-msgstr "בסוף"
+msgstr "ממשק משתמש סוף"
#: core/project_settings.cpp main/main.cpp modules/bullet/register_types.cpp
#: modules/bullet/space_bullet.cpp scene/2d/physics_body_2d.cpp
@@ -796,7 +772,7 @@ msgstr ""
#: scene/main/viewport.cpp servers/visual/visual_server_scene.cpp
#: servers/visual_server.cpp
msgid "Rendering"
-msgstr ""
+msgstr "רינדור"
#: core/project_settings.cpp drivers/gles2/rasterizer_storage_gles2.cpp
#: drivers/gles3/rasterizer_scene_gles3.cpp
@@ -816,7 +792,7 @@ msgstr "מסנני×"
#: core/project_settings.cpp scene/main/viewport.cpp
msgid "Sharpen Intensity"
-msgstr ""
+msgstr "עוצמת חידוד"
#: core/project_settings.cpp editor/editor_export.cpp editor/editor_node.cpp
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
@@ -842,42 +818,40 @@ msgid "Profiler"
msgstr "מ×פיין"
#: core/project_settings.cpp
-#, fuzzy
msgid "Max Functions"
-msgstr "יצירת פונקציה"
+msgstr "פונקציות מקסימו×"
#: core/project_settings.cpp scene/3d/vehicle_body.cpp
msgid "Compression"
msgstr "כיווץ"
#: core/project_settings.cpp
-#, fuzzy
msgid "Formats"
-msgstr "תבנית"
+msgstr "פורמטי×"
#: core/project_settings.cpp
msgid "Zstd"
-msgstr ""
+msgstr "Zstd"
#: core/project_settings.cpp
msgid "Long Distance Matching"
-msgstr ""
+msgstr "הת×מה ×œ×ž×¨×—×§×™× ×רוכי×"
#: core/project_settings.cpp
msgid "Compression Level"
-msgstr ""
+msgstr "רמת דחיסה"
#: core/project_settings.cpp
msgid "Window Log Size"
-msgstr ""
+msgstr "גודל חלון יומן"
#: core/project_settings.cpp
msgid "Zlib"
-msgstr ""
+msgstr "ZLIB"
#: core/project_settings.cpp
msgid "Gzip"
-msgstr ""
+msgstr "Gzip"
#: core/project_settings.cpp platform/android/export/export.cpp
msgid "Android"
@@ -885,24 +859,23 @@ msgstr "Android"
#: core/project_settings.cpp
msgid "Modules"
-msgstr ""
+msgstr "מודולי×"
#: core/register_core_types.cpp
msgid "TCP"
msgstr "TCP"
#: core/register_core_types.cpp
-#, fuzzy
msgid "Connect Timeout Seconds"
-msgstr "שניות קצובות להתחברות"
+msgstr "זמן קצוב לחיבור בשניות"
#: core/register_core_types.cpp
msgid "Packet Peer Stream"
-msgstr ""
+msgstr "×–×¨× ×¢×ž×™×ª מנות"
#: core/register_core_types.cpp
msgid "Max Buffer (Power of 2)"
-msgstr ""
+msgstr "גודל מחסנית מקסימלי (בחזקה)"
#: core/register_core_types.cpp editor/editor_settings.cpp main/main.cpp
msgid "SSL"
@@ -943,7 +916,7 @@ msgstr "בדיקה"
#: core/translation.cpp scene/resources/font.cpp
msgid "Fallback"
-msgstr ""
+msgstr "חזרה"
#: core/ustring.cpp scene/resources/segment_shape_2d.cpp
msgid "B"
@@ -979,7 +952,7 @@ msgstr "EiB"
#: drivers/gles3/rasterizer_scene_gles3.cpp
#: drivers/gles3/rasterizer_storage_gles3.cpp modules/gltf/gltf_state.cpp
msgid "Buffers"
-msgstr ""
+msgstr "מחסניות"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
@@ -1005,39 +978,36 @@ msgstr "2D"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
-#, fuzzy
msgid "Snapping"
-msgstr "הגדרות הצמדה"
+msgstr "הצמדה"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
-#, fuzzy
msgid "Use GPU Pixel Snap"
-msgstr "מצב מרחב מקומי (%s)"
+msgstr "שימוש בהצמדת ×¤×™×§×¡×œ×™× ×©×œ GPU"
#: drivers/gles2/rasterizer_scene_gles2.cpp
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Immediate Buffer Size (KB)"
-msgstr ""
+msgstr "גודל מחסנית מיידי (KB)"
#: drivers/gles2/rasterizer_storage_gles2.cpp
#: drivers/gles3/rasterizer_storage_gles3.cpp
-#, fuzzy
msgid "Lightmapping"
-msgstr "×פיית Lightmaps"
+msgstr "מיפוי ×ורות"
#: drivers/gles2/rasterizer_storage_gles2.cpp
#: drivers/gles3/rasterizer_storage_gles3.cpp
msgid "Use Bicubic Sampling"
-msgstr ""
+msgstr "השתמש בדגימה דו-כיוונית"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Renderable Elements"
-msgstr ""
+msgstr "×ž×§×¡×™×ž×•× ×¨×›×™×‘×™× ×”× ×™×ª× ×™× ×œ×¨×™× ×“×•×¨"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Renderable Lights"
-msgstr ""
+msgstr "×ž×§×¡×™×ž×•× ×ורות × ×™×ª× ×™× ×œ×¨×™× ×“×•×¨"
#: drivers/gles3/rasterizer_scene_gles3.cpp
#, fuzzy
@@ -1046,11 +1016,11 @@ msgstr "GridMap מחיקת הבחירה"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Lights Per Object"
-msgstr ""
+msgstr "×ž×§×¡×™×ž×•× ×ורות לכל ×ובייקט"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Subsurface Scattering"
-msgstr ""
+msgstr "פיזור תת-שטח"
#: drivers/gles3/rasterizer_scene_gles3.cpp editor/animation_track_editor.cpp
#: editor/import/resource_importer_texture.cpp
@@ -1067,15 +1037,15 @@ msgstr "קנה מידה"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Follow Surface"
-msgstr ""
+msgstr "עקוב ×חר פני השטח"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Weight Samples"
-msgstr ""
+msgstr "דוגמ×ות משקל"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Voxel Cone Tracing"
-msgstr ""
+msgstr "מעקב חרוט ווקסל"
#: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp
msgid "High Quality"
@@ -1192,7 +1162,7 @@ msgstr "כמות:"
#: editor/animation_track_editor.cpp main/main.cpp
#: modules/mono/mono_gd/gd_mono.cpp
msgid "Args"
-msgstr ""
+msgstr "×רגומנטי×"
#: editor/animation_track_editor.cpp editor/editor_settings.cpp
#: editor/script_editor_debugger.cpp modules/gltf/gltf_accessor.cpp
@@ -1214,7 +1184,7 @@ msgstr ""
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp
msgid "Stream"
-msgstr ""
+msgstr "זר×"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -1238,7 +1208,7 @@ msgstr "הנפשה"
#: editor/animation_track_editor.cpp
msgid "Easing"
-msgstr ""
+msgstr "הקלה (×נימציה)"
#: editor/animation_track_editor.cpp
msgid "Anim Multi Change Keyframe Time"
@@ -1373,7 +1343,7 @@ msgstr "קנה מידה:"
#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Type:"
-msgstr ""
+msgstr "סוג:"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -1466,7 +1436,7 @@ msgstr "שכפול מפתח(ות)"
#: editor/animation_track_editor.cpp
msgid "Add RESET Value(s)"
-msgstr ""
+msgstr "הוסף ערכי ×יפוס"
#: editor/animation_track_editor.cpp
msgid "Delete Key(s)"
@@ -2232,7 +2202,7 @@ msgstr "פתיחה"
#: editor/dependency_editor.cpp
msgid "Owners of: %s (Total: %d)"
-msgstr ""
+msgstr "×‘×¢×œ×™× ×©×œ: %s (סה\"×›: %d)"
#: editor/dependency_editor.cpp
msgid ""
@@ -2645,7 +2615,7 @@ msgstr "×©× ×©×’×•×™."
#: editor/editor_autoload_settings.cpp
msgid "Cannot begin with a digit."
-msgstr ""
+msgstr "×œ× × ×™×ª×Ÿ להתחיל ×¢× ×¡×™×¤×¨×”."
#: editor/editor_autoload_settings.cpp
msgid "Valid characters:"
@@ -2790,7 +2760,7 @@ msgstr "בחירה"
#: editor/editor_export.cpp
msgid "Project export for platform:"
-msgstr ""
+msgstr "×™×™×¦×•× ×¤×¨×•×™×§×˜ לפלטפורמה:"
#: editor/editor_export.cpp
#, fuzzy
@@ -2908,7 +2878,7 @@ msgstr "חברי×"
#: platform/javascript/export/export.cpp platform/osx/export/export.cpp
#: platform/uwp/export/export.cpp
msgid "Release"
-msgstr ""
+msgstr "שחרר"
#: editor/editor_export.cpp
#, fuzzy
@@ -2917,7 +2887,7 @@ msgstr "התמרה"
#: editor/editor_export.cpp
msgid "64 Bits"
-msgstr ""
+msgstr "64 ביטי×"
#: editor/editor_export.cpp
msgid "Embed PCK"
@@ -2930,23 +2900,23 @@ msgstr "מצב שינוי קנה מידה (R)"
#: editor/editor_export.cpp
msgid "BPTC"
-msgstr ""
+msgstr "BPTC"
#: editor/editor_export.cpp platform/osx/export/export.cpp
msgid "S3TC"
-msgstr ""
+msgstr "S3TC"
#: editor/editor_export.cpp platform/osx/export/export.cpp
msgid "ETC"
-msgstr ""
+msgstr "ETC"
#: editor/editor_export.cpp platform/osx/export/export.cpp
msgid "ETC2"
-msgstr ""
+msgstr "ETC2"
#: editor/editor_export.cpp
msgid "No BPTC Fallbacks"
-msgstr ""
+msgstr "×ין חזרות BPTC"
#: editor/editor_export.cpp platform/android/export/export_plugin.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -2991,7 +2961,7 @@ msgstr "×‘×™×™×¦×•× ×רכיטקטורת 32 ביט, ×” PCK המובנה ×œ× ×™
#: editor/editor_export.cpp
msgid "Convert Text Resources To Binary On Export"
-msgstr ""
+msgstr "המרת מש×בי טקסט לבינ××¨×™×™× ×‘×™×™×¦×•×"
#: editor/editor_feature_profile.cpp
msgid "3D Editor"
@@ -3315,7 +3285,7 @@ msgstr "הצג/הסתר ×§×‘×¦×™× ×ž×•×¡×ª×¨×™×"
#: editor/editor_file_dialog.cpp
msgid "Disable Overwrite Warning"
-msgstr ""
+msgstr "השבת ×ת ×זהרת החלפה"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
@@ -3471,16 +3441,16 @@ msgstr "קבועי×"
#: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Fonts"
-msgstr ""
+msgstr "גופני×"
#: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp
#: platform/iphone/export/export.cpp
msgid "Icons"
-msgstr ""
+msgstr "סמלי×"
#: editor/editor_help.cpp
msgid "Styles"
-msgstr ""
+msgstr "סגנונות"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -3530,7 +3500,7 @@ msgstr "עזרה"
#: editor/editor_help.cpp
msgid "Sort Functions Alphabetically"
-msgstr ""
+msgstr "מיון פונקציות בסדר ×לפביתי"
#: editor/editor_help_search.cpp editor/editor_node.cpp
#: editor/plugins/script_editor_plugin.cpp
@@ -3622,7 +3592,7 @@ msgstr "מתודות בלבד"
#: editor/editor_inspector.cpp editor/plugins/item_list_editor_plugin.cpp
msgid "Checkable"
-msgstr ""
+msgstr "ניתן לבדיקה"
#: editor/editor_inspector.cpp editor/plugins/item_list_editor_plugin.cpp
#: scene/resources/default_theme/default_theme.cpp
@@ -3648,11 +3618,11 @@ msgstr "(ערך)"
#: editor/editor_inspector.cpp
msgid ""
"Pinning a value forces it to be saved even if it's equal to the default."
-msgstr ""
+msgstr "הצמדת ערך מ×לצת ×ותו להישמר ×’× ×× ×”×•× ×©×•×•×” לברירת המחדל."
#: editor/editor_inspector.cpp
msgid "Pin value [Disabled because '%s' is editor-only]"
-msgstr ""
+msgstr "הצמדת ערך [מושבת מכיוון ש- '%s' ×”×•× ×œ-עורך בלבד]"
#: editor/editor_inspector.cpp
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -3669,11 +3639,11 @@ msgstr "קביעה מרובה:"
#: editor/editor_inspector.cpp
msgid "Pinned %s"
-msgstr ""
+msgstr "הוצמד %s"
#: editor/editor_inspector.cpp
msgid "Unpinned %s"
-msgstr ""
+msgstr "בוטלה ההצמדה של %s"
#: editor/editor_inspector.cpp
#, fuzzy
@@ -3761,7 +3731,7 @@ msgstr "חלון חדש"
#: editor/editor_node.cpp editor/project_manager.cpp
msgid "Unnamed Project"
-msgstr ""
+msgstr "פרויקט ×œ×œ× ×©×"
#: editor/editor_node.cpp
msgid ""
@@ -3769,6 +3739,9 @@ msgid ""
"Update Continuously is enabled, which can increase power usage. Click to "
"disable it."
msgstr ""
+"מסתובב ×›×שר חלון העורך מצייר מחדש.\n"
+"×”×פשרות 'עדכן רציף' מופעלת, מה שעלול להגביר ×ת צריכת החשמל. לחץ כדי להשבית "
+"×ותו."
#: editor/editor_node.cpp
msgid "Spins when the editor window redraws."
@@ -3895,6 +3868,8 @@ msgid ""
"An error occurred while trying to save the editor layout.\n"
"Make sure the editor's user data path is writable."
msgstr ""
+"×ירעה שגי××” בעת ניסיון לשמור ×ת פריסת העורך.\n"
+"×•×“× ×©× ×ª×™×‘ נתוני המשתמש של העורך ניתן לכתיבה."
#: editor/editor_node.cpp
msgid ""
@@ -3902,6 +3877,9 @@ msgid ""
"To restore the Default layout to its base settings, use the Delete Layout "
"option and delete the Default layout."
msgstr ""
+"פריסת עורך ברירת המחדל נדרסת.\n"
+"כדי לשחזר ×ת פריסת ברירת המחדל להגדרות הבסיס שלה, השתמש ב×פשרות מחק פריסה "
+"ומחק ×ת פריסת ברירת המחדל."
#: editor/editor_node.cpp
msgid "Layout name not found!"
@@ -3963,7 +3941,7 @@ msgstr "×ין סצנה מוגדרת להרצה."
#: editor/editor_node.cpp
msgid "Save scene before running..."
-msgstr ""
+msgstr "שמור סצנה לפני ריצה..."
#: editor/editor_node.cpp
msgid "Could not start subprocess!"
@@ -4009,13 +3987,14 @@ msgstr "לשמור ×ת ×”×©×™× ×•×™×™× ×œÖ¾'%s' לפני הסגירה?"
#: editor/editor_node.cpp
msgid "%s no longer exists! Please specify a new save location."
-msgstr ""
+msgstr "%s כבר ×œ× ×§×™×™×! × × ×œ×¦×™×™×Ÿ ×ž×™×§×•× ×©×ž×™×¨×” חדש."
#: editor/editor_node.cpp
msgid ""
"The current scene has no root node, but %d modified external resource(s) "
"were saved anyway."
msgstr ""
+"לסצנה הנוכחית ×ין צומת שורש, ×ך %d מש××‘×™× ×—×™×¦×•× ×™×™× ×©×©×•× ×• נשמרו בכל מקרה."
#: editor/editor_node.cpp
#, fuzzy
@@ -11258,7 +11237,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/hi.po b/editor/translations/hi.po
index 657ee0ff41..229a1e6ee7 100644
--- a/editor/translations/hi.po
+++ b/editor/translations/hi.po
@@ -11065,7 +11065,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/hr.po b/editor/translations/hr.po
index 85fcb184f3..d3ea72cf63 100644
--- a/editor/translations/hr.po
+++ b/editor/translations/hr.po
@@ -8,12 +8,13 @@
# LeoClose <leoclose575@gmail.com>, 2020, 2021, 2022.
# Filip <fhomolka@protonmail.com>, 2022.
# Milo Ivir <mail@milotype.de>, 2022.
+# peter277 <ps2718@hotmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
-"PO-Revision-Date: 2022-09-27 21:37+0000\n"
-"Last-Translator: Milo Ivir <mail@milotype.de>\n"
+"PO-Revision-Date: 2022-12-21 07:02+0000\n"
+"Last-Translator: peter277 <ps2718@hotmail.com>\n"
"Language-Team: Croatian <https://hosted.weblate.org/projects/godot-engine/"
"godot/hr/>\n"
"Language: hr\n"
@@ -21,7 +22,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.14.1\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -3432,7 +3433,7 @@ msgstr ""
#: editor/editor_help.cpp
msgid "Enumerations"
-msgstr ""
+msgstr "Nabrajanja"
#: editor/editor_help.cpp
msgid "Property Descriptions"
@@ -10824,7 +10825,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/hu.po b/editor/translations/hu.po
index b8bab10568..ad7ba523e3 100644
--- a/editor/translations/hu.po
+++ b/editor/translations/hu.po
@@ -11273,7 +11273,7 @@ msgstr "Perspektíva"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/id.po b/editor/translations/id.po
index 89153d88d3..47b026986a 100644
--- a/editor/translations/id.po
+++ b/editor/translations/id.po
@@ -41,13 +41,14 @@
# Primananda Kurnia <primakurnia71@gmail.com>, 2022.
# FellowMustard <rachmawanng33@gmail.com>, 2022.
# Muhammad Zainal Abidin <eviepk12@gmail.com>, 2022.
+# adfriz <aditiyaafrizal2@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-09-27 21:37+0000\n"
-"Last-Translator: Muhammad Zainal Abidin <eviepk12@gmail.com>\n"
+"PO-Revision-Date: 2023-01-04 10:47+0000\n"
+"Last-Translator: adfriz <aditiyaafrizal2@gmail.com>\n"
"Language-Team: Indonesian <https://hosted.weblate.org/projects/godot-engine/"
"godot/id/>\n"
"Language: id\n"
@@ -55,7 +56,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.14.1\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -11181,7 +11182,7 @@ msgstr "Perspektif Belakang"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portal aktif]"
@@ -20765,9 +20766,8 @@ msgid "Executable \"pck\" section not found."
msgstr ""
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Windows"
-msgstr "Jendela Baru"
+msgstr "Windows"
#: platform/windows/export/export.cpp
msgid "Rcedit"
diff --git a/editor/translations/ig.po b/editor/translations/ig.po
index e0c1a85c99..9acd1e98b7 100644
--- a/editor/translations/ig.po
+++ b/editor/translations/ig.po
@@ -10569,7 +10569,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/is.po b/editor/translations/is.po
index 7551598f22..fda8086f4b 100644
--- a/editor/translations/is.po
+++ b/editor/translations/is.po
@@ -10792,7 +10792,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/it.po b/editor/translations/it.po
index f1ff871a69..6010f082aa 100644
--- a/editor/translations/it.po
+++ b/editor/translations/it.po
@@ -73,7 +73,7 @@
# ale piccia <picciatialessio2@gmail.com>, 2022.
# Simone Starace <simone.starace93@gmail.com>, 2022.
# Daniele Giunta <danielegiunta2007@gmail.com>, 2022.
-# Damiano Guida <damiano.guida22@gmail.com>, 2022.
+# Damiano Guida <damiano.guida22@gmail.com>, 2022, 2023.
# Silvia Scaglione <sissisoad@gmail.com>, 2022.
# Cosimo Davide Viggiano <cosimod089@gmail.com>, 2022.
# Francesco Cammarata <francescocammarata.fr@gmail.com>, 2022.
@@ -82,8 +82,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-11-22 20:37+0000\n"
-"Last-Translator: Francesco Cammarata <francescocammarata.fr@gmail.com>\n"
+"PO-Revision-Date: 2023-01-15 13:34+0000\n"
+"Last-Translator: Damiano Guida <damiano.guida22@gmail.com>\n"
"Language-Team: Italian <https://hosted.weblate.org/projects/godot-engine/"
"godot/it/>\n"
"Language: it\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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -11031,7 +11031,7 @@ msgstr "Prospettica da dietro"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portali attivi]"
@@ -26477,7 +26477,7 @@ msgstr "Debug del Canale UV"
#: scene/resources/environment.cpp
msgid "Blur"
-msgstr ""
+msgstr "Sfocatura"
#: scene/resources/environment.cpp
msgid "Edge Sharpness"
diff --git a/editor/translations/ja.po b/editor/translations/ja.po
index dc17329ba7..e7016610d7 100644
--- a/editor/translations/ja.po
+++ b/editor/translations/ja.po
@@ -46,13 +46,13 @@
# Fire Dingo <snowsable113@icloud.com>, 2022.
# Narazaki Shuji <shujinarazaki@protonmail.com>, 2022.
# ta ko <neji.cion@gmail.com>, 2022.
-# T K <kidaaam@gmail.com>, 2022.
+# T K <kidaaam@gmail.com>, 2022, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-12-13 13:21+0000\n"
+"PO-Revision-Date: 2023-01-20 10:19+0000\n"
"Last-Translator: T K <kidaaam@gmail.com>\n"
"Language-Team: Japanese <https://hosted.weblate.org/projects/godot-engine/"
"godot/ja/>\n"
@@ -61,7 +61,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.15-dev\n"
+"X-Generator: Weblate 4.15.1\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -886,7 +886,6 @@ msgid "Connect Timeout Seconds"
msgstr "接続タイムアウトã®ç§’æ•°"
#: core/register_core_types.cpp
-#, fuzzy
msgid "Packet Peer Stream"
msgstr "パケットピアストリーム"
@@ -5288,12 +5287,11 @@ msgstr "ダイアログã®ãƒãƒƒãƒ—アップ時ã«ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼ã‚’è–„æš—ãã™
#: editor/editor_settings.cpp main/main.cpp
msgid "Low Processor Mode Sleep (µsec)"
-msgstr "低プロセッサ モード スリープ (マイクロ秒)"
+msgstr "çœã‚¨ãƒãƒ¢ãƒ¼ãƒ‰ã‚¹ãƒªãƒ¼ãƒ—時間 (マイクロ秒)"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Unfocused Low Processor Mode Sleep (µsec)"
-msgstr "フォーカスã•ã‚Œã¦ã„ãªã„低プロセッサ モード スリープ (マイクロ秒)"
+msgstr "éžãƒ•ã‚©ãƒ¼ã‚«ã‚¹æ™‚ã®çœã‚¨ãƒãƒ¢ãƒ¼ãƒ‰ã‚¹ãƒªãƒ¼ãƒ—時間 (マイクロ秒)"
#: editor/editor_settings.cpp
msgid "Separate Distraction Mode"
@@ -5346,9 +5344,8 @@ msgid "Border Size"
msgstr "ボーダーサイズ"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Use Graph Node Headers"
-msgstr "グラフ ノード ヘッダーを使用ã™ã‚‹"
+msgstr "グラフノードヘッダーを使用ã™ã‚‹"
#: editor/editor_settings.cpp
msgid "Additional Spacing"
@@ -5690,9 +5687,8 @@ msgid "Secondary Grid Color"
msgstr "グリッドã®ã‚»ã‚«ãƒ³ãƒ€ãƒªã®è‰²"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Selection Box Color"
-msgstr "é¸æŠžç¯„囲ã®ã¿"
+msgstr "é¸æŠžãƒœãƒƒã‚¯ã‚¹ã®è‰²"
#: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
@@ -5795,19 +5791,16 @@ msgid "Emulate 3 Button Mouse"
msgstr "3ボタンマウスをエミュレート"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Orbit Modifier"
-msgstr "更新日時ãŒå¤ã„é †ã§ä¸¦ã³æ›¿ãˆ"
+msgstr "オービットæ“作ã®ä¿®é£¾ã‚­ãƒ¼"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Pan Modifier"
-msgstr "パンモード"
+msgstr "パンæ“作ã®ä¿®é£¾ã‚­ãƒ¼"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Zoom Modifier"
-msgstr "変更済ã¿"
+msgstr "ズームæ“作ã®ä¿®é£¾ã‚­ãƒ¼"
#: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp
#, fuzzy
@@ -5815,38 +5808,32 @@ msgid "Warped Mouse Panning"
msgstr "ワープマウスパンニング"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Navigation Feel"
-msgstr "ナビゲーションモード"
+msgstr "ナビゲーション感度"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Orbit Sensitivity"
-msgstr "軌é“感度"
+msgstr "オービット感度"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Orbit Inertia"
-msgstr "軌é“慣性"
+msgstr "オービット慣性"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Translation Inertia"
-msgstr "翻訳"
+msgstr "移動ã®æ…£æ€§"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Zoom Inertia"
-msgstr "ズームイン"
+msgstr "ズームã®æ…£æ€§"
#: editor/editor_settings.cpp
msgid "Freelook"
msgstr "フリールック"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Navigation Scheme"
-msgstr "ナビゲーションメッシュを生æˆ"
+msgstr "フリールックナビゲーション方å¼"
#: editor/editor_settings.cpp
msgid "Freelook Sensitivity"
@@ -5861,14 +5848,12 @@ msgid "Freelook Base Speed"
msgstr "フリールックã®åŸºæœ¬é€Ÿåº¦"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Activation Modifier"
-msgstr "フリールックã®æ¸›é€Ÿèª¿æ•´"
+msgstr "フリールック有効化ã®ä¿®é£¾ã‚­ãƒ¼"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Speed Zoom Link"
-msgstr "フリールックã®é€Ÿåº¦èª¿æ•´"
+msgstr "フリールックã®é€Ÿåº¦ã‚’ズーム値ã«ãƒªãƒ³ã‚¯"
#: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp
msgid "Grid Color"
@@ -5915,14 +5900,12 @@ msgid "Viewport Border Color"
msgstr "ビューãƒãƒ¼ãƒˆã®ãƒœãƒ¼ãƒ€ãƒ¼ã®è‰²"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Constrain Editor View"
-msgstr "エディター ビューを制é™"
+msgstr "エディタビューをæŸç¸›ã™ã‚‹"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Simple Panning"
-msgstr "簡易パンニング"
+msgstr "簡易パンニングæ“作"
#: editor/editor_settings.cpp
#, fuzzy
@@ -5930,23 +5913,20 @@ msgid "Scroll To Pan"
msgstr "スクロールã—ã¦ãƒ‘ンニング"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Pan Speed"
-msgstr "速度:"
+msgstr "パン速度"
#: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp
msgid "Poly Editor"
msgstr "ãƒãƒªã‚´ãƒ³ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Point Grab Radius"
-msgstr "ãƒã‚¤ãƒ³ãƒˆã‚°ãƒ©ãƒ–åŠå¾„"
+msgstr "ãƒã‚¤ãƒ³ãƒˆã®é¸æŠžåŠå¾„"
#: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Show Previous Outline"
-msgstr "å‰ã®å¹³é¢"
+msgstr "å‰ã®ã‚¢ã‚¦ãƒˆãƒ©ã‚¤ãƒ³ã‚’表示ã™ã‚‹"
#: editor/editor_settings.cpp editor/scene_tree_dock.cpp
msgid "Autorename Animation Tracks"
@@ -5961,19 +5941,16 @@ msgid "Default Create Reset Tracks"
msgstr "デフォルトã§RESETトラックを作æˆ"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Onion Layers Past Color"
msgstr "オニオンレイヤーéŽåŽ»ã®è‰²"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Onion Layers Future Color"
msgstr "オニオンレイヤー将æ¥ã®è‰²"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Visual Editors"
-msgstr "グループエディター"
+msgstr "ビジュアルエディター"
#: editor/editor_settings.cpp
msgid "Minimap Opacity"
@@ -6086,29 +6063,24 @@ msgid "Background Color"
msgstr "背景色"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Background Color"
-msgstr "無効ãªèƒŒæ™¯è‰²ã§ã™ã€‚"
+msgstr "補完ã®èƒŒæ™¯è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Selected Color"
-msgstr "é¸æŠžã•ã‚ŒãŸã‚‚ã®ã‚’インãƒãƒ¼ãƒˆ"
+msgstr "補完ã®é¸æŠžä¸­ã®è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Existing Color"
-msgstr "既存ã®è‰²ã®è£œå®Œ"
+msgstr "æ—¢ã«è£œå®Œã•ã‚Œã¦ã„る箇所ã®è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Scroll Color"
-msgstr "スクロール色ã®è£œå®Œ"
+msgstr "補完ウインドウã®ã‚¹ã‚¯ãƒ­ãƒ¼ãƒ«è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Font Color"
-msgstr "フォント色ã®è£œå®Œ"
+msgstr "補完ã®ãƒ•ã‚©ãƒ³ãƒˆè‰²"
#: editor/editor_settings.cpp
msgid "Text Color"
@@ -6135,9 +6107,8 @@ msgid "Text Selected Color"
msgstr "é¸æŠžã•ã‚ŒãŸãƒ†ã‚­ã‚¹ãƒˆã®è‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Selection Color"
-msgstr "é¸æŠžç¯„囲ã®ã¿"
+msgstr "é¸æŠžè‰²"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Brace Mismatch Color"
@@ -7235,14 +7206,12 @@ msgid "Fix Alpha Border"
msgstr "アルファボーダーを修正"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Premult Alpha"
-msgstr "ãƒãƒªã‚´ãƒ³ã‚’編集"
+msgstr "乗算済ã¿ã‚¢ãƒ«ãƒ•ã‚¡"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Hdr As Srgb"
-msgstr "Srgbã¨ã—ã¦Hdr"
+msgstr "HDRã‚’sRGBã¨ã—ã¦è¡¨ç¤º"
#: editor/import/resource_importer_texture.cpp
msgid "Invert Color"
@@ -10980,7 +10949,7 @@ msgstr "å¾Œé¢ é€è¦–投影"
msgid " [auto]"
msgstr " [自動]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [ãƒãƒ¼ã‚¿ãƒ«æœ‰åŠ¹]"
@@ -14136,6 +14105,8 @@ msgid ""
"Note: Encryption key needs to be stored in the binary,\n"
"you need to build the export templates from source."
msgstr ""
+"注:æš—å·åŒ–キーã¯ãƒã‚¤ãƒŠãƒªã«æ ¼ç´ã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚\n"
+"ソースã‹ã‚‰ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãƒ†ãƒ³ãƒ—レートをビルドã™ã‚‹å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
#: editor/project_export.cpp
msgid "More Info..."
@@ -14242,17 +14213,15 @@ msgid "Invalid project path (changed anything?)."
msgstr "無効ãªãƒ—ロジェクトパスã§ã™ (ãªã«ã‹å¤‰æ›´ãŒã‚ã‚Šã¾ã—ãŸã‹ï¼Ÿ)。"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
msgstr ""
-"プロジェクトパス㮠project.godot を読ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸã€‚ (エラー %d)。見ã¤ã‹"
-"らãªã„ã‹ç ´æã—ã¦ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚"
+"%s ã®ãƒ—ロジェクトを読ã¿è¾¼ã‚ã¾ã›ã‚“ã§ã—ãŸã€‚ (エラー %d)。見ã¤ã‹ã‚‰ãªã„ã‹ç ´æã—ã¦"
+"ã„ã‚‹å¯èƒ½æ€§ãŒã‚ã‚Šã¾ã™ã€‚"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Couldn't save project at '%s' (error %d)."
-msgstr "次ã®å ´æ‰€ã®ãƒ—ロジェクトを開ã‘ã¾ã›ã‚“ '%s'。"
+msgstr "プロジェクトを '%s' ã«ä¿å­˜ã§ãã¾ã›ã‚“ã§ã—㟠(エラー %d)。"
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
@@ -15510,6 +15479,9 @@ msgid ""
"with the '%s' prefix in a node path.\n"
"Click to disable this."
msgstr ""
+"ã“ã®ãƒŽãƒ¼ãƒ‰ã«ã¯ã€ãƒŽãƒ¼ãƒ‰ パスã®å…ˆé ­ã« '%s' プレフィックスを付ã‘ã‚‹ã“ã¨ã§ã€ã‚·ãƒ¼ãƒ³"
+"内ã®ã©ã“ã‹ã‚‰ã§ã‚‚アクセスã§ãã¾ã™ã€‚\n"
+"クリックã™ã‚‹ã¨ç„¡åŠ¹ã«ãªã‚Šã¾ã™ã€‚"
#: editor/scene_tree_editor.cpp
msgid ""
@@ -15911,7 +15883,7 @@ msgstr "å…‰æºã®åŠå¾„を変更"
#: editor/spatial_editor_gizmos.cpp
msgid "Stream Player 3D"
-msgstr ""
+msgstr "ストリームプレイヤー3D"
#: editor/spatial_editor_gizmos.cpp
msgid "Change AudioStreamPlayer3D Emission Angle"
@@ -15933,7 +15905,7 @@ msgstr "カメラサイズを変更"
#: editor/spatial_editor_gizmos.cpp
msgid "Visibility Notifier"
-msgstr ""
+msgstr "å¯è¦–性通知"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Notifier AABB"
@@ -15941,7 +15913,7 @@ msgstr "Notifierã®AABBを変更"
#: editor/spatial_editor_gizmos.cpp
msgid "Change Particles AABB"
-msgstr "パーティクルã®è»¸å¹³è¡Œå¢ƒç•Œãƒœãƒƒã‚¯ã‚¹ã‚’変更"
+msgstr "パーティクルã®AABBを変更"
#: editor/spatial_editor_gizmos.cpp
msgid "Reflection Probe"
@@ -16113,9 +16085,8 @@ msgid "RID Pool Prealloc"
msgstr "RIDプールã®äº‹å‰å‰²ã‚Šå½“ã¦"
#: main/main.cpp
-#, fuzzy
msgid "Debugger stdout"
-msgstr "デãƒãƒƒã‚¬ãƒ¼"
+msgstr "デãƒãƒƒã‚¬ãƒ¼ã®æ¨™æº–出力"
#: main/main.cpp
msgid "Max Chars Per Second"
@@ -16155,7 +16126,7 @@ msgstr "ログã®ãƒ‘ス"
#: main/main.cpp
msgid "Max Log Files"
-msgstr ""
+msgstr "最大ログファイル数"
#: main/main.cpp
msgid "Driver"
@@ -16195,7 +16166,7 @@ msgstr "ピクセルå˜ä½ã®é€æ˜Žåº¦"
#: main/main.cpp
msgid "Allowed"
-msgstr ""
+msgstr "許å¯"
#: main/main.cpp
msgid "Intended Usage"
@@ -16206,9 +16177,8 @@ msgid "Framebuffer Allocation"
msgstr "フレームãƒãƒƒãƒ•ã‚¡ã®å‰²ã‚Šå½“ã¦"
#: main/main.cpp platform/uwp/os_uwp.cpp
-#, fuzzy
msgid "Energy Saving"
-msgstr "ä¿å­˜ä¸­ã«ã‚¨ãƒ©ãƒ¼ãŒç™ºç”Ÿã—ã¾ã—ãŸ"
+msgstr "çœã‚¨ãƒãƒ«ã‚®ãƒ¼"
#: main/main.cpp
msgid "Threads"
@@ -16224,32 +16194,29 @@ msgstr "スレッドセーフãªBVH"
#: main/main.cpp
msgid "Handheld"
-msgstr ""
+msgstr "ãƒãƒ¼ã‚¿ãƒ–ル"
#: main/main.cpp platform/javascript/export/export.cpp
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Orientation"
-msgstr "オンラインドキュメント"
+msgstr "æ–¹å‘"
#: main/main.cpp scene/gui/scroll_container.cpp scene/gui/text_edit.cpp
#: scene/main/scene_tree.cpp scene/register_scene_types.cpp
-#, fuzzy
msgid "Common"
-msgstr "コミュニティ"
+msgstr "一般"
#: main/main.cpp
msgid "Physics FPS"
msgstr "物ç†FPS"
#: main/main.cpp
-#, fuzzy
msgid "Force FPS"
-msgstr "強制プッシュ"
+msgstr "強制FPS"
#: main/main.cpp
msgid "Enable Pause Aware Picking"
-msgstr ""
+msgstr "一時åœæ­¢ä¸­ã®é¸æŠžèªè­˜ã®æœ‰åŠ¹åŒ–"
#: main/main.cpp scene/gui/item_list.cpp scene/gui/popup_menu.cpp
#: scene/gui/scroll_container.cpp scene/gui/text_edit.cpp scene/gui/tree.cpp
@@ -16287,11 +16254,11 @@ msgstr "フレームé…延 (ミリ秒)"
#: main/main.cpp
msgid "Low Processor Mode"
-msgstr ""
+msgstr "低プロセッサモード"
#: main/main.cpp
msgid "Delta Sync After Draw"
-msgstr ""
+msgstr "æ画後ã®ãƒ‡ãƒ«ã‚¿åŒæœŸ"
#: main/main.cpp
msgid "iOS"
@@ -16299,7 +16266,7 @@ msgstr "iOS"
#: main/main.cpp
msgid "Hide Home Indicator"
-msgstr ""
+msgstr "ホームインジケーターを隠ã™"
#: main/main.cpp
msgid "Input Devices"
@@ -16322,9 +16289,8 @@ msgid "Shaders"
msgstr "シェーダー"
#: main/main.cpp
-#, fuzzy
msgid "Debug Shader Fallbacks"
-msgstr "シェーダーフォールãƒãƒƒã‚¯ã‚’強制"
+msgstr "シェーダーフォールãƒãƒƒã‚¯ã®ãƒ‡ãƒãƒƒã‚°"
#: main/main.cpp scene/3d/baked_lightmap.cpp scene/3d/camera.cpp
#: scene/3d/world_environment.cpp scene/main/scene_tree.cpp
@@ -16334,16 +16300,15 @@ msgstr "環境"
#: main/main.cpp
msgid "Default Clear Color"
-msgstr ""
+msgstr "デフォルトã®ã‚¯ãƒªã‚¢ãƒ¼è‰²"
#: main/main.cpp
msgid "Boot Splash"
msgstr "ブートスプラッシュ"
#: main/main.cpp
-#, fuzzy
msgid "Show Image"
-msgstr "ボーンを表示ã™ã‚‹"
+msgstr "ç”»åƒã‚’表示"
#: main/main.cpp
msgid "Image"
@@ -16375,7 +16340,7 @@ msgstr "ãƒãƒƒãƒ•ã‚¡ãƒªãƒ³ã‚°"
#: main/main.cpp
msgid "Agile Event Flushing"
-msgstr ""
+msgstr "å³åº§ã«ã‚¤ãƒ™ãƒ³ãƒˆãƒ•ãƒ©ãƒƒã‚·ãƒ¥"
#: main/main.cpp
msgid "Emulate Touch From Mouse"
@@ -16390,13 +16355,12 @@ msgid "Mouse Cursor"
msgstr "マウスカーソル"
#: main/main.cpp
-#, fuzzy
msgid "Custom Image"
-msgstr "ノードを切りå–ã‚‹"
+msgstr "カスタムイメージ"
#: main/main.cpp
msgid "Custom Image Hotspot"
-msgstr ""
+msgstr "カスタムイメージホットスãƒãƒƒãƒˆ"
#: main/main.cpp
msgid "Tooltip Position Offset"
@@ -16441,12 +16405,11 @@ msgstr "縮å°"
#: main/main.cpp scene/main/scene_tree.cpp
msgid "Auto Accept Quit"
-msgstr ""
+msgstr "プログラム終了を自動的ã«å—ã‘入れる"
#: main/main.cpp scene/main/scene_tree.cpp
-#, fuzzy
msgid "Quit On Go Back"
-msgstr "戻る"
+msgstr "「戻るã€æ™‚ã«ãƒ—ログラム終了ã™ã‚‹"
#: main/main.cpp scene/main/viewport.cpp
msgid "Snap Controls To Pixels"
@@ -16462,7 +16425,7 @@ msgstr "オーãƒãƒ¼ã‚µãƒ³ãƒ—リングを使用"
#: modules/bullet/register_types.cpp modules/bullet/space_bullet.cpp
msgid "Active Soft World"
-msgstr ""
+msgstr "SoftBodyを有効ã«ã™ã‚‹"
#: modules/csg/csg_gizmos.cpp
msgid "CSG"
@@ -16478,11 +16441,11 @@ msgstr "円柱ã®é«˜ã•ã‚’変更"
#: modules/csg/csg_gizmos.cpp
msgid "Change Torus Inner Radius"
-msgstr "トーラスã®å†…径を変更"
+msgstr "トーラスã®å†…åŠå¾„を変更"
#: modules/csg/csg_gizmos.cpp
msgid "Change Torus Outer Radius"
-msgstr "トーラスã®å¤–径を変更"
+msgstr "トーラスã®å¤–åŠå¾„を変更"
#: modules/csg/csg_shape.cpp
msgid "Operation"
@@ -16546,14 +16509,12 @@ msgid "Cone"
msgstr "円éŒ"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Inner Radius"
-msgstr "トーラスã®å†…径を変更"
+msgstr "内åŠå¾„"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Outer Radius"
-msgstr "トーラスã®å¤–径を変更"
+msgstr "外åŠå¾„"
#: modules/csg/csg_shape.cpp
msgid "Ring Sides"
@@ -16629,17 +16590,16 @@ msgid "Channel Count"
msgstr "ãƒãƒ£ãƒ³ãƒãƒ«ã®æ•°"
#: modules/enet/networked_multiplayer_enet.cpp
-#, fuzzy
msgid "Always Ordered"
-msgstr "常ã«ã‚°ãƒªãƒƒãƒ‰ã‚’表示"
+msgstr "常ã«é †åºä»˜ã‘ã‚’ã™ã‚‹"
#: modules/enet/networked_multiplayer_enet.cpp
msgid "Server Relay"
-msgstr ""
+msgstr "サーãƒãƒ¼ãƒªãƒ¬ãƒ¼"
#: modules/enet/networked_multiplayer_enet.cpp
msgid "DTLS Verify"
-msgstr ""
+msgstr "DTLS 検証"
#: modules/enet/networked_multiplayer_enet.cpp
msgid "DTLS Hostname"
@@ -18014,17 +17974,16 @@ msgid "in order:"
msgstr ""
#: modules/visual_script/visual_script_flow_control.cpp
-#, fuzzy
msgid "Steps"
msgstr "ステップ"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Switch"
-msgstr ""
+msgstr "スイッãƒ"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "'input' is:"
-msgstr ""
+msgstr "入力ã¯:"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Type Cast"
@@ -18273,14 +18232,12 @@ msgid "Construct %s"
msgstr "定数"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Get Local Var"
-msgstr "ローカル空間を使用"
+msgstr "ローカル変数を使用"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Set Local Var"
-msgstr "ローカル空間を使用"
+msgstr "ローカル変数をセット"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Action %s"
@@ -19552,9 +19509,8 @@ msgstr "コード署å"
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Identity"
-msgstr "インデント"
+msgstr "識別å­"
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
#, fuzzy
@@ -19752,9 +19708,8 @@ msgid ""
msgstr ""
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
-#, fuzzy
msgid "No identity found."
-msgstr "アイコンãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
+msgstr "識別å­ãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
#: platform/osx/export/export.cpp
#, fuzzy
@@ -19818,6 +19773,8 @@ msgid ""
"Ad-hoc signed applications require the 'Disable Library Validation' "
"entitlement to load dynamic libraries."
msgstr ""
+"アドホック署å付ãアプリケーションã§ã¯ã€å‹•çš„ライブラリを読ã¿è¾¼ã‚€ãŸã‚ã«ã€Œãƒ©ã‚¤"
+"ブラリ検証を無効ã«ã™ã‚‹ã€ã®æ¨©é™ãŒå¿…è¦ã§ã™ã€‚"
#: platform/osx/export/export.cpp
msgid "Code signing bundle"
@@ -19848,15 +19805,12 @@ msgid "Sending archive for notarization"
msgstr "公証をã™ã‚‹ãŸã‚ã«ã‚¢ãƒ¼ã‚«ã‚¤ãƒ–ã‚’é€ä¿¡ä¸­"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "ZIP Creation"
-msgstr "プロジェクト"
+msgstr "ZIP作æˆ"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Could not open file to read from path \"%s\"."
-msgstr ""
-"プロジェクトファイルをgladleプロジェクトã«ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“ã§ã—ãŸ\n"
+msgstr "パス \"%s\" ã‹ã‚‰ãƒ•ã‚¡ã‚¤ãƒ«ã‚’é–‹ã‘ã¾ã›ã‚“ã§ã—ãŸã€‚"
#: platform/osx/export/export.cpp
msgid "Invalid bundle identifier:"
@@ -19867,12 +19821,17 @@ msgid ""
"Warning: Built-in \"codesign\" is selected in the Editor Settings. Code "
"signing is limited to ad-hoc signature only."
msgstr ""
+"警告: ビルトインã®ã€Œã‚³ãƒ¼ãƒ‰ç½²åã€ãŒã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼è¨­å®šã§é¸æŠžã•ã‚Œã¦ã„ã¾ã™ã€‚コード署"
+"åã¯ã‚¢ãƒ‰ãƒ›ãƒƒã‚¯ç½²åã®ã¿ã«åˆ¶é™ã•ã‚Œã¦ã„ã¾ã™ã€‚"
#: platform/osx/export/export.cpp
msgid ""
"Warning: Xcode command line tools are not installed, using built-in "
"\"codesign\". Code signing is limited to ad-hoc signature only."
msgstr ""
+"警告: Xcodeã®ã‚³ãƒžãƒ³ãƒ‰ãƒ©ã‚¤ãƒ³ãƒ„ールãŒã‚¤ãƒ³ã‚¹ãƒˆãƒ¼ãƒ«ã•ã‚Œã¦ã„ãªã„ãŸã‚ã€ãƒ“ルトインã®"
+"「コード署åã€ãŒä½¿ç”¨ã•ã‚Œã¾ã™ã€‚コード署åã¯ã‚¢ãƒ‰ãƒ›ãƒƒã‚¯ç½²åã®ã¿ã«åˆ¶é™ã•ã‚Œã¦ã„ã¾"
+"ã™ã€‚"
#: platform/osx/export/export.cpp
msgid "Notarization: Notarization with an ad-hoc signature is not supported."
@@ -19911,17 +19870,19 @@ msgid ""
"Code signing is disabled. The exported project will not run on Macs with "
"enabled Gatekeeper and Apple Silicon powered Macs."
msgstr ""
+"コード署åãŒç„¡åŠ¹ã«ãªã£ã¦ã„ã¾ã™ã€‚エクスãƒãƒ¼ãƒˆã•ã‚ŒãŸãƒ—ロジェクトã¯ã€Gatekeeper "
+"ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã‚‹ Mac ãŠã‚ˆã³ Apple Silicon æ­è¼‰ã® Mac ã§ã¯å‹•ä½œã—ã¾ã›ã‚“。"
#: platform/osx/export/export.cpp
msgid ""
"Hardened Runtime is not compatible with ad-hoc signature, and will be "
"disabled!"
-msgstr ""
+msgstr "Hardened Runtime ã¯ã‚¢ãƒ‰ãƒ›ãƒƒã‚¯ç½²åã¨äº’æ›æ€§ãŒãªã„ãŸã‚ã€ç„¡åŠ¹ã«ãªã‚Šã¾ã™!"
#: platform/osx/export/export.cpp
msgid ""
"Timestamping is not compatible with ad-hoc signature, and will be disabled!"
-msgstr ""
+msgstr "タイムスタンプã¯ã‚¢ãƒ‰ãƒ›ãƒƒã‚¯ç½²åã¨äº’æ›æ€§ãŒãªã„ãŸã‚ã€ç„¡åŠ¹ã«ãªã‚Šã¾ã™!"
#: platform/osx/export/export.cpp
msgid ""
@@ -19937,34 +19898,46 @@ msgid ""
"Privacy: Microphone access is enabled, but usage description is not "
"specified."
msgstr ""
+"プライãƒã‚·ãƒ¼: マイクã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒã‚ã‚Š"
+"ã¾ã›ã‚“。"
#: platform/osx/export/export.cpp
msgid ""
"Privacy: Camera access is enabled, but usage description is not specified."
msgstr ""
+"プライãƒã‚·ãƒ¼: カメラã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒã‚ã‚Š"
+"ã¾ã›ã‚“。"
#: platform/osx/export/export.cpp
msgid ""
"Privacy: Location information access is enabled, but usage description is "
"not specified."
msgstr ""
+"プライãƒã‚·ãƒ¼: ä½ç½®æƒ…å ±ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒã‚"
+"ã‚Šã¾ã›ã‚“。"
#: platform/osx/export/export.cpp
msgid ""
"Privacy: Address book access is enabled, but usage description is not "
"specified."
msgstr ""
+"プライãƒã‚·ãƒ¼: アドレス帳ã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒ"
+"ã‚ã‚Šã¾ã›ã‚“。"
#: platform/osx/export/export.cpp
msgid ""
"Privacy: Calendar access is enabled, but usage description is not specified."
msgstr ""
+"プライãƒã‚·ãƒ¼: カレンダーã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬æ˜ŽãŒ"
+"ã‚ã‚Šã¾ã›ã‚“。"
#: platform/osx/export/export.cpp
msgid ""
"Privacy: Photo library access is enabled, but usage description is not "
"specified."
msgstr ""
+"プライãƒã‚·ãƒ¼:フォトライブラリã¸ã®ã‚¢ã‚¯ã‚»ã‚¹ãŒæœ‰åŠ¹ã«ãªã£ã¦ã„ã¾ã™ãŒã€ä½¿ç”¨æ–¹æ³•ã®èª¬"
+"明ãŒã‚ã‚Šã¾ã›ã‚“。"
#: platform/osx/export/export.cpp
msgid "macOS"
@@ -19972,40 +19945,35 @@ msgstr "macOS"
#: platform/osx/export/export.cpp
msgid "Force Builtin Codesign"
-msgstr ""
+msgstr "ビルドインコード署åを強制"
#: platform/uwp/export/export.cpp
msgid "Architecture"
msgstr "アーキテクãƒãƒ£"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Display Name"
-msgstr "表示スケール"
+msgstr "表示å"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Short Name"
-msgstr "スクリプトå:"
+msgstr "略称"
#: platform/uwp/export/export.cpp
msgid "Publisher"
-msgstr ""
+msgstr "パブリッシャー"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Publisher Display Name"
-msgstr "パッケージ発行者ã®è¡¨ç¤ºåãŒç„¡åŠ¹ã§ã™ã€‚"
+msgstr "パブリッシャー表示å"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Product GUID"
-msgstr "無効ãªãƒ—ロダクト GUIDã§ã™ã€‚"
+msgstr "プロダクト GUID"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Publisher GUID"
-msgstr "ガイドをクリアã™ã‚‹"
+msgstr "パブリッシャー GUID"
#: platform/uwp/export/export.cpp
msgid "Signing"
@@ -20037,73 +20005,71 @@ msgstr "リビジョン"
#: platform/uwp/export/export.cpp
msgid "Landscape"
-msgstr ""
+msgstr "ランドスケープ"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Portrait"
-msgstr "ãƒãƒ¼ãƒˆ"
+msgstr "ãƒãƒ¼ãƒˆãƒ¬ãƒ¼ãƒˆ"
#: platform/uwp/export/export.cpp
msgid "Landscape Flipped"
-msgstr ""
+msgstr "ランドスケープå転"
#: platform/uwp/export/export.cpp
msgid "Portrait Flipped"
-msgstr ""
+msgstr "ãƒãƒ¼ãƒˆãƒ¬ãƒ¼ãƒˆå転"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Store Logo"
-msgstr "スケールモード"
+msgstr "ストアロゴ"
#: platform/uwp/export/export.cpp
msgid "Square 44 X 44 Logo"
-msgstr ""
+msgstr "正方形 44 x 44 ロゴ"
#: platform/uwp/export/export.cpp
msgid "Square 71 X 71 Logo"
-msgstr ""
+msgstr "正方形 71 x 71 ロゴ"
#: platform/uwp/export/export.cpp
msgid "Square 150 X 150 Logo"
-msgstr ""
+msgstr "正方形 150 x 150 ロゴ"
#: platform/uwp/export/export.cpp
msgid "Square 310 X 310 Logo"
-msgstr ""
+msgstr "正方形 310 x 310 ロゴ"
#: platform/uwp/export/export.cpp
msgid "Wide 310 X 150 Logo"
-msgstr ""
+msgstr "ワイド 310 x 150 ロゴ"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Splash Screen"
-msgstr "ドローコール:"
+msgstr "スプラッシュ・スクリーン"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Tiles"
-msgstr "ファイル"
+msgstr "タイル"
#: platform/uwp/export/export.cpp
msgid "Show Name On Square 150 X 150"
-msgstr ""
+msgstr "正方形 150×150 表示å"
#: platform/uwp/export/export.cpp
msgid "Show Name On Wide 310 X 150"
-msgstr ""
+msgstr "ワイド 310x150 表示å"
#: platform/uwp/export/export.cpp
msgid "Show Name On Square 310 X 310"
-msgstr ""
+msgstr "正方形 310×310 表示å"
#: platform/uwp/export/export.cpp
msgid ""
"Godot's Mono version does not support the UWP platform. Use the standard "
"build (no C# support) if you wish to target UWP."
msgstr ""
+"Godot ã® Mono ãƒãƒ¼ã‚¸ãƒ§ãƒ³ã¯ UWP プラットフォームをサãƒãƒ¼ãƒˆã—ã¦ã„ã¾ã›ã‚“。UWP ã‚’"
+"対象ã¨ã—ãŸã„å ´åˆã¯ã€æ¨™æº–ビルド(C# éžã‚µãƒãƒ¼ãƒˆ)を使用ã—ã¦ä¸‹ã•ã„。"
#: platform/uwp/export/export.cpp
msgid "Invalid package short name."
@@ -20169,41 +20135,36 @@ msgid "UWP"
msgstr "UWP"
#: platform/uwp/export/export.cpp platform/windows/export/export.cpp
-#, fuzzy
msgid "Signtool"
-msgstr "シグナル"
+msgstr "サインツール"
#: platform/uwp/export/export.cpp
msgid "Debug Certificate"
-msgstr ""
+msgstr "デãƒãƒƒã‚°è¨¼æ˜Žæ›¸"
#: platform/uwp/export/export.cpp
-#, fuzzy
msgid "Debug Algorithm"
-msgstr "デãƒãƒƒã‚¬ãƒ¼"
+msgstr "デãƒãƒƒã‚°ã‚¢ãƒ«ã‚´ãƒªã‚ºãƒ "
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Failed to rename temporary file \"%s\"."
-msgstr "一時ファイルを削除ã§ãã¾ã›ã‚“:"
+msgstr "一時ファイル \"%s\" ã®åå‰ã®å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
#: platform/windows/export/export.cpp
msgid "Identity Type"
-msgstr ""
+msgstr "識別å­ã‚¿ã‚¤ãƒ—"
#: platform/windows/export/export.cpp
msgid "Timestamp Server URL"
-msgstr ""
+msgstr "タイムスタンプサーãƒãƒ¼URL"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Digest Algorithm"
-msgstr "デãƒãƒƒã‚¬ãƒ¼"
+msgstr "ダイジェストアルゴリズム"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Modify Resources"
-msgstr "リソースをコピー"
+msgstr "リソースã®å¤‰æ›´"
#: platform/windows/export/export.cpp
msgid "File Version"
@@ -20227,22 +20188,19 @@ msgstr "ファイルã®èª¬æ˜Ž"
#: platform/windows/export/export.cpp
msgid "Trademarks"
-msgstr ""
+msgstr "商標"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Resources Modification"
-msgstr "ランダムãªå›žè»¢:"
+msgstr "リソースã®å¤‰æ›´"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Could not find rcedit executable at \"%s\"."
-msgstr "キーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。"
+msgstr "\"%s\" ã« rcedit 実行ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Could not find wine executable at \"%s\"."
-msgstr "キーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。"
+msgstr "\"%s\" ã« wine 実行ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
#: platform/windows/export/export.cpp
msgid ""
@@ -20250,31 +20208,29 @@ msgid ""
"Settings (Export > Windows > Rcedit), or disable \"Application > Modify "
"Resources\" in the export preset."
msgstr ""
+"rcedit 実行ファイルを開始ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚エディター設定 (Export > Windows "
+"> Rcedit)ã‹ã‚‰ rcedit ã®ãƒ‘スを設定ã™ã‚‹ã‹ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãƒ—リセット㧠\"アプリ"
+"ケーション > リソースã®å¤‰æ›´\"を無効ã«ã—ã¦ä¸‹ã•ã„。"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "rcedit failed to modify executable: %s."
-msgstr "無効ãªå®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã§ã™ã€‚"
+msgstr "rcedit ã¯å®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã®å¤‰æ›´ã«å¤±æ•—ã—ã¾ã—ãŸ: %s。"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Could not find signtool executable at \"%s\"."
-msgstr "キーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。"
+msgstr "\"%s\" 㫠サインツール実行ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Could not find osslsigncode executable at \"%s\"."
-msgstr "キーストアãŒè¦‹ã¤ã‹ã‚‰ãªã„ãŸã‚ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆã§ãã¾ã›ã‚“。"
+msgstr "\"%s\" ã« osslsigncode 実行ファイルãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“ã§ã—ãŸã€‚"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Invalid identity type."
-msgstr "無効ãªè­˜åˆ¥å­:"
+msgstr "無効ãªè­˜åˆ¥å­ã‚¿ã‚¤ãƒ—。"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Invalid timestamp server."
-msgstr "無効ãªåå‰ã§ã™ã€‚"
+msgstr "タイムスタンプサーãƒãƒ¼ãŒç„¡åŠ¹ã§ã™ã€‚"
#: platform/windows/export/export.cpp
msgid ""
@@ -20282,22 +20238,25 @@ msgid ""
"Settings (Export > Windows > Signtool), or disable \"Codesign\" in the "
"export preset."
msgstr ""
+"サインツール実行ファイルを開始ã§ãã¾ã›ã‚“ã§ã—ãŸã€‚エディター設定 (Export > "
+"Windows > サインツール)ã‹ã‚‰ã‚µã‚¤ãƒ³ãƒ„ールã®ãƒ‘スを設定ã™ã‚‹ã‹ã€ã‚¨ã‚¯ã‚¹ãƒãƒ¼ãƒˆãƒ—リ"
+"セット㧠\"コード署å\"を無効ã«ã—ã¦ä¸‹ã•ã„。"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Signtool failed to sign executable: %s."
-msgstr "無効ãªå®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã§ã™ã€‚"
+msgstr "サインツールã¯å®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã®ç½²åã«å¤±æ•—ã—ã¾ã—ãŸ: %s。"
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Failed to remove temporary file \"%s\"."
-msgstr "一時ファイルを削除ã§ãã¾ã›ã‚“:"
+msgstr "一時ファイル \"%s\" ã®å‰Šé™¤ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
#: platform/windows/export/export.cpp
msgid ""
"The rcedit tool must be configured in the Editor Settings (Export > Windows "
"> Rcedit) to change the icon or app information data."
msgstr ""
+"アイコンやアプリ情報データを変更ã™ã‚‹ã«ã¯ã€ã‚¨ãƒ‡ã‚£ã‚¿ãƒ¼è¨­å®š (Export > Windows > "
+"Rcedit) 㧠rcedit ã®è¨­å®šã‚’è¡Œã†å¿…è¦ãŒã‚ã‚Šã¾ã™ã€‚"
#: platform/windows/export/export.cpp
msgid "Invalid icon path:"
@@ -20313,20 +20272,19 @@ msgstr "無効ãªè£½å“ãƒãƒ¼ã‚¸ãƒ§ãƒ³:"
#: platform/windows/export/export.cpp
msgid "Windows executables cannot be >= 4 GiB."
-msgstr ""
+msgstr "Windows ã®å®Ÿè¡Œãƒ•ã‚¡ã‚¤ãƒ«ã¯ã€4GiBを超ãˆã‚‹ã“ã¨ã¯ã§ãã¾ã›ã‚“。"
#: platform/windows/export/export.cpp platform/x11/export/export.cpp
-#, fuzzy
msgid "Failed to open executable file \"%s\"."
-msgstr "無効ãªå®Ÿè¡Œå¯èƒ½ãƒ•ã‚¡ã‚¤ãƒ«ã§ã™ã€‚"
+msgstr "実行ファイル \"%s\" ã‚’é–‹ãã®ã«å¤±æ•—ã—ã¾ã—ãŸã€‚"
#: platform/windows/export/export.cpp platform/x11/export/export.cpp
msgid "Executable file header corrupted."
-msgstr ""
+msgstr "実行ファイルã®ãƒ˜ãƒƒãƒ€ãƒ¼ãŒç ´æã—ã¦ã„ã¾ã™ã€‚"
#: platform/windows/export/export.cpp platform/x11/export/export.cpp
msgid "Executable \"pck\" section not found."
-msgstr ""
+msgstr "実行å¯èƒ½ãª \"pck \"セクションãŒè¦‹ã¤ã‹ã‚Šã¾ã›ã‚“。"
#: platform/windows/export/export.cpp
msgid "Windows"
@@ -20334,7 +20292,7 @@ msgstr "Windows"
#: platform/windows/export/export.cpp
msgid "Rcedit"
-msgstr ""
+msgstr "Rcedit"
#: platform/windows/export/export.cpp
msgid "Osslsigncode"
@@ -20363,21 +20321,18 @@ msgstr ""
#: scene/2d/animated_sprite.cpp scene/2d/cpu_particles_2d.cpp
#: scene/2d/particles_2d.cpp scene/3d/cpu_particles.cpp scene/3d/particles.cpp
-#, fuzzy
msgid "Speed Scale"
-msgstr "スケール"
+msgstr "スピードスケール"
#: scene/2d/animated_sprite.cpp scene/2d/audio_stream_player_2d.cpp
#: scene/3d/audio_stream_player_3d.cpp scene/3d/sprite_3d.cpp
#: scene/audio/audio_stream_player.cpp
-#, fuzzy
msgid "Playing"
-msgstr "実行"
+msgstr "実行中"
#: scene/2d/animated_sprite.cpp scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
-#, fuzzy
msgid "Centered"
-msgstr "中央"
+msgstr "中央æƒãˆ"
#: scene/2d/animated_sprite.cpp scene/2d/sprite.cpp scene/3d/sprite_3d.cpp
#: scene/gui/texture_button.cpp scene/gui/texture_rect.cpp
@@ -20390,52 +20345,45 @@ msgid "Flip V"
msgstr "åž‚ç›´å転"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Monitoring"
-msgstr "モニター"
+msgstr "モニタリング"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Monitorable"
-msgstr "モニター"
+msgstr "モニターå¯èƒ½"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
msgid "Physics Overrides"
msgstr "物ç†ã®ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Space Override"
-msgstr "上書ã"
+msgstr "領域ã®ã‚ªãƒ¼ãƒãƒ¼ãƒ©ã‚¤ãƒ‰"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Gravity Point"
-msgstr "ãƒã‚¤ãƒ³ãƒˆã‚’生æˆ"
+msgstr "é‡åŠ›ç‚¹"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Gravity Distance Scale"
-msgstr "インスタンス"
+msgstr "é‡åŠ›è·é›¢ã‚¹ã‚±ãƒ¼ãƒ«"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Gravity Vec"
-msgstr "デフォルトã®ãƒ—レビュー"
+msgstr "é‡åŠ›ãƒ™ã‚¯ãƒˆãƒ«"
#: scene/2d/area_2d.cpp scene/2d/cpu_particles_2d.cpp scene/3d/area.cpp
#: scene/3d/cpu_particles.cpp scene/resources/particles_material.cpp
msgid "Gravity"
-msgstr ""
+msgstr "é‡åŠ›"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
-#, fuzzy
msgid "Linear Damp"
-msgstr "リニア"
+msgstr "線形減衰"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
msgid "Angular Damp"
-msgstr ""
+msgstr "角度減衰"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
msgid "Audio Bus"
@@ -20453,9 +20401,8 @@ msgstr "ボリューム dB"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp
#: servers/audio/effects/audio_effect_pitch_shift.cpp
-#, fuzzy
msgid "Pitch Scale"
-msgstr "スケール"
+msgstr "ピッãƒã‚¹ã‚±ãƒ¼ãƒ«"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp
@@ -20465,7 +20412,7 @@ msgstr "自動å†ç”Ÿ"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp
msgid "Stream Paused"
-msgstr ""
+msgstr "ストリームã®ä¸€æ™‚åœæ­¢"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/3d/light.cpp scene/3d/reflection_probe.cpp
@@ -20475,9 +20422,8 @@ msgid "Max Distance"
msgstr "最大è·é›¢"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/light.cpp
-#, fuzzy
msgid "Attenuation"
-msgstr "アニメーション"
+msgstr "減衰é‡"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp scene/gui/video_player.cpp
@@ -20486,22 +20432,19 @@ msgstr "ãƒã‚¹"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
msgid "Area Mask"
-msgstr ""
+msgstr "エリアマスク"
#: scene/2d/back_buffer_copy.cpp
-#, fuzzy
msgid "Copy Mode"
-msgstr "ノードをコピー"
+msgstr "コピーモード"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Anchor Mode"
-msgstr "アイコンモード"
+msgstr "アンカーモード"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Rotating"
-msgstr "回転ã®ã‚¹ãƒ†ãƒƒãƒ—:"
+msgstr "回転"
#: scene/2d/camera_2d.cpp scene/2d/listener_2d.cpp scene/3d/camera.cpp
#: scene/3d/listener.cpp scene/animation/animation_blend_tree.cpp
@@ -20513,9 +20456,8 @@ msgid "Zoom"
msgstr "ズーム"
#: scene/2d/camera_2d.cpp scene/main/canvas_layer.cpp
-#, fuzzy
msgid "Custom Viewport"
-msgstr "1 ビューãƒãƒ¼ãƒˆ"
+msgstr "カスタムビューãƒãƒ¼ãƒˆ"
#: scene/2d/camera_2d.cpp scene/3d/camera.cpp scene/3d/interpolated_camera.cpp
#: scene/animation/animation_player.cpp scene/animation/animation_tree.cpp
@@ -20544,29 +20486,24 @@ msgid "Bottom"
msgstr "下"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Smoothed"
-msgstr "スムーズステップ"
+msgstr "スムージング"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Draw Margin"
-msgstr "マージンを設定ã™ã‚‹"
+msgstr "マージンをæç”»ã™ã‚‹"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Drag Margin H Enabled"
-msgstr "マージンを設定ã™ã‚‹"
+msgstr "水平方å‘ã®ãƒ‰ãƒ©ãƒƒã‚°ãƒžãƒ¼ã‚¸ãƒ³ã«ã®ã¿æœ‰åŠ¹"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Drag Margin V Enabled"
-msgstr "マージンを設定ã™ã‚‹"
+msgstr "åž‚ç›´æ–¹å‘ã®ãƒ‰ãƒ©ãƒƒã‚°ãƒžãƒ¼ã‚¸ãƒ³ã«ã®ã¿æœ‰åŠ¹"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Smoothing"
-msgstr "スムーズステップ"
+msgstr "スムージング"
#: scene/2d/camera_2d.cpp
msgid "H"
@@ -20577,35 +20514,29 @@ msgid "V"
msgstr "åž‚ç›´"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Drag Margin"
-msgstr "マージンを設定ã™ã‚‹"
+msgstr "ドラッグマージン"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Draw Screen"
-msgstr "ドローコール:"
+msgstr "スクリーンをæç”»ã™ã‚‹"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Draw Limits"
-msgstr "ドローコール:"
+msgstr "é™ç•Œã‚’æç”»ã™ã‚‹"
#: scene/2d/camera_2d.cpp
-#, fuzzy
msgid "Draw Drag Margin"
-msgstr "マージンを設定ã™ã‚‹"
+msgstr "ドラッグマージンをæç”»ã™ã‚‹"
#: scene/2d/canvas_item.cpp scene/resources/environment.cpp
#: scene/resources/material.cpp
-#, fuzzy
msgid "Blend Mode"
-msgstr "ブレンド2 ノード"
+msgstr "ブレンドモード"
#: scene/2d/canvas_item.cpp
-#, fuzzy
msgid "Light Mode"
-msgstr "å³ä¼¸é•·"
+msgstr "ライトモード"
#: scene/2d/canvas_item.cpp
#, fuzzy
@@ -23582,14 +23513,12 @@ msgid "AABB"
msgstr ""
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Sorting"
msgstr "ソート"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Use AABB Center"
-msgstr "アンビエントを使用"
+msgstr "AABBセンターを使用"
#: scene/3d/visual_instance.cpp scene/resources/navigation_mesh.cpp
#, fuzzy
diff --git a/editor/translations/ka.po b/editor/translations/ka.po
index 629afaa429..ce7502e5ac 100644
--- a/editor/translations/ka.po
+++ b/editor/translations/ka.po
@@ -11066,7 +11066,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/km.po b/editor/translations/km.po
index ade147ec7e..85f5081b6f 100644
--- a/editor/translations/km.po
+++ b/editor/translations/km.po
@@ -10598,7 +10598,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/ko.po b/editor/translations/ko.po
index f43830b1e9..9563bc6244 100644
--- a/editor/translations/ko.po
+++ b/editor/translations/ko.po
@@ -29,7 +29,7 @@
# ì‹ ë™ê·œ <rlsl0422@gmail.com>, 2021.
# Kiroo <elusive1102@naver.com>, 2021.
# JumpJetAvocado <dwkng@jbnu.ac.kr>, 2021.
-# Lee Minhak <minarihak@gmail.com>, 2022.
+# Lee Minhak <minarihak@gmail.com>, 2022, 2023.
# 한수현 <shh1473@ajou.ac.kr>, 2022.
# Taehun Yun <yooontehoon@naver.com>, 2022.
# vrSono <global.sonogong@gmail.com>, 2022.
@@ -41,13 +41,14 @@
# nulltable <un5450@naver.com>, 2022.
# Godoto <aicompose@gmail.com>, 2022.
# gaenyang <gaenyang@outlook.com>, 2022.
+# 오지훈 <jule1130@naver.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-10-24 12:41+0000\n"
-"Last-Translator: Godoto <aicompose@gmail.com>\n"
+"PO-Revision-Date: 2023-01-20 10:19+0000\n"
+"Last-Translator: 오지훈 <jule1130@naver.com>\n"
"Language-Team: Korean <https://hosted.weblate.org/projects/godot-engine/"
"godot/ko/>\n"
"Language: ko\n"
@@ -55,7 +56,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.14.2-dev\n"
+"X-Generator: Weblate 4.15.1\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -582,7 +583,7 @@ msgstr "ì´ë¦„"
#: modules/visual_script/visual_script_nodes.cpp platform/uwp/export/export.cpp
#: platform/windows/export/export.cpp
msgid "Description"
-msgstr "서술"
+msgstr "설명"
#: core/project_settings.cpp editor/editor_node.cpp editor/editor_settings.cpp
#: editor/plugins/script_editor_plugin.cpp editor/project_manager.cpp
@@ -10886,7 +10887,7 @@ msgstr "후면 ì›ê·¼"
msgid " [auto]"
msgstr " [ìžë™]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [í¬í„¸ 활성]"
@@ -17852,9 +17853,8 @@ msgid "Use Default Args"
msgstr "ë””í´íŠ¸ë¡œ 재설정"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "Validate"
-msgstr "올바른 문ìž:"
+msgstr "올바른 문ìž"
#: modules/visual_script/visual_script_func_nodes.cpp
#, fuzzy
@@ -17984,24 +17984,20 @@ msgid "Preload"
msgstr "새로고침"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Get Index"
-msgstr "Z ì¸ë±ìŠ¤"
+msgstr "ì¸ë±ìŠ¤ 가져오기"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Set Index"
-msgstr "Z ì¸ë±ìŠ¤"
+msgstr "ì¸ë±ìŠ¤ 설정"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Global Constant"
-msgstr "ìƒìˆ˜"
+msgstr "ì „ì—­ ìƒìˆ˜"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Class Constant"
-msgstr "ìƒìˆ˜"
+msgstr "í´ëž˜ìŠ¤ ìƒìˆ˜"
#: modules/visual_script/visual_script_nodes.cpp
#, fuzzy
@@ -18009,24 +18005,21 @@ msgid "Basic Constant"
msgstr "ìƒìˆ˜"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Math Constant"
-msgstr "ìƒìˆ˜"
+msgstr "수학 ìƒìˆ˜"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Get Engine Singleton"
-msgstr "í™œì„±í™”ëœ GDNative 싱글톤"
+msgstr "엔진 싱글톤 가져오기"
#: modules/visual_script/visual_script_nodes.cpp
#, fuzzy
msgid "Get Scene Node"
-msgstr "시간 íƒìƒ‰ 노드"
+msgstr "씬 Node 가져오기"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "Get Scene Tree"
-msgstr "씬 트리 편집"
+msgstr "씬 트리 가져오기"
#: modules/visual_script/visual_script_nodes.cpp
#, fuzzy
@@ -18034,9 +18027,8 @@ msgid "Get Self"
msgstr "ìžì²´"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "CustomNode"
-msgstr "노드 잘ë¼ë‚´ê¸°"
+msgstr ""
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
@@ -18096,18 +18088,16 @@ msgid "Wait"
msgstr "대기"
#: modules/visual_script/visual_script_yield_nodes.cpp
-#, fuzzy
msgid "Next Frame"
-msgstr "프레임 ì´ë™"
+msgstr "ë‹¤ìŒ í”„ë ˆìž„"
#: modules/visual_script/visual_script_yield_nodes.cpp
-#, fuzzy
msgid "Next Physics Frame"
-msgstr "물리 프레임 %"
+msgstr "ë‹¤ìŒ ë¬¼ë¦¬ 프레임"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "%s sec(s)"
-msgstr ""
+msgstr "%sì´ˆ"
#: modules/visual_script/visual_script_yield_nodes.cpp scene/main/timer.cpp
#, fuzzy
@@ -18136,7 +18126,7 @@ msgstr "우선 순위 모드"
#: modules/webrtc/webrtc_data_channel.h
msgid "WebRTC"
-msgstr ""
+msgstr "WebRTC"
#: modules/webrtc/webrtc_data_channel.h
msgid "Max Channel In Buffer (KB)"
@@ -18148,12 +18138,12 @@ msgstr ""
#: modules/websocket/websocket_client.cpp
msgid "Trusted SSL Certificate"
-msgstr ""
+msgstr "신뢰할 수 있는 SSL ì¸ì¦ì„œ"
#: modules/websocket/websocket_macros.h
#, fuzzy
msgid "WebSocket Client"
-msgstr "ë„¤íŠ¸ì›Œí¬ í”„ë¡œíŒŒì¼ëŸ¬"
+msgstr "WebSocket í´ë¼ì´ì–¸íŠ¸"
#: modules/websocket/websocket_macros.h
msgid "Max In Buffer (KB)"
@@ -18181,13 +18171,12 @@ msgid "Bind IP"
msgstr ""
#: modules/websocket/websocket_server.cpp
-#, fuzzy
msgid "Private Key"
-msgstr "물리 키"
+msgstr "ê°œì¸ í‚¤"
#: modules/websocket/websocket_server.cpp platform/javascript/export/export.cpp
msgid "SSL Certificate"
-msgstr ""
+msgstr "SSL ì¸ì¦ì„œ"
#: modules/websocket/websocket_server.cpp
#, fuzzy
@@ -18212,8 +18201,9 @@ msgid "Optional Features"
msgstr "ì„ íƒì  기능"
#: modules/webxr/webxr_interface.cpp
+#, fuzzy
msgid "Requested Reference Space Types"
-msgstr ""
+msgstr "ìš”ì²­ëœ ì°¸ì¡° 공간 유형"
#: modules/webxr/webxr_interface.cpp
msgid "Reference Space Type"
diff --git a/editor/translations/lt.po b/editor/translations/lt.po
index 5f0c068dbb..33cc2f8ae9 100644
--- a/editor/translations/lt.po
+++ b/editor/translations/lt.po
@@ -11054,7 +11054,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/lv.po b/editor/translations/lv.po
index 51836c627b..18c5c4242e 100644
--- a/editor/translations/lv.po
+++ b/editor/translations/lv.po
@@ -10997,7 +10997,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/mk.po b/editor/translations/mk.po
index 6d725ac82b..9f06f03d81 100644
--- a/editor/translations/mk.po
+++ b/editor/translations/mk.po
@@ -10624,7 +10624,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/ml.po b/editor/translations/ml.po
index 171cc17fdb..8a66f8b8b4 100644
--- a/editor/translations/ml.po
+++ b/editor/translations/ml.po
@@ -10647,7 +10647,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/mr.po b/editor/translations/mr.po
index 24300da41a..ac50228677 100644
--- a/editor/translations/mr.po
+++ b/editor/translations/mr.po
@@ -10634,7 +10634,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/ms.po b/editor/translations/ms.po
index 3b34efe6f2..7c87a4709d 100644
--- a/editor/translations/ms.po
+++ b/editor/translations/ms.po
@@ -11073,7 +11073,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/nb.po b/editor/translations/nb.po
index 9d831aee5d..f7aac38f70 100644
--- a/editor/translations/nb.po
+++ b/editor/translations/nb.po
@@ -4,7 +4,7 @@
# This file is distributed under the same license as the Godot source code.
# Allan Nordhøy <epost@anotheragency.no>, 2017-2018, 2019, 2020, 2021.
# Anonymous <GentleSaucepan@protonmail.com>, 2017, 2021.
-# Elias <eliasnykrem@gmail.com>, 2018.
+# Elias <eliasnykrem@gmail.com>, 2018, 2023.
# flesk <eivindkn@gmail.com>, 2017, 2019.
# Frank T. Rambol <frank@d-fect.com>, 2018, 2021.
# Jørgen Aarmo Lund <jorgen.aarmo@gmail.com>, 2016, 2019.
@@ -28,8 +28,8 @@ msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-12-08 10:28+0000\n"
-"Last-Translator: slasken06 <ask.skivdal@gmail.com>\n"
+"PO-Revision-Date: 2023-01-17 13:54+0000\n"
+"Last-Translator: Elias <eliasnykrem@gmail.com>\n"
"Language-Team: Norwegian Bokmål <https://hosted.weblate.org/projects/godot-"
"engine/godot/nb_NO/>\n"
"Language: nb\n"
@@ -37,7 +37,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -2281,7 +2281,7 @@ msgstr "Ã…pne"
#: editor/dependency_editor.cpp
msgid "Owners of: %s (Total: %d)"
-msgstr ""
+msgstr "Eiere av: %s (Totalt: %d)"
#: editor/dependency_editor.cpp
#, fuzzy
@@ -2868,22 +2868,19 @@ msgstr "Velg"
#: editor/editor_export.cpp
msgid "Project export for platform:"
-msgstr ""
+msgstr "Prosjekteksport til platform:"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Completed with warnings."
-msgstr "Kopier Node-bane"
+msgstr "Fullført med varsler."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Completed successfully."
-msgstr "Vellykket Installering av Pakke!"
+msgstr "Fullført vellykket."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Failed."
-msgstr "Feilet:"
+msgstr "Feilet."
#: editor/editor_export.cpp
msgid "Storing File:"
@@ -2898,29 +2895,24 @@ msgid "Packing"
msgstr "Pakking"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Save PCK"
-msgstr "Lagre som"
+msgstr "Lagre PCK"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Cannot create file \"%s\"."
-msgstr "Kunne ikke opprette mappe."
+msgstr "Kunne ikke opprette filen \"%s\"."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Failed to export project files."
-msgstr "Kunne ikke opprette mappe."
+msgstr "Kunne ikke eksportere prosjektfiler."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Can't open file to read from path \"%s\"."
-msgstr "Kan ikke åpne fil for skriving:"
+msgstr "Kan ikke åpne filen for å lese fra banen \"%s\"."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Save ZIP"
-msgstr "Lagre som"
+msgstr "Lagre ZIP"
#: editor/editor_export.cpp
msgid ""
@@ -2984,9 +2976,8 @@ msgstr ""
#: editor/editor_export.cpp platform/android/export/export_plugin.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
-#, fuzzy
msgid "Custom Template"
-msgstr "Medlemmer"
+msgstr "Egendefinert mal"
#: editor/editor_export.cpp editor/project_export.cpp
#: platform/android/export/export_plugin.cpp platform/iphone/export/export.cpp
@@ -2996,22 +2987,20 @@ msgid "Release"
msgstr "Slipp"
#: editor/editor_export.cpp
-#, fuzzy
msgid "Binary Format"
-msgstr "Anim Forandre Omforming"
+msgstr "Binærformat"
#: editor/editor_export.cpp
msgid "64 Bits"
-msgstr ""
+msgstr "64 Bits"
#: editor/editor_export.cpp
msgid "Embed PCK"
-msgstr ""
+msgstr "Innebygd PCK"
#: editor/editor_export.cpp platform/osx/export/export.cpp
-#, fuzzy
msgid "Texture Format"
-msgstr "Linjal Modus"
+msgstr "Teksturformat"
#: editor/editor_export.cpp
msgid "BPTC"
@@ -3031,9 +3020,8 @@ msgid "ETC2"
msgstr ""
#: editor/editor_export.cpp
-#, fuzzy
msgid "No BPTC Fallbacks"
-msgstr "Tilbakefall"
+msgstr "Ingen BPTC tilbakefall"
#: editor/editor_export.cpp platform/android/export/export_plugin.cpp
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
@@ -3048,24 +3036,20 @@ msgid "Custom release template not found."
msgstr "Fant ikke tilpasset utgivelsesmal."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Prepare Template"
-msgstr "HÃ¥ndter Eksportmaler"
+msgstr "Forbered mal"
#: editor/editor_export.cpp platform/osx/export/export.cpp
-#, fuzzy
msgid "The given export path doesn't exist."
-msgstr "Fil eksisterer ikke."
+msgstr "Den angitte eksportbanen eksisterer ikke."
#: editor/editor_export.cpp platform/javascript/export/export.cpp
-#, fuzzy
msgid "Template file not found: \"%s\"."
-msgstr "Malfil ble ikke funnet:"
+msgstr "Malfil ble ikke funnet \"%s\"."
#: editor/editor_export.cpp
-#, fuzzy
msgid "Failed to copy export template."
-msgstr "HÃ¥ndter Eksportmaler"
+msgstr "Kunne ikke kopiere eksportmalen."
#: editor/editor_export.cpp platform/windows/export/export.cpp
#: platform/x11/export/export.cpp
@@ -3082,9 +3066,8 @@ msgid "Convert Text Resources To Binary On Export"
msgstr ""
#: editor/editor_feature_profile.cpp
-#, fuzzy
msgid "3D Editor"
-msgstr "Redigeringsverktøy"
+msgstr "3D Redigeringsverktøy"
#: editor/editor_feature_profile.cpp
msgid "Script Editor"
@@ -3097,7 +3080,7 @@ msgstr "Ressursbibliotek"
#: editor/editor_feature_profile.cpp
msgid "Scene Tree Editing"
-msgstr ""
+msgstr "Scenetre redigering"
#: editor/editor_feature_profile.cpp
#, fuzzy
@@ -3115,7 +3098,7 @@ msgstr "Importer"
#: editor/editor_feature_profile.cpp
msgid "Allows to view and edit 3D scenes."
-msgstr ""
+msgstr "Lar deg se og redigere 3D scener."
#: editor/editor_feature_profile.cpp
msgid "Allows to edit scripts using the integrated script editor."
@@ -11529,7 +11512,7 @@ msgstr "Perspektiv"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
@@ -14991,9 +14974,8 @@ msgid "Project Path:"
msgstr "Prosjektsti:"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Project Installation Path:"
-msgstr "Prosjektsti:"
+msgstr "Prosjekt installasjonsti:"
#: editor/project_manager.cpp
msgid "Renderer:"
@@ -15005,7 +14987,7 @@ msgstr ""
#: editor/project_manager.cpp
msgid "Not supported by your GPU drivers."
-msgstr ""
+msgstr "Støttes ikke av dine GPU-drivere."
#: editor/project_manager.cpp
msgid ""
@@ -15040,9 +15022,8 @@ msgid "Renderer can be changed later, but scenes may need to be adjusted."
msgstr "Rendrer kan endres senere, men scener må kanskje justeres."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Missing Project"
-msgstr "Importer Eksisterende Prosjekt"
+msgstr "Manglede Prosjekt"
#: editor/project_manager.cpp
msgid "Error: Project is missing on the filesystem."
@@ -15053,9 +15034,8 @@ msgid "Local"
msgstr "Lokal"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Local Projects"
-msgstr "Prosjekter"
+msgstr "Lokale prosjekter"
#: editor/project_manager.cpp
#, fuzzy
@@ -15063,9 +15043,8 @@ msgid "Asset Library Projects"
msgstr "Ressursbibliotek"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Can't open project at '%s'."
-msgstr "Kan ikke åpne prosjekt"
+msgstr "Kan ikke åpne prosjektet i '%s'."
#: editor/project_manager.cpp
msgid "Are you sure to open more than one project?"
@@ -15172,23 +15151,20 @@ msgid "Loading, please wait..."
msgstr "Henter fillager, vennligst vent..."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Edit Project"
-msgstr "Eksporter Prosjekt"
+msgstr "Rediger Prosjekt"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Run Project"
-msgstr "Endre Navn på Prosjekt"
+msgstr "Kjør prosjektet"
#: editor/project_manager.cpp
msgid "Scan"
-msgstr "Skann"
+msgstr "Søk"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Scan Projects"
-msgstr "Prosjekter"
+msgstr "Søk etter prosjekter"
#: editor/project_manager.cpp
msgid "Select a Folder to Scan"
@@ -15199,19 +15175,16 @@ msgid "New Project"
msgstr "Nytt prosjekt"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Import Project"
-msgstr "Eksporter Prosjekt"
+msgstr "Importert prosjekt"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove Project"
-msgstr "Endre Navn på Prosjekt"
+msgstr "Fjern prosjekt"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Remove Missing"
-msgstr "Fjern punkt"
+msgstr "Fjern manglende"
#: editor/project_manager.cpp
msgid "About"
@@ -15227,7 +15200,7 @@ msgstr "Fjern alle"
#: editor/project_manager.cpp
msgid "Also delete project contents (no undo!)"
-msgstr ""
+msgstr "Slett også prosjektets innhold (kan ikke reverseres!)"
#: editor/project_manager.cpp
msgid "Can't run project"
@@ -15240,9 +15213,8 @@ msgid ""
msgstr ""
#: editor/project_manager.cpp
-#, fuzzy
msgid "Filter projects"
-msgstr "Lim inn Noder"
+msgstr "Filtre prosjekter"
#: editor/project_manager.cpp
msgid ""
diff --git a/editor/translations/nl.po b/editor/translations/nl.po
index 5e80c53732..0e47306f0d 100644
--- a/editor/translations/nl.po
+++ b/editor/translations/nl.po
@@ -11327,7 +11327,7 @@ msgstr "Perspectief"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/pl.po b/editor/translations/pl.po
index 47b7bfe98a..31048d3390 100644
--- a/editor/translations/pl.po
+++ b/editor/translations/pl.po
@@ -2,7 +2,7 @@
# Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur.
# Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md).
# This file is distributed under the same license as the Godot source code.
-# 8-bit Pixel <dawdejw@gmail.com>, 2016.
+# 8-bit Pixel <dawdejw@gmail.com>, 2016, 2023.
# Adam Wolanski <adam.wolanski94@gmail.com>, 2017.
# Adrian Węcławski <weclawskiadrian@gmail.com>, 2016.
# aelspire <aelspire@gmail.com>, 2017, 2019, 2020, 2021.
@@ -17,14 +17,14 @@
# Maksymilian Świąć <maksymilian.swiac@gmail.com>, 2017-2018.
# Mietek Szcześniak <ravaging@go2.pl>, 2016.
# NeverK <neverkoxu@gmail.com>, 2018, 2019, 2020, 2021, 2022.
-# Rafal Brozio <rafal.brozio@gmail.com>, 2016, 2019, 2020, 2021.
+# Rafal Brozio <rafal.brozio@gmail.com>, 2016, 2019, 2020, 2021, 2023.
# Rafał Ziemniak <synaptykq@gmail.com>, 2017.
-# RM <synaptykq@gmail.com>, 2018, 2020, 2022.
+# RM <synaptykq@gmail.com>, 2018, 2020, 2022, 2023.
# Sebastian Krzyszkowiak <dos@dosowisko.net>, 2017.
-# Sebastian Pasich <sebastian.pasich@gmail.com>, 2017, 2019, 2020, 2022.
+# Sebastian Pasich <sebastian.pasich@gmail.com>, 2017, 2019, 2020, 2022, 2023.
# siatek papieros <sbigneu@gmail.com>, 2016.
# Zatherz <zatherz@linux.pl>, 2017, 2020, 2021.
-# Tomek <kobewi4e@gmail.com>, 2018, 2019, 2020, 2021, 2022.
+# Tomek <kobewi4e@gmail.com>, 2018, 2019, 2020, 2021, 2022, 2023.
# Wojcieh Er Zet <wojcieh.rzepecki@gmail.com>, 2018.
# Dariusz Siek <dariuszynski@gmail.com>, 2018, 2019, 2020, 2021.
# Szymon Nowakowski <smnbdg13@gmail.com>, 2019.
@@ -45,7 +45,7 @@
# Piotr Grodzki <ziemniakglados@gmail.com>, 2020.
# Dzejkop <jakubtrad@gmail.com>, 2020, 2021.
# Mateusz Grzonka <alpinus4@gmail.com>, 2020.
-# gnu-ewm <gnu.ewm@protonmail.com>, 2021.
+# gnu-ewm <gnu.ewm@protonmail.com>, 2021, 2023.
# vrid <patryksoon@live.com>, 2021.
# Suchy Talerz <kacperkubis06@gmail.com>, 2021.
# Bartosz Stasiak <bs97086@amu.edu.pl>, 2021.
@@ -60,22 +60,23 @@
# Mateusz Zdrzałek <matjozohd@gmail.com>, 2022.
# Konrad <kobe-interactive@protonmail.com>, 2022.
# Pixel Zone - Godot Engine Tutorials <karoltomaszewskimusic@gmail.com>, 2022.
-# DK0492 <doriankaczmarek28@gmail.com>, 2022.
+# DK0492 <doriankaczmarek28@gmail.com>, 2022, 2023.
# Dawid Skubij <davidsd@tlen.pl>, 2022.
-# kingofsponges <q.patex.q@gmail.com>, 2022.
+# kingofsponges <q.patex.q@gmail.com>, 2022, 2023.
# Patryk Morawski <gormit7@gmail.com>, 2022.
# Adrians <adrianspl@o2.pl>, 2022.
# Wodorek <Krol.w94@gmail.com>, 2022.
# Filip Gliszczyński <filipgliszczynski@gmail.com>, 2022.
# Piotr Åšlusarz <piotrekslusarz@outlook.com>, 2022.
# Jan Kurzak <Iqaz0oki@outlook.com>, 2022.
+# Wojciech Pluta <wojciech.pluta@oracle.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-12-12 09:46+0000\n"
-"Last-Translator: Tomek <kobewi4e@gmail.com>\n"
+"PO-Revision-Date: 2023-01-20 10:19+0000\n"
+"Last-Translator: RM <synaptykq@gmail.com>\n"
"Language-Team: Polish <https://hosted.weblate.org/projects/godot-engine/"
"godot/pl/>\n"
"Language: pl\n"
@@ -84,7 +85,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.15-dev\n"
+"X-Generator: Weblate 4.15.1\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -104,7 +105,7 @@ msgstr "Kod zakończenia"
#: core/bind/core_bind.cpp
msgid "V-Sync Enabled"
-msgstr "V-Sync WÅ‚Ä…czone"
+msgstr "V-Sync włączone"
#: core/bind/core_bind.cpp main/main.cpp
msgid "V-Sync Via Compositor"
@@ -112,7 +113,7 @@ msgstr "V-Sync przez kompozytor"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Delta Smoothing"
-msgstr "Wygładzanie Delta"
+msgstr "Wygładzanie delta"
#: core/bind/core_bind.cpp
msgid "Low Processor Usage Mode"
@@ -5523,18 +5524,16 @@ msgid "Show Line Numbers"
msgstr "Pokaż numery linii"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Line Numbers Zero Padded"
-msgstr "Numer linii:"
+msgstr "Numery linii wyrównane zerami"
#: editor/editor_settings.cpp
msgid "Show Bookmark Gutter"
msgstr "Pokaż ciek zakładek"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Breakpoint Gutter"
-msgstr "Pomiń punkty wstrzymania"
+msgstr "Pokaż rynnę punktów wstrzymania"
#: editor/editor_settings.cpp
msgid "Show Info Gutter"
@@ -5561,9 +5560,8 @@ msgid "Line Length Guideline Hard Column"
msgstr "Wytyczne dotyczące długości linii twardej kolumny"
#: editor/editor_settings.cpp editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Script List"
-msgstr "Edytor skryptów"
+msgstr "Lista skryptów"
#: editor/editor_settings.cpp
msgid "Show Members Overview"
@@ -5594,9 +5592,8 @@ msgid "Auto Reload Scripts On External Change"
msgstr "Automatycznie przeładuj skrypty przy zmianie zewnętrznej"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Create Signal Callbacks"
-msgstr "Opóźnienia wymuszania shaderów"
+msgstr "Twórz wywołania zwrotne sygnałów"
#: editor/editor_settings.cpp
msgid "Sort Members Outline Alphabetically"
@@ -5623,9 +5620,8 @@ msgid "Caret Blink Speed"
msgstr "Prędkość migania karety"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Right Click Moves Caret"
-msgstr "Prawy klik, aby dodać punkt"
+msgstr "Prawy klik przesuwa kursor"
#: editor/editor_settings.cpp modules/gdscript/gdscript.cpp
#: modules/gdscript/gdscript_editor.cpp
@@ -5647,56 +5643,51 @@ msgstr "Opóźnienie zakończenia kodu"
#: editor/editor_settings.cpp
msgid "Put Callhint Tooltip Below Current Line"
-msgstr ""
+msgstr "Ustaw dymek podpowiedzi pod aktualnym wierszem"
#: editor/editor_settings.cpp
msgid "Callhint Tooltip Offset"
-msgstr ""
+msgstr "Przesunięcie dymka podpowiedzi"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Complete File Paths"
-msgstr "Skopiuj ścieżkę węzła"
+msgstr "Uzupełniaj ścieżki plików"
#: editor/editor_settings.cpp modules/gdscript/gdscript_editor.cpp
-#, fuzzy
msgid "Add Type Hints"
-msgstr "Dodaj typ"
+msgstr "Dodaj wskazówki typów"
#: editor/editor_settings.cpp
msgid "Use Single Quotes"
msgstr "Użyj pojedynczych cudzysłowów"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Show Help Index"
-msgstr "Pokaż linie pomocnicze"
+msgstr "Pokaż indeks pomocy"
#: editor/editor_settings.cpp
msgid "Help Font Size"
-msgstr ""
+msgstr "Rozmiar czcionki pomocy"
#: editor/editor_settings.cpp
msgid "Help Source Font Size"
-msgstr ""
+msgstr "Rozmiar czcionki kodu w pomocy"
#: editor/editor_settings.cpp
msgid "Help Title Font Size"
-msgstr ""
+msgstr "Rozmiar czcionki tytułu w pomocy"
#: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp
msgid "Grid Map"
msgstr "Siatka"
#: editor/editor_settings.cpp modules/gridmap/grid_map_editor_plugin.cpp
-#, fuzzy
msgid "Pick Distance"
-msgstr "Wybierz odległość:"
+msgstr "Dystans Å‚apania"
#: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Preview Size"
-msgstr "PodglÄ…d"
+msgstr "Rozmiar podglÄ…du"
#: editor/editor_settings.cpp
msgid "Primary Grid Color"
@@ -5707,32 +5698,27 @@ msgid "Secondary Grid Color"
msgstr "Pomocniczy kolor siatki"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Selection Box Color"
-msgstr "Tylko zaznaczenie"
+msgstr "Kolor prostopadłościanu zaznaczenia"
#: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "3D Gizmos"
-msgstr "Uchwyty"
+msgstr "Uchwyty 3D"
#: editor/editor_settings.cpp editor/plugins/path_editor_plugin.cpp
#: editor/spatial_editor_gizmos.cpp modules/csg/csg_gizmos.cpp
-#, fuzzy
msgid "Gizmo Colors"
-msgstr "Kolory emisji"
+msgstr "Kolory uchwytów"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Instanced"
-msgstr "Instancja"
+msgstr "Instancjonowany"
#: editor/editor_settings.cpp modules/gltf/gltf_node.cpp
#: scene/3d/physics_body.cpp
-#, fuzzy
msgid "Joint"
-msgstr "Punkt"
+msgstr "ZÅ‚Ä…cze"
#: editor/editor_settings.cpp scene/2d/collision_shape_2d.cpp
#: scene/2d/cpu_particles_2d.cpp scene/2d/touch_screen_button.cpp
@@ -5744,276 +5730,236 @@ msgid "Shape"
msgstr "Kształt"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Primary Grid Steps"
-msgstr "Krok siatki:"
+msgstr "Główne kroki siatki"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid Size"
-msgstr "Krok siatki:"
+msgstr "Rozmiar siatki"
#: editor/editor_settings.cpp
msgid "Grid Division Level Max"
-msgstr ""
+msgstr "Maksymalny poziom podziału siatki"
#: editor/editor_settings.cpp
msgid "Grid Division Level Min"
-msgstr ""
+msgstr "Minimalny poziom podziału siatki"
#: editor/editor_settings.cpp
msgid "Grid Division Level Bias"
-msgstr ""
+msgstr "Tendencja poziomu podziału siatki"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid XZ Plane"
-msgstr "Malowanie GridMap"
+msgstr "PÅ‚aszczyzna siatki XZ"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid XY Plane"
-msgstr "Malowanie GridMap"
+msgstr "PÅ‚aszczyzna siatki XY"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Grid YZ Plane"
-msgstr "Malowanie GridMap"
+msgstr "PÅ‚aszczyzna siatki YZ"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default FOV"
-msgstr "Domyślny"
+msgstr "Domyślne pole widzenia (FOV)"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default Z Near"
-msgstr "Domyślny motyw"
+msgstr "Domyślne bliskie Z"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default Z Far"
-msgstr "Domyślny"
+msgstr "Domyślne dalekie Z"
#: editor/editor_settings.cpp
msgid "Lightmap Baking Number Of CPU Threads"
-msgstr ""
+msgstr "Liczba wątków CPU dla wypalania map światła"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Navigation Scheme"
-msgstr "Tryb nawigacji"
+msgstr "Schemat nawigacji"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Invert Y Axis"
-msgstr "Edytuj oÅ› Y"
+msgstr "Odwróć oś Y"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Invert X Axis"
-msgstr "Edytuj oÅ› X"
+msgstr "Odwróć oś X"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Zoom Style"
-msgstr "Oddal"
+msgstr "Styl przybliżenia"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Emulate Numpad"
-msgstr "WÅ‚Ä…cz emulacjÄ™ klawiatury numerycznej"
+msgstr "Emuluj klawiaturÄ™ numerycznÄ…"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Emulate 3 Button Mouse"
-msgstr "Włącz emulację środkowego przycisku myszy"
+msgstr "Emuluj trzyprzyciskowÄ… mysz"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Orbit Modifier"
-msgstr "Pierwsze zmodyfikowane"
+msgstr "Modyfikator orbity"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Pan Modifier"
-msgstr "Tryb przesuwania"
+msgstr "Modyfikator przesuwania"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Zoom Modifier"
-msgstr "Zmodyfikowany"
+msgstr "Modyfikator przybliżenia"
#: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Warped Mouse Panning"
-msgstr ""
+msgstr "Zawinięte przesuwanie myszą"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Navigation Feel"
-msgstr "Tryb nawigacji"
+msgstr "Preferencje nawigacji"
#: editor/editor_settings.cpp
msgid "Orbit Sensitivity"
-msgstr ""
+msgstr "Czułość orbity"
#: editor/editor_settings.cpp
msgid "Orbit Inertia"
-msgstr ""
+msgstr "Bezwładność orbity"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Translation Inertia"
-msgstr "TÅ‚umaczenia"
+msgstr "Bezwładność przesunięcia"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Zoom Inertia"
-msgstr "Przybliż"
+msgstr "Bezwładność przybliżenia"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook"
-msgstr "\"Wolny widok\" w górę"
+msgstr "Wolny widok"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Navigation Scheme"
-msgstr "Utwórz siatkę nawigacyjną (Navigation Mesh)"
+msgstr "Schemat nawigacji wolnego widoku"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Sensitivity"
-msgstr "\"Wolny widok\" w lewo"
+msgstr "Czułość wolnego widoku"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Inertia"
-msgstr "\"Wolny widok\" w lewo"
+msgstr "Bezwładność wolnego widoku"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Base Speed"
-msgstr "Modyfikator prędkości swobodnego widoku"
+msgstr "Bazowa prędkość wolnego widoku"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Activation Modifier"
-msgstr "Wolny modyfikator swobodnego widoku"
+msgstr "Modyfikator aktywacji wolnego widoku"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Freelook Speed Zoom Link"
-msgstr "Modyfikator prędkości swobodnego widoku"
+msgstr "Szybkość swobodnego widoku zależna od przybliżenia"
#: editor/editor_settings.cpp editor/plugins/tile_map_editor_plugin.cpp
-#, fuzzy
msgid "Grid Color"
-msgstr "Wybierz Kolor"
+msgstr "Kolor siatki"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Guides Color"
-msgstr "Wybierz Kolor"
+msgstr "Kolor prowadnic"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Smart Snapping Line Color"
-msgstr "Inteligentne przyciÄ…ganie"
+msgstr "Kolor linii inteligentnego przyciÄ…gania"
#: editor/editor_settings.cpp
msgid "Bone Width"
-msgstr ""
+msgstr "Szerokość kości"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Color 1"
-msgstr "Zmień nazwę elementu koloru"
+msgstr "Kolor kości 1"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Color 2"
-msgstr "Zmień nazwę elementu koloru"
+msgstr "Kolor kości 2"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Selected Color"
-msgstr "Konfiguruj wybrany profil:"
+msgstr "Kolor zaznaczenia kości"
#: editor/editor_settings.cpp
msgid "Bone IK Color"
-msgstr ""
+msgstr "Kolor kości IK"
#: editor/editor_settings.cpp
msgid "Bone Outline Color"
-msgstr ""
+msgstr "Kolor obrysu kości"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Bone Outline Size"
-msgstr "Rozmiar zarysu:"
+msgstr "Rozmiar obrysu kości"
#: editor/editor_settings.cpp
msgid "Viewport Border Color"
-msgstr ""
+msgstr "Kolor obwódki viewportu"
#: editor/editor_settings.cpp
msgid "Constrain Editor View"
-msgstr ""
+msgstr "Ogranicz widok edytora"
#: editor/editor_settings.cpp
msgid "Simple Panning"
-msgstr ""
+msgstr "Proste przesuwanie"
#: editor/editor_settings.cpp
msgid "Scroll To Pan"
-msgstr ""
+msgstr "Przewijanie przesuwa"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Pan Speed"
-msgstr "Szybkość:"
+msgstr "Szybkość przesuwania"
#: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Poly Editor"
-msgstr "WielokÄ…t 2D UV Edytor"
+msgstr "Edytor wielokątów"
#: editor/editor_settings.cpp
msgid "Point Grab Radius"
-msgstr ""
+msgstr "Promień chwytania punktów"
#: editor/editor_settings.cpp editor/plugins/polygon_2d_editor_plugin.cpp
-#, fuzzy
msgid "Show Previous Outline"
-msgstr "Poprzednia płaszczyzna"
+msgstr "Pokaż poprzedni obrys"
#: editor/editor_settings.cpp editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Autorename Animation Tracks"
-msgstr "Zmień nazwę animacji"
+msgstr "Automatycznie przemianuj ścieżki animacji"
#: editor/editor_settings.cpp
msgid "Default Create Bezier Tracks"
-msgstr ""
+msgstr "Twórz domyślnie ścieżki Beziera"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Default Create Reset Tracks"
-msgstr "Utwórz ścieżki RESET"
+msgstr "Domyślnie twórz ścieżki resetu"
#: editor/editor_settings.cpp
msgid "Onion Layers Past Color"
-msgstr ""
+msgstr "Przeszły kolor warstw cebuli"
#: editor/editor_settings.cpp
msgid "Onion Layers Future Color"
-msgstr ""
+msgstr "Przyszły kolor warstw cebuli"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Visual Editors"
-msgstr "Edytor grup"
+msgstr "Edytory wizualne"
#: editor/editor_settings.cpp
msgid "Minimap Opacity"
@@ -6021,69 +5967,61 @@ msgstr "Przezroczystość minimapy"
#: editor/editor_settings.cpp
msgid "Window Placement"
-msgstr ""
+msgstr "Ustawienie okna"
#: editor/editor_settings.cpp scene/2d/back_buffer_copy.cpp scene/2d/sprite.cpp
#: scene/2d/visibility_notifier_2d.cpp scene/3d/sprite_3d.cpp
#: scene/gui/control.cpp
-#, fuzzy
msgid "Rect"
-msgstr "Cały obszar"
+msgstr "ProstokÄ…t"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Rect Custom Position"
-msgstr "Ustaw punkt kontrolny wychodzÄ…cy z krzywej"
+msgstr "WÅ‚asna pozycja prostokÄ…ta"
#: editor/editor_settings.cpp platform/android/export/export_plugin.cpp
msgid "Screen"
-msgstr ""
+msgstr "Ekran"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Auto Save"
-msgstr "Tnij automatycznie"
+msgstr "Autozapis"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Save Before Running"
-msgstr "Zapisz scenÄ™ przed uruchomieniem..."
+msgstr "Zapisz przed uruchomieniem"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Font Size"
-msgstr "Widok z przodu"
+msgstr "Rozmiar czcionki"
#: editor/editor_settings.cpp
#: modules/gdscript/language_server/gdscript_language_server.cpp
-#, fuzzy
msgid "Remote Host"
-msgstr "Zdalny "
+msgstr "Zdalny host"
#: editor/editor_settings.cpp
#: modules/gdscript/language_server/gdscript_language_server.cpp
-#, fuzzy
msgid "Remote Port"
-msgstr "Usuń punkt"
+msgstr "Zdalny port"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Editor SSL Certificates"
-msgstr "Ustawienia edytora"
+msgstr "Certyfikaty SSL edytora"
#: editor/editor_settings.cpp
msgid "HTTP Proxy"
-msgstr ""
+msgstr "Proxy HTTP"
#: editor/editor_settings.cpp
msgid "Host"
-msgstr ""
+msgstr "Host"
#: editor/editor_settings.cpp editor/fileserver/editor_file_server.cpp
#: main/main.cpp modules/mono/mono_gd/gd_mono.cpp
#: scene/resources/default_theme/default_theme.cpp
msgid "Port"
-msgstr ""
+msgstr "Port"
#. TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects.
#: editor/editor_settings.cpp
@@ -6092,171 +6030,150 @@ msgstr "Menedżer projektów"
#. TRANSLATORS: Project Manager here refers to the tool used to create/manage Godot projects.
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Sorting Order"
-msgstr "w kolejności:"
+msgstr "Kolejność sortowania"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Symbol Color"
-msgstr ""
+msgstr "Kolor symbolu"
#: editor/editor_settings.cpp
msgid "Keyword Color"
-msgstr ""
+msgstr "Kolor słowa kluczowego"
#: editor/editor_settings.cpp
msgid "Control Flow Keyword Color"
-msgstr ""
+msgstr "Kolor słowa kluczowego kontroli przepływu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Base Type Color"
-msgstr "Zmień typ podstawowy"
+msgstr "Kolor typu bazowego"
#: editor/editor_settings.cpp
msgid "Engine Type Color"
-msgstr ""
+msgstr "Kolor typu silnika"
#: editor/editor_settings.cpp
msgid "User Type Color"
-msgstr ""
+msgstr "Kolor typu użytkownika"
#: editor/editor_settings.cpp
msgid "Comment Color"
-msgstr ""
+msgstr "Kolor komentarza"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "String Color"
-msgstr "Zapisywanie pliku:"
+msgstr "Kolor ciągu znaków"
#: editor/editor_settings.cpp platform/javascript/export/export.cpp
#: platform/uwp/export/export.cpp
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Background Color"
-msgstr "Kolor tła nieprawidłowy."
+msgstr "Kolor tła"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Background Color"
-msgstr "Kolor tła nieprawidłowy."
+msgstr "Kolor tła uzupełniania"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Completion Selected Color"
-msgstr "Importuj zaznaczone"
+msgstr "Kolor zaznaczenia uzupełniania"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Completion Existing Color"
-msgstr ""
+msgstr "Kolor istniejącego uzupełniania"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Completion Scroll Color"
-msgstr ""
+msgstr "Kolor przewijania uzupełniania"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Completion Font Color"
-msgstr ""
+msgstr "Kolor czcionki uzupełniania"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Text Color"
-msgstr "Następny poziom"
+msgstr "Kolor tekstu"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Line Number Color"
-msgstr "Numer linii:"
+msgstr "Kolor numerów linii"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Safe Line Number Color"
-msgstr "Numer linii:"
+msgstr "Kolor numerów bezpiecznych linii"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Caret Color"
-msgstr ""
+msgstr "Kolor kursora"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Caret Background Color"
-msgstr "Kolor tła nieprawidłowy."
+msgstr "Kolor tła kursora"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Text Selected Color"
-msgstr "Usuń zaznaczone"
+msgstr "Kolor zaznaczonego tekstu"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Selection Color"
-msgstr "Tylko zaznaczenie"
+msgstr "Kolor zaznaczenia"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Brace Mismatch Color"
-msgstr ""
+msgstr "Kolor niedopasowanych nawiasów"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Current Line Color"
-msgstr "Aktualna scena"
+msgstr "Kolor aktualnej linii"
#: editor/editor_settings.cpp
msgid "Line Length Guideline Color"
-msgstr ""
+msgstr "Kolor prowadnicy długości linii"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Word Highlighted Color"
-msgstr "Podświetlacz składni"
+msgstr "Kolor podświetlonego słowa"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Number Color"
-msgstr ""
+msgstr "Kolor numeru"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Function Color"
-msgstr "Funkcja"
+msgstr "Kolor funkcji"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Member Variable Color"
-msgstr "Zmień nawę zmiennej"
+msgstr "Kolor zmiennej członkowskiej"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Mark Color"
-msgstr "Wybierz Kolor"
+msgstr "Kolor oznaczenia"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Bookmark Color"
-msgstr "Zakładki"
+msgstr "Kolor zakładki"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Breakpoint Color"
-msgstr "Punkty wstrzymania"
+msgstr "Kolor punktu wstrzymania"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Executing Line Color"
-msgstr ""
+msgstr "Kolor wywoływanej linii"
#: editor/editor_settings.cpp scene/resources/default_theme/default_theme.cpp
msgid "Code Folding Color"
-msgstr ""
+msgstr "Kolor zawinięcia kodu"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Search Result Color"
-msgstr "Wyniki wyszukiwania"
+msgstr "Kolor wyniku wyszukiwania"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Search Result Border Color"
-msgstr "Wyniki wyszukiwania"
+msgstr "Kolor obramowania wyniku wyszukiwania"
#: editor/editor_spin_slider.cpp
msgid "Hold %s to round to integers. Hold Shift for more precise changes."
@@ -6265,14 +6182,12 @@ msgstr ""
"bardziej precyzyjnych zmian."
#: editor/editor_spin_slider.cpp scene/gui/button.cpp
-#, fuzzy
msgid "Flat"
-msgstr "PÅ‚askie 0"
+msgstr "PÅ‚aski"
#: editor/editor_spin_slider.cpp
-#, fuzzy
msgid "Hide Slider"
-msgstr "Tryb kolizji"
+msgstr "Ukryj suwak"
#: editor/editor_sub_scene.cpp
msgid "Select Node(s) to Import"
@@ -6563,7 +6478,7 @@ msgstr ""
#: editor/fileserver/editor_file_server.cpp
msgid "File Server"
-msgstr ""
+msgstr "Serwer plików"
#: editor/fileserver/editor_file_server.cpp
#: editor/plugins/version_control_editor_plugin.cpp
@@ -6936,43 +6851,40 @@ msgstr "ZarzÄ…dzaj grupami"
#: editor/import/editor_import_collada.cpp
msgid "Collada"
-msgstr ""
+msgstr "Collada"
#: editor/import/editor_import_collada.cpp
msgid "Use Ambient"
-msgstr ""
+msgstr "Użyj otoczenia"
#: editor/import/resource_importer_bitmask.cpp
-#, fuzzy
msgid "Create From"
-msgstr "Utwórz katalog"
+msgstr "Utwórz z"
#: editor/import/resource_importer_bitmask.cpp
#: servers/audio/effects/audio_effect_compressor.cpp
msgid "Threshold"
-msgstr ""
+msgstr "Próg"
#: editor/import/resource_importer_csv_translation.cpp
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_scene.cpp
#: editor/import/resource_importer_texture.cpp
#: editor/import/resource_importer_wav.cpp scene/3d/gi_probe.cpp
-#, fuzzy
msgid "Compress"
-msgstr "Komponenty"
+msgstr "Skompresuj"
#: editor/import/resource_importer_csv_translation.cpp
msgid "Delimiter"
-msgstr ""
+msgstr "Separator"
#: editor/import/resource_importer_layered_texture.cpp
-#, fuzzy
msgid "ColorCorrect"
-msgstr "Funkcja koloru."
+msgstr "ColorCorrect"
#: editor/import/resource_importer_layered_texture.cpp
msgid "No BPTC If RGB"
-msgstr ""
+msgstr "Bez BPTC jeśli RGB"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp scene/2d/cpu_particles_2d.cpp
@@ -6980,31 +6892,29 @@ msgstr ""
#: scene/resources/material.cpp scene/resources/particles_material.cpp
#: scene/resources/texture.cpp scene/resources/visual_shader.cpp
msgid "Flags"
-msgstr ""
+msgstr "Flagi"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp scene/animation/tween.cpp
#: scene/resources/texture.cpp
msgid "Repeat"
-msgstr ""
+msgstr "Powtórz"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp scene/2d/light_2d.cpp
#: scene/gui/control.cpp
-#, fuzzy
msgid "Filter"
-msgstr "Filtry:"
+msgstr "Filtr"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Mipmaps"
-msgstr "Sygnały"
+msgstr "Mipmapy"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp
msgid "Anisotropic"
-msgstr ""
+msgstr "Anizotropowe"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp
@@ -7012,51 +6922,43 @@ msgid "sRGB"
msgstr "sRGB"
#: editor/import/resource_importer_layered_texture.cpp
-#, fuzzy
msgid "Slices"
-msgstr "Tnij automatycznie"
+msgstr "Kawałki"
#: editor/import/resource_importer_layered_texture.cpp
#: scene/gui/aspect_ratio_container.cpp scene/gui/control.cpp
#: scene/gui/nine_patch_rect.cpp scene/gui/scroll_container.cpp
#: scene/resources/style_box.cpp
-#, fuzzy
msgid "Horizontal"
-msgstr "Poziomo:"
+msgstr "Poziomo"
#: editor/import/resource_importer_layered_texture.cpp
#: scene/gui/aspect_ratio_container.cpp scene/gui/control.cpp
#: scene/gui/nine_patch_rect.cpp scene/gui/scroll_container.cpp
#: scene/resources/style_box.cpp
-#, fuzzy
msgid "Vertical"
-msgstr "Pionowo:"
+msgstr "Pionowo"
#: editor/import/resource_importer_obj.cpp
-#, fuzzy
msgid "Generate Tangents"
-msgstr "Wygeneruj punkty"
+msgstr "Wygeneruj styczne"
#: editor/import/resource_importer_obj.cpp
-#, fuzzy
msgid "Scale Mesh"
-msgstr "Tryb skalowania"
+msgstr "Skaluj siatkÄ™"
#: editor/import/resource_importer_obj.cpp
-#, fuzzy
msgid "Offset Mesh"
-msgstr "Przesunięcie:"
+msgstr "Przesuń siatkę"
#: editor/import/resource_importer_obj.cpp
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Octahedral Compression"
-msgstr "Kompresja"
+msgstr "Kompresja ośmiościenna"
#: editor/import/resource_importer_obj.cpp
-#, fuzzy
msgid "Optimize Mesh Flags"
-msgstr "Rozmiar: "
+msgstr "Optymalizuj flagi siatki"
#: editor/import/resource_importer_scene.cpp
msgid "Import as Single Scene"
@@ -7100,101 +7002,84 @@ msgstr "Importuj jako wiele scen + materiały"
#: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp
#: scene/3d/physics_joint.cpp
-#, fuzzy
msgid "Nodes"
-msgstr "Węzeł"
+msgstr "Węzły"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Root Type"
-msgstr "Wróć"
+msgstr "Typ korzenia"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Root Name"
-msgstr "Nazwa zdalnego repozytorium"
+msgstr "Nazwa korzenia"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Root Scale"
-msgstr "Skaluj"
+msgstr "Skala korzenia"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Custom Script"
-msgstr "NiestandardowyWęzeł"
+msgstr "WÅ‚asny skrypt"
#: editor/import/resource_importer_scene.cpp scene/resources/texture.cpp
-#, fuzzy
msgid "Storage"
-msgstr "Zapisywanie pliku:"
+msgstr "Przechowywanie"
#: editor/import/resource_importer_scene.cpp
msgid "Use Legacy Names"
-msgstr ""
+msgstr "Użyj starszych nazw"
#: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Materials"
-msgstr "Zmiany materiału:"
+msgstr "Materiały"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Keep On Reimport"
-msgstr "Importuj ponownie"
+msgstr "Zachowaj po reimporcie"
#: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Meshes"
-msgstr "Siatka"
+msgstr "Siatki"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Ensure Tangents"
-msgstr "Modyfikuj stycznÄ… krzywej"
+msgstr "Zapewnij styczne"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Light Baking"
-msgstr "Lightmapping"
+msgstr "Wypalanie światła"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Lightmap Texel Size"
-msgstr "Stwórz Lightmaps"
+msgstr "Rozmiar teksela mapy światła"
#: editor/import/resource_importer_scene.cpp modules/gltf/gltf_state.cpp
msgid "Skins"
-msgstr ""
+msgstr "Skórki"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Use Named Skins"
-msgstr "Użyj przyciągania skali"
+msgstr "Używaj nazwanych skórek"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "External Files"
-msgstr "Otwórz plik"
+msgstr "Pliki zewnętrzne"
#: editor/import/resource_importer_scene.cpp
msgid "Store In Subdir"
-msgstr ""
+msgstr "Przechowaj w podfolderze"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Filter Script"
-msgstr "Filtruj skrypty"
+msgstr "Skrypt filtra"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Keep Custom Tracks"
-msgstr "Przekształcanie"
+msgstr "Zachowaj własne ścieżki"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Optimizer"
-msgstr "Zoptymalizuj"
+msgstr "Optymalizator"
#: editor/import/resource_importer_scene.cpp
#: editor/plugins/item_list_editor_plugin.cpp main/main.cpp
@@ -7208,41 +7093,34 @@ msgstr "Zoptymalizuj"
#: scene/3d/sprite_3d.cpp scene/gui/graph_edit.cpp
#: scene/gui/rich_text_label.cpp scene/resources/curve.cpp
#: scene/resources/environment.cpp scene/resources/material.cpp
-#, fuzzy
msgid "Enabled"
-msgstr "WÅ‚Ä…cz"
+msgstr "WÅ‚Ä…czony"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Max Linear Error"
-msgstr "Maks. błąd liniowy:"
+msgstr "Maks. błąd liniowy"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Max Angular Error"
-msgstr "Maks. błąd kątowy:"
+msgstr "Maks. błąd kątowy"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Max Angle"
-msgstr "Wartość"
+msgstr "Maksymalny kÄ…t"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Remove Unused Tracks"
-msgstr "Usuń ścieżkę animacji"
+msgstr "Usuń nieużywane ścieżki"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Clips"
-msgstr "Klipy animacji"
+msgstr "Klipy"
#: editor/import/resource_importer_scene.cpp scene/2d/cpu_particles_2d.cpp
#: scene/2d/particles_2d.cpp scene/3d/area.cpp scene/3d/cpu_particles.cpp
#: scene/3d/particles.cpp scene/resources/environment.cpp
-#, fuzzy
msgid "Amount"
-msgstr "Ilośc:"
+msgstr "Ilość"
#: editor/import/resource_importer_scene.cpp
#: editor/plugins/mesh_library_editor_plugin.cpp
@@ -7258,9 +7136,8 @@ msgid "Generating Lightmaps"
msgstr "Generowanie Lightmapy"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Generating for Mesh:"
-msgstr "Generowanie dla siatki: "
+msgstr "Generowanie dla siatki:"
#: editor/import/resource_importer_scene.cpp
msgid "Running Custom Script..."
@@ -7293,34 +7170,37 @@ msgid ""
"%s: Texture detected as used as a normal map in 3D. Enabling red-green "
"texture compression to reduce memory usage (blue channel is discarded)."
msgstr ""
+"%s: Tekstura wykryta jako mapa normalnych w 3D. WÅ‚Ä…czam czerwono-zielonÄ… "
+"kompresję tekstury, by zmniejszyć zużycie pamięci (niebieski kanał jest "
+"odrzucony)."
#: editor/import/resource_importer_texture.cpp
msgid ""
"%s: Texture detected as used in 3D. Enabling filter, repeat, mipmap "
"generation and VRAM texture compression."
msgstr ""
+"%s: Tekstura wykryta jako używana w 3D. Włączam filtrowanie, powtarzanie, "
+"generacjÄ™ mipmap i kompresjÄ™ tekstur VRAM."
#: editor/import/resource_importer_texture.cpp
msgid "2D, Detect 3D"
-msgstr ""
+msgstr "2D, wykryj 3D"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "2D Pixel"
-msgstr "Widoczne piksele"
+msgstr "2D piksel"
#: editor/import/resource_importer_texture.cpp scene/resources/texture.cpp
msgid "Lossy Quality"
-msgstr ""
+msgstr "Stratna jakość"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "HDR Mode"
-msgstr "Tryb zaznaczenia"
+msgstr "Tryb HDR"
#: editor/import/resource_importer_texture.cpp
msgid "BPTC LDR"
-msgstr ""
+msgstr "LDR BPTC"
#: editor/import/resource_importer_texture.cpp
#: editor/plugins/tile_set_editor_plugin.cpp scene/2d/cpu_particles_2d.cpp
@@ -7330,105 +7210,94 @@ msgid "Normal Map"
msgstr "Mapa normalnych"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Process"
-msgstr "Przetwarzanie końcowe"
+msgstr "Przetwarzanie"
#: editor/import/resource_importer_texture.cpp
msgid "Fix Alpha Border"
-msgstr ""
+msgstr "Popraw obramowanie alfa"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Premult Alpha"
-msgstr "Edytuj wielokÄ…t"
+msgstr "Wstępnie przemnóż alfę"
#: editor/import/resource_importer_texture.cpp
msgid "Hdr As Srgb"
-msgstr ""
+msgstr "HDR jako sRGB"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Invert Color"
-msgstr "Wierzchołki"
+msgstr "Odwróć kolor"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Normal Map Invert Y"
-msgstr "Losowa skala:"
+msgstr "Odwróć Y mapy normalnych"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Size Limit"
-msgstr "Limity"
+msgstr "Limit rozmiaru"
#: editor/import/resource_importer_texture.cpp
msgid "Detect 3D"
-msgstr ""
+msgstr "Wykryj 3D"
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "SVG"
-msgstr "HSV"
+msgstr "SVG"
#: editor/import/resource_importer_texture.cpp
msgid ""
"Warning, no suitable PC VRAM compression enabled in Project Settings. This "
"texture will not display correctly on PC."
msgstr ""
+"Ostrzeżenie, brak ustawionej w ustawieniach projektu odpowiedniej kompresji "
+"PC VRAM. Ta tekstura nie będzie się poprawnie wyświetlać na PC."
#: editor/import/resource_importer_texture_atlas.cpp
-#, fuzzy
msgid "Atlas File"
-msgstr "Rozmiar zarysu:"
+msgstr "Plik atlasu"
#: editor/import/resource_importer_texture_atlas.cpp
-#, fuzzy
msgid "Import Mode"
-msgstr "Tryb eksportu:"
+msgstr "Tryb importu"
#: editor/import/resource_importer_texture_atlas.cpp
-#, fuzzy
msgid "Crop To Region"
-msgstr "Ustaw obszar Kafelka"
+msgstr "Przytnij do regionu"
#: editor/import/resource_importer_texture_atlas.cpp
msgid "Trim Alpha Border From Region"
-msgstr ""
+msgstr "Przytnij obramowanie alfy z regionu"
#: editor/import/resource_importer_wav.cpp scene/2d/physics_body_2d.cpp
-#, fuzzy
msgid "Force"
-msgstr "Wrzuć na siłę"
+msgstr "Siła"
#: editor/import/resource_importer_wav.cpp
msgid "8 Bit"
-msgstr ""
+msgstr "8 bitów"
#: editor/import/resource_importer_wav.cpp main/main.cpp
#: modules/mono/editor/csharp_project.cpp modules/mono/godotsharp_dirs.cpp
#: modules/mono/mono_gd/gd_mono.cpp
msgid "Mono"
-msgstr ""
+msgstr "Mono"
#: editor/import/resource_importer_wav.cpp
-#, fuzzy
msgid "Max Rate"
-msgstr "Węzeł Mieszania"
+msgstr "Maksymalne tempo"
#: editor/import/resource_importer_wav.cpp
-#, fuzzy
msgid "Max Rate Hz"
-msgstr "Węzeł Mieszania"
+msgstr "Maksymalne tempo Hz"
#: editor/import/resource_importer_wav.cpp
msgid "Trim"
-msgstr ""
+msgstr "Przytnij"
#: editor/import/resource_importer_wav.cpp
-#, fuzzy
msgid "Normalize"
-msgstr "Format"
+msgstr "Normalizuj"
#: editor/import/resource_importer_wav.cpp
#: scene/resources/audio_stream_sample.cpp
@@ -7437,15 +7306,13 @@ msgstr "Tryb zapętlenia"
#: editor/import/resource_importer_wav.cpp
#: scene/resources/audio_stream_sample.cpp
-#, fuzzy
msgid "Loop Begin"
-msgstr "Tryb przesuwania"
+msgstr "Początek pętli"
#: editor/import/resource_importer_wav.cpp
#: scene/resources/audio_stream_sample.cpp
-#, fuzzy
msgid "Loop End"
-msgstr "Tryb przesuwania"
+msgstr "Koniec pętli"
#: editor/import_defaults_editor.cpp
msgid "Select Importer"
@@ -7523,27 +7390,24 @@ msgid "Failed to load resource."
msgstr "Nie udało się wczytać zasobu."
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Property Name Style"
-msgstr "Nazwa projektu:"
+msgstr "Styl nazw właściwości"
#: editor/inspector_dock.cpp scene/gui/color_picker.cpp
msgid "Raw"
msgstr "Raw"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Capitalized"
-msgstr "Wielkie litery na początku słów"
+msgstr "Z wielkiej litery"
#: editor/inspector_dock.cpp
-#, fuzzy
msgid "Localized"
-msgstr "Ustawienia regionalne"
+msgstr "TÅ‚umaczone"
#: editor/inspector_dock.cpp
msgid "Localization not available for current language."
-msgstr ""
+msgstr "Tłumaczenie niedostępne dla aktualnego języka."
#: editor/inspector_dock.cpp
msgid "Copy Properties"
@@ -8088,9 +7952,8 @@ msgid "New"
msgstr "Nowy"
#: editor/plugins/animation_player_editor_plugin.cpp
-#, fuzzy
msgid "Paste As Reference"
-msgstr "Referencja klasy %s"
+msgstr "Wklej jako referencjÄ™"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Edit Transitions..."
@@ -8281,9 +8144,8 @@ msgid "Set the end animation. This is useful for sub-transitions."
msgstr "Ustaw koniec animacji. To jest przydatne dla podprzejść."
#: editor/plugins/animation_state_machine_editor.cpp
-#, fuzzy
msgid "Transition:"
-msgstr "Przejście: "
+msgstr "Przejście:"
#: editor/plugins/animation_state_machine_editor.cpp
msgid "Play Mode:"
@@ -8420,7 +8282,7 @@ msgstr "Filtry..."
#: editor/plugins/asset_library_editor_plugin.cpp scene/main/http_request.cpp
msgid "Use Threads"
-msgstr ""
+msgstr "Używaj wątków"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Contents:"
@@ -8548,9 +8410,8 @@ msgid "Download Error"
msgstr "BÅ‚Ä…d pobierania"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgid "Available URLs"
-msgstr "Dostępne profile:"
+msgstr "Dostępne URL"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Download for this asset is already in progress!"
@@ -8585,25 +8446,21 @@ msgid "Loading..."
msgstr "Wczytywanie..."
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgctxt "Pagination"
msgid "First"
msgstr "PoczÄ…tek"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgctxt "Pagination"
msgid "Previous"
msgstr "Wstecz"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgctxt "Pagination"
msgid "Next"
msgstr "Dalej"
#: editor/plugins/asset_library_editor_plugin.cpp
-#, fuzzy
msgctxt "Pagination"
msgid "Last"
msgstr "Koniec"
@@ -8654,7 +8511,7 @@ msgstr "Testowanie"
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Failed to get repository configuration."
-msgstr ""
+msgstr "Nie udało się uzyskać konfiguracji repozytorium."
#: editor/plugins/asset_library_editor_plugin.cpp
msgid "Assets ZIP File"
@@ -8713,7 +8570,7 @@ msgstr "Stwórz Lightmaps"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "LightMap Bake"
-msgstr ""
+msgstr "Wypal mapę światła"
#: editor/plugins/baked_lightmap_editor_plugin.cpp
msgid "Select lightmap bake file:"
@@ -9220,23 +9077,20 @@ msgid "View"
msgstr "Widok"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Show"
-msgstr "Pokaż siatkę"
+msgstr "Pokaż"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Show When Snapping"
-msgstr "Inteligentne przyciÄ…ganie"
+msgstr "Pokaż podczas przyciągania"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Hide"
-msgstr ""
+msgstr "Ukryj"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Grid"
-msgstr "Przełącz tryb"
+msgstr "Przełącz siatkę"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
@@ -9588,16 +9442,15 @@ msgstr "Gradient edytowany"
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
msgid "Swap GradientTexture2D Fill Points"
-msgstr ""
+msgstr "Zamień punkty wypełnienia GradientTexture2D"
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
msgid "Swap Gradient Fill Points"
-msgstr ""
+msgstr "Zamień punkty wypełnienia gradientu"
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Grid Snap"
-msgstr "Przełącz tryb"
+msgstr "Przełącz przyciąganie do siatki"
#: editor/plugins/item_list_editor_plugin.cpp editor/project_export.cpp
#: scene/3d/label_3d.cpp scene/gui/button.cpp scene/gui/dialogs.cpp
@@ -9616,13 +9469,12 @@ msgstr "Ikona"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "ID"
-msgstr ""
+msgstr "ID"
#: editor/plugins/item_list_editor_plugin.cpp
#: scene/resources/default_theme/default_theme.cpp
-#, fuzzy
msgid "Separator"
-msgstr "Separacja:"
+msgstr "Separator"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "Item %d"
@@ -9859,9 +9711,8 @@ msgstr ""
"%s"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "MeshLibrary"
-msgstr "Biblioteka meshów"
+msgstr "Biblioteka siatek"
#: editor/plugins/mesh_library_editor_plugin.cpp
msgid "Add Item"
@@ -9884,14 +9735,12 @@ msgid "Update from Scene"
msgstr "Aktualizuj ze sceny"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "Apply without Transforms"
-msgstr "Zastosuj transformacje MeshInstance"
+msgstr "Zastosuj bez transformacji"
#: editor/plugins/mesh_library_editor_plugin.cpp
-#, fuzzy
msgid "Apply with Transforms"
-msgstr "Zastosuj transformacje MeshInstance"
+msgstr "Zastosuj z transformacjami"
#: editor/plugins/multimesh_editor_plugin.cpp
msgid "No mesh source specified (and no MultiMesh set in node)."
@@ -10059,9 +9908,8 @@ msgid "Volume"
msgstr "Głośność"
#: editor/plugins/particles_editor_plugin.cpp
-#, fuzzy
msgid "Emission Source:"
-msgstr "Źródła emisji: "
+msgstr "Źródło emisji:"
#: editor/plugins/particles_editor_plugin.cpp
msgid "A processor material of type 'ParticlesMaterial' is required."
@@ -10417,7 +10265,7 @@ msgstr "Synchronizuj kości z wielokątem"
#: editor/plugins/ray_cast_2d_editor_plugin.cpp
msgid "Set cast_to"
-msgstr ""
+msgstr "Ustaw cast_to"
#: editor/plugins/resource_preloader_editor_plugin.cpp
msgid "ERROR: Couldn't load resource!"
@@ -10748,58 +10596,51 @@ msgstr "Wyniki wyszukiwania"
#: editor/plugins/script_editor_plugin.cpp
msgid "Open Dominant Script On Scene Change"
-msgstr ""
+msgstr "Otwórz dominujący skrypt przy zmianie sceny"
#: editor/plugins/script_editor_plugin.cpp
msgid "External"
-msgstr ""
+msgstr "Zewnętrzne"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Use External Editor"
-msgstr "Debugowanie z zewnętrznym edytorem"
+msgstr "Użyj zewnętrznego edytora"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Exec Path"
-msgstr "Ścieżka eksportu"
+msgstr "Ścieżka uruchomienia"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Script Temperature Enabled"
-msgstr "Wybierz plik szablonu"
+msgstr "Włącz temperaturę skryptów"
#: editor/plugins/script_editor_plugin.cpp
msgid "Highlight Current Script"
-msgstr ""
+msgstr "Podświetl aktualny skrypt"
#: editor/plugins/script_editor_plugin.cpp
msgid "Script Temperature History Size"
-msgstr ""
+msgstr "Rozmiar historii temperatury skryptów"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Current Script Background Color"
-msgstr "Kolor tła nieprawidłowy."
+msgstr "Kolor tła aktualnego skryptu"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Group Help Pages"
-msgstr "Grupuj wybrane"
+msgstr "Grupuj strony pomocy"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "Sort Scripts By"
-msgstr "Utwórz Skrypt"
+msgstr "Sortuj skrypty po"
#: editor/plugins/script_editor_plugin.cpp
-#, fuzzy
msgid "List Script Names As"
-msgstr "Nazwa skryptu:"
+msgstr "Listuj nazwy skryptów jako"
#: editor/plugins/script_editor_plugin.cpp
msgid "Exec Flags"
-msgstr ""
+msgstr "Parametry uruchomienia"
#: editor/plugins/script_editor_plugin.cpp
msgid "Clear Recent Scripts"
@@ -11118,7 +10959,7 @@ msgstr "Tył perspektywicznie"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portale aktywne]"
@@ -11160,15 +11001,13 @@ msgstr "Przesuń"
#. TRANSLATORS: Refers to changing the scale of a node in the 3D editor.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scaling:"
-msgstr "Skalowanie: "
+msgstr "Skalowanie:"
#. TRANSLATORS: Refers to changing the position of a node in the 3D editor.
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Translating:"
-msgstr "Przesuwanie: "
+msgstr "Przesuwanie:"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Rotating %s degrees."
@@ -11316,13 +11155,14 @@ msgstr "PodglÄ…d kinowy"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "(Not in GLES2)"
-msgstr ""
+msgstr "(Nie w GLES2)"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid ""
"Debug draw modes are only available when using the GLES3 renderer, not GLES2."
-msgstr "Niedostępne dla renderera GLES2."
+msgstr ""
+"Tryby rysowania debugowego są dostępne tylko w przypadku korzystania z "
+"renderera GLES3, a nie GLES2."
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Freelook Left"
@@ -11617,16 +11457,15 @@ msgstr "Po"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Manipulator Gizmo Size"
-msgstr ""
+msgstr "Regulacja wielkości uchwytu"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Manipulator Gizmo Opacity"
-msgstr ""
+msgstr "Regulacja przezroczystości uchwytu"
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Show Viewport Rotation Gizmo"
-msgstr "Zablokuj obrót widoku"
+msgstr "Pokaż obrót widoku uchwytu"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unnamed Gizmo"
@@ -11678,9 +11517,8 @@ msgid "Invalid geometry, can't replace by mesh."
msgstr "Nieprawidłowa geometria, nie można zastąpić przez siatkę."
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Convert to MeshInstance2D"
-msgstr "Zamień na Mesh2D"
+msgstr "Konwertuj do MeshInstance2D"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Invalid geometry, can't create polygon."
@@ -11711,19 +11549,16 @@ msgid "Sprite"
msgstr "Sprite"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Simplification:"
-msgstr "Uproszczenie: "
+msgstr "Uproszczenie:"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Shrink (Pixels):"
-msgstr "Zmniejsz (piksele): "
+msgstr "Zmniejsz (piksele):"
#: editor/plugins/sprite_editor_plugin.cpp
-#, fuzzy
msgid "Grow (Pixels):"
-msgstr "Zwiększ (piksele): "
+msgstr "Zwiększ (piksele):"
#: editor/plugins/sprite_editor_plugin.cpp
msgid "Update Preview"
@@ -11786,9 +11621,8 @@ msgid "New Animation"
msgstr "Nowa animacja"
#: editor/plugins/sprite_frames_editor_plugin.cpp
-#, fuzzy
msgid "Filter animations"
-msgstr "Filtruj metody"
+msgstr "Filtruj animacje"
#: editor/plugins/sprite_frames_editor_plugin.cpp
msgid "Speed:"
@@ -12088,9 +11922,8 @@ msgstr ""
"Zamknąć tak czy inaczej?"
#: editor/plugins/theme_editor_plugin.cpp
-#, fuzzy
msgid "Remove Type"
-msgstr "Usuń Kafelek"
+msgstr "Usuń typ"
#: editor/plugins/theme_editor_plugin.cpp
msgid ""
@@ -16481,7 +16314,7 @@ msgstr ""
#: main/main.cpp
msgid "Verbose stdout"
-msgstr ""
+msgstr "Werbalne stdout"
#: main/main.cpp scene/main/scene_tree.cpp scene/resources/multimesh.cpp
#, fuzzy
@@ -16500,11 +16333,11 @@ msgstr "Powiększ do zaznaczenia"
#: main/main.cpp
msgid "Low Processor Mode"
-msgstr ""
+msgstr "Tryb niskiego wykorzystania procesora"
#: main/main.cpp
msgid "Delta Sync After Draw"
-msgstr ""
+msgstr "Synchronizacja delta po wyświetlaniu"
#: main/main.cpp
msgid "iOS"
@@ -16512,7 +16345,7 @@ msgstr "iOS"
#: main/main.cpp
msgid "Hide Home Indicator"
-msgstr ""
+msgstr "Ukryj wskaźnik powitalny"
#: main/main.cpp
#, fuzzy
@@ -16526,11 +16359,11 @@ msgstr "Punkt"
#: main/main.cpp
msgid "Touch Delay"
-msgstr ""
+msgstr "Opóźnienie dotyku"
#: main/main.cpp servers/visual_server.cpp
msgid "GLES3"
-msgstr ""
+msgstr "GLES3"
#: main/main.cpp servers/visual_server.cpp
#, fuzzy
@@ -16555,43 +16388,39 @@ msgstr ""
#: main/main.cpp
msgid "Boot Splash"
-msgstr ""
+msgstr "Ekran uruchamiania"
#: main/main.cpp
-#, fuzzy
msgid "Show Image"
-msgstr "Pokaż kości"
+msgstr "Pokaż obraz"
#: main/main.cpp
msgid "Image"
-msgstr ""
+msgstr "Obraz"
#: main/main.cpp
msgid "Fullsize"
-msgstr ""
+msgstr "Pełny rozmiar"
#: main/main.cpp scene/resources/dynamic_font.cpp
-#, fuzzy
msgid "Use Filter"
-msgstr "Filtr:"
+msgstr "Użyj filtra"
#: main/main.cpp scene/resources/style_box.cpp
-#, fuzzy
msgid "BG Color"
-msgstr "Kolory"
+msgstr "Kolor tła"
#: main/main.cpp
-#, fuzzy
msgid "macOS Native Icon"
-msgstr "Ustaw ikonÄ™ Kafelka"
+msgstr "Ikona natywna macOS"
#: main/main.cpp
msgid "Windows Native Icon"
-msgstr ""
+msgstr "Ikona natywna Windows"
#: main/main.cpp
msgid "Buffering"
-msgstr ""
+msgstr "Buforowanie"
#: main/main.cpp
msgid "Agile Event Flushing"
@@ -16599,30 +16428,27 @@ msgstr ""
#: main/main.cpp
msgid "Emulate Touch From Mouse"
-msgstr ""
+msgstr "Emulacja dotyku za pomocÄ… myszy"
#: main/main.cpp
msgid "Emulate Mouse From Touch"
-msgstr ""
+msgstr "Emulacja myszy za pomocÄ… dotyku"
#: main/main.cpp
-#, fuzzy
msgid "Mouse Cursor"
-msgstr "Przycisk myszy"
+msgstr "Kursor myszy"
#: main/main.cpp
-#, fuzzy
msgid "Custom Image"
-msgstr "NiestandardowyWęzeł"
+msgstr "Niestandardowy obraz"
#: main/main.cpp
msgid "Custom Image Hotspot"
-msgstr ""
+msgstr "Własny punkt dostępu do obrazów"
#: main/main.cpp
-#, fuzzy
msgid "Tooltip Position Offset"
-msgstr "Offset obrotu:"
+msgstr "Przesunięcie pozycji podpowiedzi"
#: main/main.cpp modules/mono/mono_gd/gd_mono.cpp
#, fuzzy
@@ -16630,22 +16456,20 @@ msgid "Debugger Agent"
msgstr "Debugger"
#: main/main.cpp modules/mono/mono_gd/gd_mono.cpp
-#, fuzzy
msgid "Wait For Debugger"
-msgstr "Debugger"
+msgstr "Czekanie na Debuggera"
#: main/main.cpp modules/mono/mono_gd/gd_mono.cpp
-#, fuzzy
msgid "Wait Timeout"
-msgstr "Przekroczenie czasu."
+msgstr "Limit czasu oczekiwania"
#: main/main.cpp
msgid "Runtime"
-msgstr ""
+msgstr "Åšrodowisko pracy"
#: main/main.cpp
msgid "Unhandled Exception Policy"
-msgstr ""
+msgstr "Polityka dotycząca wyjątków nieobsługiwanych"
#: main/main.cpp
#, fuzzy
@@ -16654,22 +16478,20 @@ msgstr "Znajdź typ węzła"
#: main/main.cpp scene/gui/texture_progress.cpp
#: scene/gui/viewport_container.cpp
-#, fuzzy
msgid "Stretch"
-msgstr "Załaduj"
+msgstr "RozciÄ…gnij"
#: main/main.cpp
-#, fuzzy
msgid "Aspect"
-msgstr "Inspektor"
+msgstr "Aspekt"
#: main/main.cpp
msgid "Shrink"
-msgstr ""
+msgstr "Zmniejsz"
#: main/main.cpp scene/main/scene_tree.cpp
msgid "Auto Accept Quit"
-msgstr ""
+msgstr "Automatyczne akceptowanie zamknięcia"
#: main/main.cpp scene/main/scene_tree.cpp
#, fuzzy
@@ -16677,25 +16499,24 @@ msgid "Quit On Go Back"
msgstr "Wróć"
#: main/main.cpp scene/main/viewport.cpp
-#, fuzzy
msgid "Snap Controls To Pixels"
-msgstr "Przyciągaj do boków węzła"
+msgstr "Przymocuj elementy sterujÄ…ce do pikseli"
#: main/main.cpp
msgid "Dynamic Fonts"
-msgstr ""
+msgstr "Czcionki dynamiczne"
#: main/main.cpp
msgid "Use Oversampling"
-msgstr ""
+msgstr "Zastosuj nadpróbkowanie"
#: modules/bullet/register_types.cpp modules/bullet/space_bullet.cpp
msgid "Active Soft World"
-msgstr ""
+msgstr "Aktywuj wsparcie SoftBody World"
#: modules/csg/csg_gizmos.cpp
msgid "CSG"
-msgstr ""
+msgstr "CSG"
#: modules/csg/csg_gizmos.cpp
msgid "Change Cylinder Radius"
@@ -16714,30 +16535,26 @@ msgid "Change Torus Outer Radius"
msgstr "Zmień zewnętrzny promień torusa"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Operation"
-msgstr "Opcje"
+msgstr "Operacja"
#: modules/csg/csg_shape.cpp
msgid "Calculate Tangents"
-msgstr ""
+msgstr "Oblicz styczne"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Use Collision"
-msgstr "Kolizja"
+msgstr "Użyj kolizji"
#: modules/csg/csg_shape.cpp servers/physics_2d_server.cpp
-#, fuzzy
msgid "Collision Layer"
-msgstr "Tryb kolizji"
+msgstr "Warstwa kolizji"
#: modules/csg/csg_shape.cpp scene/2d/ray_cast_2d.cpp scene/3d/camera.cpp
#: scene/3d/ray_cast.cpp scene/3d/spring_arm.cpp
#: scene/resources/navigation_mesh.cpp servers/physics_server.cpp
-#, fuzzy
msgid "Collision Mask"
-msgstr "Tryb kolizji"
+msgstr "Maska kolizji"
#: modules/csg/csg_shape.cpp
#, fuzzy
@@ -16752,9 +16569,8 @@ msgstr "Zmień wielkość liter"
#: scene/resources/cylinder_shape.cpp scene/resources/environment.cpp
#: scene/resources/navigation_mesh.cpp scene/resources/primitive_meshes.cpp
#: scene/resources/sphere_shape.cpp
-#, fuzzy
msgid "Radius"
-msgstr "Promień:"
+msgstr "Promień"
#: modules/csg/csg_shape.cpp scene/resources/primitive_meshes.cpp
#, fuzzy
@@ -16762,33 +16578,28 @@ msgid "Radial Segments"
msgstr "Argumenty głównej sceny:"
#: modules/csg/csg_shape.cpp scene/resources/primitive_meshes.cpp
-#, fuzzy
msgid "Rings"
-msgstr "Ostrzeżenia"
+msgstr "Pierścienie"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Smooth Faces"
-msgstr "PÅ‚ynny Krok"
+msgstr "GÅ‚adkie twarze"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Sides"
-msgstr "Pokaż prowadnice"
+msgstr "Boki"
#: modules/csg/csg_shape.cpp
msgid "Cone"
-msgstr ""
+msgstr "Stożek"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Inner Radius"
-msgstr "Zmień wewnętrzny promień torusa"
+msgstr "Promień wewnętrzny"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Outer Radius"
-msgstr "Zmień zewnętrzny promień torusa"
+msgstr "promień zewnętrzny"
#: modules/csg/csg_shape.cpp
msgid "Ring Sides"
@@ -16797,7 +16608,6 @@ msgstr ""
#: modules/csg/csg_shape.cpp scene/2d/collision_polygon_2d.cpp
#: scene/2d/light_occluder_2d.cpp scene/2d/polygon_2d.cpp
#: scene/3d/collision_polygon.cpp
-#, fuzzy
msgid "Polygon"
msgstr "WielokÄ…t"
@@ -16810,9 +16620,8 @@ msgid "Spin Sides"
msgstr ""
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Node"
-msgstr "Wklej węzły"
+msgstr "Ścieżka węzła"
#: modules/csg/csg_shape.cpp
#, fuzzy
@@ -16821,21 +16630,19 @@ msgstr "Utwórz wewnętrzny wierzchołek"
#: modules/csg/csg_shape.cpp
msgid "Path Interval"
-msgstr ""
+msgstr "Odstęp między ścieżkami"
#: modules/csg/csg_shape.cpp
msgid "Path Simplify Angle"
msgstr ""
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Rotation"
-msgstr "Obrót losowy:"
+msgstr "Obrót ścieżki"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Local"
-msgstr "Uczyń lokalnym"
+msgstr "Ścieżka lokalna"
#: modules/csg/csg_shape.cpp
#, fuzzy
@@ -17046,7 +16853,7 @@ msgstr "Nie bazuje na pliku zasobów"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (missing @path)"
-msgstr "Niepoprawna instancja formatu słownika (brakujący @path)"
+msgstr "Niepoprawna instancja formatu słownika (brakuje @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary format (can't load script at @path)"
@@ -17059,7 +16866,7 @@ msgstr "Niepoprawna instancja formatu słownika (niepoprawny skrypt w @path)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Invalid instance dictionary (invalid subclasses)"
-msgstr "Niepoprawna instancja słownika (niepoprawne podklasy)"
+msgstr "Niepoprawny słownik instancji (niepoprawne podklasy)"
#: modules/gdscript/gdscript_functions.cpp
msgid "Object can't provide a length."
@@ -17288,27 +17095,27 @@ msgstr "Przesuń złącze"
#: modules/gltf/gltf_skin.cpp
msgid "Joint I To Bone I"
-msgstr ""
+msgstr "Staw I do kości I"
#: modules/gltf/gltf_skin.cpp
msgid "Joint I To Name"
-msgstr ""
+msgstr "Staw I do nazwy"
#: modules/gltf/gltf_skin.cpp
msgid "Godot Skin"
-msgstr ""
+msgstr "Skórka Godot"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Diffuse Img"
-msgstr ""
+msgstr "Rozmycie obrazu"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Diffuse Factor"
-msgstr ""
+msgstr "Współczynnik rozmycia"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Gloss Factor"
-msgstr ""
+msgstr "Współczynnik połysku"
#: modules/gltf/gltf_spec_gloss.cpp
#, fuzzy
@@ -17391,19 +17198,16 @@ msgid "Skeletons"
msgstr "Szkielet"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Skeleton To Node"
-msgstr "Wybierz węzeł"
+msgstr "Szkielet do węzła"
#: modules/gltf/gltf_state.cpp
-#, fuzzy
msgid "Animations"
-msgstr "Animacje:"
+msgstr "Animacje"
#: modules/gltf/gltf_texture.cpp
-#, fuzzy
msgid "Src Image"
-msgstr "Pokaż kości"
+msgstr "Obraz źródłowy"
#: modules/gridmap/grid_map.cpp
msgid "Mesh Library"
@@ -17421,33 +17225,29 @@ msgstr "Stwórz Lightmaps"
#: modules/gridmap/grid_map.cpp scene/2d/tile_map.cpp
msgid "Cell"
-msgstr ""
+msgstr "Komórka"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Octant Size"
-msgstr "Widok z przodu"
+msgstr "Wielkość oktantu"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Center X"
-msgstr "Wyśrodkowane"
+msgstr "Wyśrodkowanie X"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Center Y"
-msgstr "Wyśrodkowane"
+msgstr "Wyśrodkowanie Y"
#: modules/gridmap/grid_map.cpp
-#, fuzzy
msgid "Center Z"
-msgstr "Wyśrodkowane"
+msgstr "Wyśrodkowanie Z"
#: modules/gridmap/grid_map.cpp scene/2d/collision_object_2d.cpp
#: scene/2d/tile_map.cpp scene/3d/collision_object.cpp scene/3d/soft_body.cpp
#: scene/resources/material.cpp
msgid "Mask"
-msgstr ""
+msgstr "Maska"
#: modules/gridmap/grid_map.cpp scene/2d/tile_map.cpp
#, fuzzy
@@ -17458,9 +17258,8 @@ msgstr "Nawigacja"
#: scene/2d/navigation_agent_2d.cpp scene/2d/navigation_polygon.cpp
#: scene/2d/tile_map.cpp scene/3d/navigation.cpp scene/3d/navigation_agent.cpp
#: scene/3d/navigation_mesh_instance.cpp
-#, fuzzy
msgid "Navigation Layers"
-msgstr "Tryb nawigacji"
+msgstr "Warstwy nawigacji"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -17620,9 +17419,8 @@ msgid "Plotting lightmaps"
msgstr "Kreślenie map światła"
#: modules/lightmapper_cpu/register_types.cpp
-#, fuzzy
msgid "CPU Lightmapper"
-msgstr "Stwórz Lightmaps"
+msgstr "Mapper światła CPU"
#: modules/lightmapper_cpu/register_types.cpp
msgid "Low Quality Ray Count"
@@ -17644,22 +17442,20 @@ msgstr ""
#: modules/minimp3/resource_importer_mp3.cpp
#: modules/stb_vorbis/audio_stream_ogg_vorbis.cpp
#: modules/stb_vorbis/resource_importer_ogg_vorbis.cpp
-#, fuzzy
msgid "Loop Offset"
-msgstr "Przesunięcie:"
+msgstr "Przesunięcie pętli"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "Eye Height"
-msgstr ""
+msgstr "Wysokość oczu"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "IOD"
-msgstr ""
+msgstr "IOD"
#: modules/mobile_vr/mobile_vr_interface.cpp
-#, fuzzy
msgid "Display Width"
-msgstr "Widok siatki"
+msgstr "Szerokość wyświetlacza"
#: modules/mobile_vr/mobile_vr_interface.cpp
#, fuzzy
@@ -17668,15 +17464,15 @@ msgstr "Widok bezcieniowy"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "Oversample"
-msgstr ""
+msgstr "Nadpróbkowanie"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "K1"
-msgstr ""
+msgstr "K1"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "K2"
-msgstr ""
+msgstr "K2"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -17687,14 +17483,12 @@ msgid "Build Solution"
msgstr "Zbuduj rozwiÄ…zanie"
#: modules/mono/editor/csharp_project.cpp
-#, fuzzy
msgid "Auto Update Project"
-msgstr "Projekt bez nazwy"
+msgstr "Automatyczna aktualizacja projektu"
#: modules/mono/godotsharp_dirs.cpp
-#, fuzzy
msgid "Assembly Name"
-msgstr "Pokaż wszystko"
+msgstr "Nazwa zespołu"
#: modules/mono/godotsharp_dirs.cpp
#, fuzzy
@@ -17702,9 +17496,8 @@ msgid "Solution Directory"
msgstr "Wybierz katalog"
#: modules/mono/godotsharp_dirs.cpp
-#, fuzzy
msgid "C# Project Directory"
-msgstr "Wybierz katalog"
+msgstr "Katalog projektów C#"
#: modules/mono/mono_gd/gd_mono_utils.cpp
msgid "End of inner exception stack trace"
@@ -17775,42 +17568,39 @@ msgstr "Parsowanie Geometrii..."
#: modules/navigation/navigation_mesh_generator.cpp
msgid "Done!"
-msgstr "Skończone!"
+msgstr "Gotowe!"
#: modules/opensimplex/noise_texture.cpp
msgid "Seamless"
msgstr ""
#: modules/opensimplex/noise_texture.cpp
-#, fuzzy
msgid "As Normal Map"
-msgstr "Losowa skala:"
+msgstr "Jako normalna mapa"
#: modules/opensimplex/noise_texture.cpp
msgid "Bump Strength"
-msgstr ""
+msgstr "Siła uderzenia"
#: modules/opensimplex/noise_texture.cpp
msgid "Noise"
-msgstr ""
+msgstr "Szum"
#: modules/opensimplex/noise_texture.cpp
-#, fuzzy
msgid "Noise Offset"
-msgstr "Offset siatki:"
+msgstr "Redukcja szumów"
#: modules/opensimplex/open_simplex_noise.cpp
msgid "Octaves"
-msgstr ""
+msgstr "Oktawy"
#: modules/opensimplex/open_simplex_noise.cpp
msgid "Period"
-msgstr ""
+msgstr "Okres"
#: modules/opensimplex/open_simplex_noise.cpp
-#, fuzzy
msgid "Persistence"
-msgstr "Perspektywa"
+msgstr "Trwałość"
#: modules/opensimplex/open_simplex_noise.cpp
msgid "Lacunarity"
@@ -17821,14 +17611,12 @@ msgid "Subject"
msgstr ""
#: modules/regex/regex.cpp
-#, fuzzy
msgid "Names"
-msgstr "Nazwa"
+msgstr "Nazwy"
#: modules/regex/regex.cpp
-#, fuzzy
msgid "Strings"
-msgstr "Ustawienia:"
+msgstr "CiÄ…gi tekstowe"
#: modules/upnp/upnp.cpp
msgid "Discover Multicast If"
@@ -17901,7 +17689,9 @@ msgstr "Węzeł zwrócił niewłaściwą sekwencję wyjściową: "
#: modules/visual_script/visual_script.cpp
msgid "Found sequence bit but not the node in the stack, report bug!"
-msgstr "Znaleziono bit sekwencji, ale nie węzeł na stosie, zgłoś błąd!"
+msgstr ""
+"Nie znaleziono węzła w stosie, choć znaleziono ciąg bitów. Powiadom o "
+"błędzie!"
#: modules/visual_script/visual_script.cpp
#, fuzzy
@@ -18031,7 +17821,7 @@ msgstr "Wklej węzeł VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Remove VisualScript Nodes"
-msgstr "Usuwanie węzłów VisualScript"
+msgstr "Usuń węzły VisualScript"
#: modules/visual_script/visual_script_editor.cpp
msgid "Duplicate VisualScript Nodes"
@@ -18088,7 +17878,7 @@ msgstr ""
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Getter Property"
-msgstr "Dodaj właściwość Gettera"
+msgstr "Dodaj właściwość Getter"
#: modules/visual_script/visual_script_editor.cpp
msgid "Add Setter Property"
@@ -19165,14 +18955,12 @@ msgid "Code Signing"
msgstr "DMG podpisywania kodu"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"'apksigner' could not be found. Please check that the command is available "
"in the Android SDK build-tools directory. The resulting %s is unsigned."
msgstr ""
-"\"apksigner\" nie został znaleziony.\n"
-"Sprawdź, czy komenda jest dostępna w folderze narzędzi SDK Androida.\n"
-"Wynikowy %s jest niepodpisany."
+"\"apksigner\" nie został znaleziony. Sprawdź, czy komenda jest dostępna w "
+"folderze narzędzi SDK Androida. Wynikowy %s jest niepodpisany."
#: platform/android/export/export_plugin.cpp
msgid "Signing debug %s..."
@@ -19233,15 +19021,12 @@ msgstr ""
"informacja o wersji. Zainstaluj ponownie z menu \"Projekt\"."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Android build version mismatch: Template installed: %s, Godot version: %s. "
"Please reinstall Android build template from 'Project' menu."
msgstr ""
-"Niezgodna wersja buildu Androida:\n"
-" Zainstalowany szablon: %s\n"
-" Wersja Godota: %s\n"
-"Zainstaluj ponownie szablon z menu \"Projekt\"."
+"Niezgodna wersja buildu Androida: Zainstalowany szablon: %s Wersja Godota: "
+"%s. Zainstaluj ponownie szablon z menu \"Projekt\"."
#: platform/android/export/export_plugin.cpp
#, fuzzy
@@ -19264,13 +19049,12 @@ msgid "Building Android Project (gradle)"
msgstr "Budowanie projektu Androida (gradle)"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Building of Android project failed, check output for the error. "
"Alternatively visit docs.godotengine.org for Android build documentation."
msgstr ""
-"Budowanie projektu Androida się nie powiodło, sprawdź wyjście błędu.\n"
-"Alternatywnie, odwiedź docs.godotengine.org po dokumentację budowania dla "
+"Budowanie projektu Androida się nie powiodło, sprawdź dane wyjściowe błędu. "
+"Ewentualnie, odwiedź docs.godotengine.org po dokumentację budowania dla "
"Androida."
#: platform/android/export/export_plugin.cpp
@@ -19295,20 +19079,16 @@ msgid "Creating APK..."
msgstr "Tworzenie APK..."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Could not find template APK to export: \"%s\"."
-msgstr ""
-"Nie udało się znaleźć szablonu APK do eksportu:\n"
-"%s"
+msgstr "Nie udało się znaleźć szablonu APK do eksportu: \"%s\"."
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid ""
"Missing libraries in the export template for the selected architectures: %s. "
"Please build a template with all required libraries, or uncheck the missing "
"architectures in the export preset."
msgstr ""
-"BrakujÄ…ce biblioteki w szablonie eksportu dla wybranej architektury: %s.\n"
+"BrakujÄ…ce biblioteki w szablonie eksportu dla wybranej architektury: %s. "
"Zbuduj szablon ze wszystkimi wymaganymi bibliotekami lub odznacz brakujÄ…ce "
"architektury w profilu eksportu."
@@ -21873,8 +21653,8 @@ msgid ""
"A material to process the particles is not assigned, so no behavior is "
"imprinted."
msgstr ""
-"Nie przypisano materiału do przetwarzania cząsteczek, więc zmiany nie będą "
-"widoczne."
+"Materiał nie jest przypisany do cząsteczek, więc ich zachowanie będzie "
+"niewidoczne."
#: scene/2d/particles_2d.cpp
msgid ""
@@ -22041,9 +21821,8 @@ msgid "Safe Margin"
msgstr "Ustaw margines"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
-#, fuzzy
msgid "Sync To Physics"
-msgstr " (fizyczny)"
+msgstr "Synchronizuj z fizykÄ…"
#: scene/2d/physics_body_2d.cpp scene/3d/physics_body.cpp
#, fuzzy
@@ -23067,7 +22846,8 @@ msgstr ""
msgid ""
"Nothing is visible because meshes have not been assigned to draw passes."
msgstr ""
-"Nic nie jest widoczne, bo siatki nie zostały przypisane do kolejki rysowania."
+"Nic nie jest widoczne ponieważ siatki nie zostały przydzielone do przebiegów "
+"wyświetlających."
#: scene/3d/particles.cpp
msgid ""
@@ -26857,7 +26637,7 @@ msgstr "Debug kanału UV"
#: scene/resources/environment.cpp
msgid "Blur"
-msgstr ""
+msgstr "Rozmazanie"
#: scene/resources/environment.cpp
msgid "Edge Sharpness"
@@ -27983,9 +27763,8 @@ msgstr ""
#: servers/audio/effects/audio_effect_delay.cpp
#: servers/audio/effects/audio_effect_phaser.cpp
#: servers/audio/effects/audio_effect_reverb.cpp
-#, fuzzy
msgid "Feedback"
-msgstr "Oceń dokumentację"
+msgstr "Informacja zwrotna"
#: servers/audio/effects/audio_effect_delay.cpp
#, fuzzy
@@ -27994,7 +27773,7 @@ msgstr "Omiń"
#: servers/audio/effects/audio_effect_distortion.cpp
msgid "Pre Gain"
-msgstr ""
+msgstr "Wstępne wzmocnienie"
#: servers/audio/effects/audio_effect_distortion.cpp
msgid "Keep Hf Hz"
@@ -28010,17 +27789,16 @@ msgid "Post Gain"
msgstr "Po"
#: servers/audio/effects/audio_effect_filter.cpp
-#, fuzzy
msgid "Resonance"
-msgstr "Zasoby"
+msgstr "Rezonans"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Ceiling dB"
-msgstr ""
+msgstr "Sufit dB"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Threshold dB"
-msgstr ""
+msgstr "Wartość progowa dB"
#: servers/audio/effects/audio_effect_limiter.cpp
msgid "Soft Clip dB"
@@ -28462,13 +28240,12 @@ msgid "Legacy Stream"
msgstr ""
#: servers/visual_server.cpp
-#, fuzzy
msgid "Batching"
-msgstr "Wyszukiwanie..."
+msgstr "Tworzenie pakietów wsadowych"
#: servers/visual_server.cpp
msgid "Use Batching"
-msgstr ""
+msgstr "Użyj przetwarzania wsadowego"
#: servers/visual_server.cpp
#, fuzzy
@@ -28581,9 +28358,8 @@ msgid "Max Active Polygons"
msgstr "Przesuń Wielokąt"
#: servers/visual_server.cpp
-#, fuzzy
msgid "Shader Compilation Mode"
-msgstr "Sposób interpolacji"
+msgstr "Sposób kompilacji shader'ów"
#: servers/visual_server.cpp
msgid "Max Simultaneous Compiles"
diff --git a/editor/translations/pr.po b/editor/translations/pr.po
index 45bbc8daf0..9b150194df 100644
--- a/editor/translations/pr.po
+++ b/editor/translations/pr.po
@@ -11039,7 +11039,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/pt.po b/editor/translations/pt.po
index 85814ded34..0fcc083b42 100644
--- a/editor/translations/pt.po
+++ b/editor/translations/pt.po
@@ -13,7 +13,7 @@
# Rueben Stevens <supercell03@gmail.com>, 2017.
# SARDON <fabio3_Santos@hotmail.com>, 2017.
# Vinicius Gonçalves <viniciusgoncalves21@gmail.com>, 2017.
-# ssantos <ssantos@web.de>, 2018, 2019, 2020, 2021, 2022.
+# ssantos <ssantos@web.de>, 2018, 2019, 2020, 2021, 2022, 2023.
# Gonçalo Dinis Guerreiro João <goncalojoao205@gmail.com>, 2019.
# Manuela Silva <mmsrs@sky.com>, 2020.
# Murilo Gama <murilovsky2030@gmail.com>, 2020, 2022.
@@ -31,12 +31,13 @@
# Tuily <brizolla.tuily@gmail.com>, 2022.
# Thuany <thutymsoares@gmail.com>, 2022.
# Isaque Mendes <isaquemendes405@gmail.com>, 2022.
+# Alex Bruno Boiniak <aboiniak@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-11-19 08:35+0000\n"
+"PO-Revision-Date: 2023-01-11 19:51+0000\n"
"Last-Translator: ssantos <ssantos@web.de>\n"
"Language-Team: Portuguese <https://hosted.weblate.org/projects/godot-engine/"
"godot/pt/>\n"
@@ -45,7 +46,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -183,7 +184,7 @@ msgstr "Erro"
#: core/bind/core_bind.cpp
msgid "Error String"
-msgstr "Erro String"
+msgstr "Cadeia de caracteres de erro"
#: core/bind/core_bind.cpp
msgid "Error Line"
@@ -383,7 +384,7 @@ msgstr "Tamanho Máximo (KB)"
#: core/os/input.cpp
msgid "Mouse Mode"
-msgstr "Modo Mouse"
+msgstr "Modo do Rato"
#: core/os/input.cpp
msgid "Use Accumulated Input"
@@ -4332,7 +4333,7 @@ msgstr "Restaurar Cenas quando carregar"
#: editor/editor_node.cpp editor/editor_settings.cpp
msgid "Show Thumbnail On Hover"
-msgstr "Mostrar Miniatura ao Passar o Mouse Por Cima"
+msgstr "Mostrar Miniatura ao Passar o Rato Por Cima"
#: editor/editor_node.cpp editor/editor_settings.cpp
msgid "Inspector"
@@ -5479,7 +5480,7 @@ msgstr "Largura do Minimapa"
#: editor/editor_settings.cpp
msgid "Mouse Extra Buttons Navigate History"
-msgstr "Botões extra do Mouse para Navegar no Histórico"
+msgstr "Botões extra do Rato para Navegar no Histórico"
#: editor/editor_settings.cpp
msgid "Drag And Drop Selection"
@@ -5773,7 +5774,7 @@ msgstr "Emular Teclado Numérico"
#: editor/editor_settings.cpp
msgid "Emulate 3 Button Mouse"
-msgstr "Emular Mouse de 3 Botões"
+msgstr "Emular Rato de 3 Botões"
#: editor/editor_settings.cpp
msgid "Orbit Modifier"
@@ -5789,7 +5790,7 @@ msgstr "Modificador de Zoom"
#: editor/editor_settings.cpp editor/plugins/spatial_editor_plugin.cpp
msgid "Warped Mouse Panning"
-msgstr "Panorama do Mouse Distorcido"
+msgstr "Panorama do Rato Distorcido"
#: editor/editor_settings.cpp
msgid "Navigation Feel"
@@ -6037,7 +6038,7 @@ msgstr "Cor do Comentário"
#: editor/editor_settings.cpp
msgid "String Color"
-msgstr "Cor da String"
+msgstr "Cor da cadeia de caracteres"
#: editor/editor_settings.cpp platform/javascript/export/export.cpp
#: platform/uwp/export/export.cpp
@@ -6887,9 +6888,8 @@ msgstr "Filtro"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp
-#, fuzzy
msgid "Mipmaps"
-msgstr "Sinais"
+msgstr "Mipmaps"
#: editor/import/resource_importer_layered_texture.cpp
#: editor/import/resource_importer_texture.cpp
@@ -10925,7 +10925,7 @@ msgstr "Perspetiva Traseira"
msgid " [auto]"
msgstr " [auto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portais ativos]"
@@ -14176,17 +14176,15 @@ msgid "Invalid project path (changed anything?)."
msgstr "Caminho de projeto inválido (alguma alteração?)."
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
msgstr ""
-"Não consegui carregar o project.godot no caminho do projeto (erro %d). "
-"Poderá estar em falta ou corrompido."
+"Não pode carregar o projeto em '%s' (error %d). Pode estar sumido ou "
+"corrompido."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Couldn't save project at '%s' (error %d)."
-msgstr "Incapaz de abrir projeto em '%s'."
+msgstr "Incapaz de salvar projeto em '%s' (error %d)."
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
@@ -16187,7 +16185,7 @@ msgstr "Interface Gráfica"
#: main/main.cpp
msgid "Drop Mouse On GUI Input Disabled"
-msgstr "Desabilitar Soltar o Mouse na Entrada da Interface Gráfica"
+msgstr "Desabilitar Soltar o Rato na Entrada da Interface Gráfica"
#: main/main.cpp
msgid "stdout"
@@ -16305,15 +16303,15 @@ msgstr "Liberação Ãgil de Eventos"
#: main/main.cpp
msgid "Emulate Touch From Mouse"
-msgstr "Emular Toque do Mouse"
+msgstr "Emular Toque do Rato"
#: main/main.cpp
msgid "Emulate Mouse From Touch"
-msgstr "Emular o Mouse do Toque"
+msgstr "Emular o Rato do Toque"
#: main/main.cpp
msgid "Mouse Cursor"
-msgstr "Cursor do Mouse"
+msgstr "Cursor do Rato"
#: main/main.cpp
msgid "Custom Image"
@@ -16516,9 +16514,8 @@ msgid "Path Local"
msgstr "Caminho Local"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Continuous U"
-msgstr "Contínuo"
+msgstr "Caminho Contínuo U"
#: modules/csg/csg_shape.cpp
msgid "Path U Distance"
@@ -16578,9 +16575,8 @@ msgstr "Carregar Apenas uma Vez"
#: modules/gdnative/gdnative.cpp
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "Singleton"
-msgstr "Esqueleto"
+msgstr "Singleton"
#: modules/gdnative/gdnative.cpp
msgid "Symbol Prefix"
@@ -17426,7 +17422,7 @@ msgstr "Nomes"
#: modules/regex/regex.cpp
msgid "Strings"
-msgstr "Strings"
+msgstr "Cadeias"
#: modules/upnp/upnp.cpp
msgid "Discover Multicast If"
@@ -18436,9 +18432,8 @@ msgid "XR Mode"
msgstr "Modo XR"
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Hand Tracking"
-msgstr "Empacotamento"
+msgstr "Rastreamento das Mãos"
#: platform/android/export/export_plugin.cpp
msgid "Hand Tracking Frequency"
@@ -18923,9 +18918,8 @@ msgid "Code Sign Identity Debug"
msgstr "Depuração de Identidade de Sinal de Código"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Export Method Debug"
-msgstr "Exportar com Depuração"
+msgstr "Exportar Método Depuração"
#: platform/iphone/export/export.cpp
msgid "Provisioning Profile UUID Release"
@@ -19001,9 +18995,8 @@ msgid "Microphone Usage Description"
msgstr "Descrição do Uso do Microfone"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Photolibrary Usage Description"
-msgstr "Descrições da Propriedade"
+msgstr "Descrição de Uso da Fotobiblioteca"
#: platform/iphone/export/export.cpp
msgid "iPhone 120 X 120"
@@ -19050,14 +19043,12 @@ msgid "Image Scale Mode"
msgstr "Modo de Escalonamento de Imagem"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Custom Image @2x"
-msgstr "CustomNode"
+msgstr "Personalizar Imagem @2x"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Custom Image @3x"
-msgstr "CustomNode"
+msgstr "Personalizar Imagem @3x"
#: platform/iphone/export/export.cpp
msgid "Use Custom BG Color"
@@ -19154,9 +19145,8 @@ msgid "Export Icon"
msgstr "Exportar Ãcone"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Custom HTML Shell"
-msgstr "CustomNode"
+msgstr "HTML Shell Personalizado"
#: platform/javascript/export/export.cpp
msgid "Head Include"
@@ -23759,7 +23749,7 @@ msgstr "Anterior"
#: scene/gui/control.cpp
msgid "Mouse"
-msgstr "Mouse"
+msgstr "Rato"
#: scene/gui/control.cpp
msgid "Default Cursor Shape"
diff --git a/editor/translations/pt_BR.po b/editor/translations/pt_BR.po
index 8e574f992d..eb7b2ffde0 100644
--- a/editor/translations/pt_BR.po
+++ b/editor/translations/pt_BR.po
@@ -20,7 +20,7 @@
# MalcomRF <malcomkbk@gmail.com>, 2017.
# Marcus Correia <marknokalt@live.com>, 2017-2018.
# Michael Alexsander Silva Dias <michaelalexsander@protonmail.com>, 2017-2018.
-# Renato Rotenberg <renato.rotenberg@gmail.com>, 2017, 2019, 2021.
+# Renato Rotenberg <renato.rotenberg@gmail.com>, 2017, 2019, 2021, 2023.
# Rodolfo R Gomes <rodolforg@gmail.com>, 2017-2018, 2019.
# Tiago Almeida <thyagoeap@gmail.com>, 2017.
# Mauricio Luan Carneiro deSouza <newmailmlcs@gmail.com>, 2018.
@@ -156,13 +156,14 @@
# Murilo Gama <murilovsky2030@gmail.com>, 2022.
# Kauã Azevedo <Kazevic@pm.me>, 2022.
# Zer0-Zer0 <dankmemerson@tutanota.com>, 2022.
+# Levi Ferreira <leviferreiramorais@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: 2016-05-30\n"
-"PO-Revision-Date: 2022-12-10 02:13+0000\n"
-"Last-Translator: Julio Yagami <juliohenrique31501234@hotmail.com>\n"
+"PO-Revision-Date: 2023-01-14 00:01+0000\n"
+"Last-Translator: Levi Ferreira <leviferreiramorais@gmail.com>\n"
"Language-Team: Portuguese (Brazil) <https://hosted.weblate.org/projects/"
"godot-engine/godot/pt_BR/>\n"
"Language: pt_BR\n"
@@ -170,7 +171,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -11075,7 +11076,7 @@ msgstr "Perspectiva Traseira"
msgid " [auto]"
msgstr " [automático]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portais ativados]"
@@ -14331,17 +14332,15 @@ msgid "Invalid project path (changed anything?)."
msgstr "Caminho de projeto inválido (mudou alguma coisa?)."
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
msgstr ""
-"Não foi possível carregar project.godot no caminho do projeto (erro %d). Ele "
-"pode estar ausente ou corrompido."
+"Não foi possível carregar project.godot em '%s' (erro %d). Ele pode estar "
+"ausente ou corrompido."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Couldn't save project at '%s' (error %d)."
-msgstr "Não é possível abrir o projeto em '%s'."
+msgstr "Não foi possível salvar o projeto em '%s' (erro %d)."
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
@@ -16200,9 +16199,8 @@ msgid "Multithreaded Server"
msgstr "Servidor com Multi-Thread"
#: main/main.cpp
-#, fuzzy
msgid "RID Pool Prealloc"
-msgstr "Pre-alocação de Pool RID"
+msgstr "Pool de Prealocação de RID"
#: main/main.cpp
msgid "Debugger stdout"
@@ -16310,7 +16308,7 @@ msgstr "Modelo de Thread"
#: main/main.cpp
msgid "Thread Safe BVH"
-msgstr ""
+msgstr "Thread Segura de BVH"
#: main/main.cpp
msgid "Handheld"
@@ -16675,9 +16673,8 @@ msgid "Path Local"
msgstr "Caminho Local"
#: modules/csg/csg_shape.cpp
-#, fuzzy
msgid "Path Continuous U"
-msgstr "Caminho Contínuo"
+msgstr "Caminho Continuo U"
#: modules/csg/csg_shape.cpp
msgid "Path U Distance"
@@ -16943,11 +16940,11 @@ msgstr "Contagem Escassa"
#: modules/gltf/gltf_accessor.cpp
msgid "Sparse Indices Buffer View"
-msgstr ""
+msgstr "Visualização de Buffer dos Indices Esparsos"
#: modules/gltf/gltf_accessor.cpp
msgid "Sparse Indices Byte Offset"
-msgstr ""
+msgstr "Deslocação de Byte dos Ãndices Esparsos"
#: modules/gltf/gltf_accessor.cpp
msgid "Sparse Indices Component Type"
@@ -16955,11 +16952,11 @@ msgstr "Tipo de Componente de Ãndices Esparsos"
#: modules/gltf/gltf_accessor.cpp
msgid "Sparse Values Buffer View"
-msgstr ""
+msgstr "Visualização de Buffer dos Valores Esparsos"
#: modules/gltf/gltf_accessor.cpp
msgid "Sparse Values Byte Offset"
-msgstr ""
+msgstr "Deslocação de Byte dos Valores Esparsos"
#: modules/gltf/gltf_buffer_view.cpp
msgid "Buffer"
@@ -16971,7 +16968,7 @@ msgstr "Largura do byte"
#: modules/gltf/gltf_buffer_view.cpp
msgid "Byte Stride"
-msgstr ""
+msgstr "Separação dos Bytes"
#: modules/gltf/gltf_buffer_view.cpp
msgid "Indices"
@@ -17031,11 +17028,11 @@ msgstr "Pai"
#: modules/gltf/gltf_node.cpp
msgid "Xform"
-msgstr ""
+msgstr "Xform"
#: modules/gltf/gltf_node.cpp scene/3d/mesh_instance.cpp
msgid "Skin"
-msgstr ""
+msgstr "Pele"
#: modules/gltf/gltf_node.cpp scene/3d/spatial.cpp
msgid "Translation"
@@ -17107,11 +17104,11 @@ msgstr "Fator Especular"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Spec Gloss Img"
-msgstr ""
+msgstr "Imagem Especular Lustrosa"
#: modules/gltf/gltf_state.cpp
msgid "Json"
-msgstr ""
+msgstr "Json"
#: modules/gltf/gltf_state.cpp
msgid "Major Version"
@@ -17127,7 +17124,7 @@ msgstr "Dados do GLB"
#: modules/gltf/gltf_state.cpp
msgid "Use Named Skin Binds"
-msgstr ""
+msgstr "Usar Associações de Pele com nome"
#: modules/gltf/gltf_state.cpp
msgid "Buffer Views"
@@ -17432,15 +17429,15 @@ msgstr "Exibir para as Lentes"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "Oversample"
-msgstr ""
+msgstr "Amostragem em excesso"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "K1"
-msgstr ""
+msgstr "K1"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "K2"
-msgstr ""
+msgstr "K2"
#: modules/mono/csharp_script.cpp
msgid "Class name can't be a reserved keyword"
@@ -18019,7 +18016,7 @@ msgstr "Iterador"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "for (elem) in (input):"
-msgstr ""
+msgstr "for (elem) in (input):"
#: modules/visual_script/visual_script_flow_control.cpp
msgid "Input type not iterable:"
@@ -18191,7 +18188,7 @@ msgstr "Argumentos inválidos:"
#: modules/visual_script/visual_script_nodes.cpp
msgid "a if cond, else b"
-msgstr ""
+msgstr "a se cond, se não b"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Var Name"
@@ -18247,11 +18244,11 @@ msgstr "Obter Ãrvore de Cenas"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Get Self"
-msgstr "Obter Sí Mesmo"
+msgstr "Obter Si Mesmo"
#: modules/visual_script/visual_script_nodes.cpp
msgid "CustomNode"
-msgstr ""
+msgstr "Nó Personalizado"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Custom node has no _step() method, can't process graph."
@@ -18269,7 +18266,7 @@ msgstr ""
#: modules/visual_script/visual_script_nodes.cpp
msgid "SubCall"
-msgstr ""
+msgstr "Sub-Chamada"
#: modules/visual_script/visual_script_nodes.cpp scene/gui/graph_node.cpp
msgid "Title"
@@ -18301,11 +18298,11 @@ msgstr "Buscar VisualScript"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "Yield"
-msgstr ""
+msgstr "Aguardar Retorno"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "Wait"
-msgstr ""
+msgstr "Esperar"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "Next Frame"
@@ -18325,7 +18322,7 @@ msgstr "Tempo de Espera"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "WaitSignal"
-msgstr ""
+msgstr "EsperarSinal"
#: modules/visual_script/visual_script_yield_nodes.cpp
msgid "WaitNodeSignal"
@@ -18341,7 +18338,7 @@ msgstr "Modo de Escrita"
#: modules/webrtc/webrtc_data_channel.h
msgid "WebRTC"
-msgstr ""
+msgstr "WebRTC"
#: modules/webrtc/webrtc_data_channel.h
msgid "Max Channel In Buffer (KB)"
@@ -18381,7 +18378,7 @@ msgstr "Servidor WebSocket"
#: modules/websocket/websocket_server.cpp
msgid "Bind IP"
-msgstr ""
+msgstr "Atrelar IP"
#: modules/websocket/websocket_server.cpp
msgid "Private Key"
@@ -18441,11 +18438,11 @@ msgstr "Depurar Keystore"
#: platform/android/export/export.cpp
msgid "Debug Keystore User"
-msgstr ""
+msgstr "Usuário da Keystore de Depuração"
#: platform/android/export/export.cpp
msgid "Debug Keystore Pass"
-msgstr ""
+msgstr "Senha da Keystore de Depuração"
#: platform/android/export/export.cpp
msgid "Force System User"
@@ -19033,43 +19030,43 @@ msgstr "Telas de Inicialização de Paisagem"
#: platform/iphone/export/export.cpp
msgid "iPhone 2436 X 1125"
-msgstr "IPhone 2436 X 1125"
+msgstr "iPhone 2436 X 1125"
#: platform/iphone/export/export.cpp
msgid "iPhone 2208 X 1242"
-msgstr ""
+msgstr "iPhone 2208 X 1242"
#: platform/iphone/export/export.cpp
msgid "iPad 1024 X 768"
-msgstr ""
+msgstr "iPad 1024 X 768"
#: platform/iphone/export/export.cpp
msgid "iPad 2048 X 1536"
-msgstr ""
+msgstr "iPad 2048 X 1536"
#: platform/iphone/export/export.cpp
msgid "Portrait Launch Screens"
-msgstr ""
+msgstr "Tela de Apresentação em Retrato"
#: platform/iphone/export/export.cpp
msgid "iPhone 640 X 960"
-msgstr ""
+msgstr "iPhone 640 X 960"
#: platform/iphone/export/export.cpp
msgid "iPhone 640 X 1136"
-msgstr ""
+msgstr "iPhone 640 X 1136"
#: platform/iphone/export/export.cpp
msgid "iPhone 750 X 1334"
-msgstr ""
+msgstr "iPhone 750 X 1334"
#: platform/iphone/export/export.cpp
msgid "iPhone 1125 X 2436"
-msgstr ""
+msgstr "iPhone 1125 X 2436"
#: platform/iphone/export/export.cpp
msgid "iPad 768 X 1024"
-msgstr ""
+msgstr "iPad 768 X 1024"
#: platform/iphone/export/export.cpp
msgid "iPad 1536 X 2048"
diff --git a/editor/translations/ro.po b/editor/translations/ro.po
index 906d6aee71..9e2d8b5c96 100644
--- a/editor/translations/ro.po
+++ b/editor/translations/ro.po
@@ -20,13 +20,15 @@
# Psynt <nichita@cadvegra.com>, 2022.
# Ilie Adrian Avramescu <himark1977@protonmail.com>, 2022.
# Andres Ene <grassiscomplex420@gmail.com>, 2022.
+# Claudiu Ceia <claudiu.ceia@gmail.com>, 2022.
+# Random Videos <istudordanadenis@gmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-11-22 20:37+0000\n"
-"Last-Translator: Andres Ene <grassiscomplex420@gmail.com>\n"
+"PO-Revision-Date: 2023-01-13 03:04+0000\n"
+"Last-Translator: Random Videos <istudordanadenis@gmail.com>\n"
"Language-Team: Romanian <https://hosted.weblate.org/projects/godot-engine/"
"godot/ro/>\n"
"Language: ro\n"
@@ -35,7 +37,7 @@ 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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -66,9 +68,8 @@ msgid "Delta Smoothing"
msgstr "Netezirea Delta"
#: core/bind/core_bind.cpp
-#, fuzzy
msgid "Low Processor Usage Mode"
-msgstr "Mod Mutare"
+msgstr "Mod utilizare redusă a procesorului"
#: core/bind/core_bind.cpp
msgid "Low Processor Usage Mode Sleep (µsec)"
@@ -225,18 +226,16 @@ msgstr "Date"
#: modules/gdscript/language_server/gdscript_language_server.cpp
#: modules/webrtc/webrtc_data_channel.h modules/websocket/websocket_macros.h
#: scene/gui/file_dialog.cpp
-#, fuzzy
msgid "Network"
-msgstr "Analizator Network"
+msgstr "Rețea"
#: core/io/file_access_network.cpp
-#, fuzzy
msgid "Remote FS"
-msgstr "Ștergeți"
+msgstr "Sistem de fișiere (FS) la distanță"
#: core/io/file_access_network.cpp
msgid "Page Size"
-msgstr "Marime Pagina"
+msgstr "Mărime Pagina"
#: core/io/file_access_network.cpp
msgid "Page Read Ahead"
@@ -248,29 +247,27 @@ msgstr "Mod de blocare Activat"
#: core/io/http_client.cpp
msgid "Connection"
-msgstr "Conexie"
+msgstr "Conexiune"
#: core/io/http_client.cpp
msgid "Read Chunk Size"
-msgstr ""
+msgstr "Dimensiunea fragmentului de citire"
#: core/io/marshalls.cpp
msgid "Object ID"
msgstr "ID Obiect"
#: core/io/multiplayer_api.cpp core/io/packet_peer.cpp
-#, fuzzy
msgid "Allow Object Decoding"
-msgstr "Activează Onion Skinning"
+msgstr "Permite Decodarea Obiectelor"
#: core/io/multiplayer_api.cpp scene/main/scene_tree.cpp
msgid "Refuse New Network Connections"
msgstr "Refuza Conexiuni noi pe retea"
#: core/io/multiplayer_api.cpp scene/main/scene_tree.cpp
-#, fuzzy
msgid "Network Peer"
-msgstr "Analizator Network"
+msgstr "Peer de Rețea"
#: core/io/multiplayer_api.cpp scene/animation/animation_player.cpp
msgid "Root Node"
@@ -286,15 +283,15 @@ msgstr "Mod Transfer"
#: core/io/packet_peer.cpp
msgid "Encode Buffer Max Size"
-msgstr ""
+msgstr "Dimensiunea Maximă a Bufferului de Encodare"
#: core/io/packet_peer.cpp
msgid "Input Buffer Max Size"
-msgstr ""
+msgstr "Dimensiunea Maximă a Bufferului de Intrare"
#: core/io/packet_peer.cpp
msgid "Output Buffer Max Size"
-msgstr ""
+msgstr "Dimensiunea Maximă a Bufferului de Ieșire"
#: core/io/packet_peer.cpp
msgid "Stream Peer"
@@ -302,11 +299,11 @@ msgstr "Fluxul Peer"
#: core/io/stream_peer.cpp
msgid "Big Endian"
-msgstr ""
+msgstr "Big Endian"
#: core/io/stream_peer.cpp
msgid "Data Array"
-msgstr ""
+msgstr "Matrice Date"
#: core/io/stream_peer_ssl.cpp
msgid "Blocking Handshake"
@@ -367,9 +364,8 @@ msgid "Seed"
msgstr "Semințe"
#: core/math/random_number_generator.cpp
-#, fuzzy
msgid "State"
-msgstr "Mod Rotație"
+msgstr "State"
#: core/message_queue.cpp
msgid "Message Queue"
@@ -377,17 +373,15 @@ msgstr "Coada de mesaje"
#: core/message_queue.cpp
msgid "Max Size (KB)"
-msgstr ""
+msgstr "Dimensiune maximă (KB)"
#: core/os/input.cpp
-#, fuzzy
msgid "Mouse Mode"
-msgstr "Mod Mutare"
+msgstr "Mod Maus"
#: core/os/input.cpp
-#, fuzzy
msgid "Use Accumulated Input"
-msgstr "Șterge Intrare(Input)"
+msgstr "Utilizează Intrarea (Input) Acumulată"
#: core/os/input_event.cpp editor/project_settings_editor.cpp
#: servers/audio_server.cpp
@@ -411,9 +405,8 @@ msgid "Meta"
msgstr "Meta"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Command"
-msgstr "Comunitate"
+msgstr "Comandă"
#: core/os/input_event.cpp
#, fuzzy
@@ -444,9 +437,8 @@ msgid "Echo"
msgstr "Ecou"
#: core/os/input_event.cpp scene/gui/base_button.cpp
-#, fuzzy
msgid "Button Mask"
-msgstr "Adaugă în Grup"
+msgstr "Mască Buton"
#: core/os/input_event.cpp scene/2d/node_2d.cpp scene/gui/control.cpp
msgid "Global Position"
@@ -457,9 +449,8 @@ msgid "Factor"
msgstr "Factor"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Button Index"
-msgstr "Mod ÃŽn Jur"
+msgstr "Indice Buton"
#: core/os/input_event.cpp
msgid "Doubleclick"
@@ -498,9 +489,8 @@ msgid "Axis Value"
msgstr "Valoarea Axei"
#: core/os/input_event.cpp modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "Index"
-msgstr "Mod ÃŽn Jur"
+msgstr "Indice"
#: core/os/input_event.cpp editor/project_settings_editor.cpp
#: modules/visual_script/visual_script_nodes.cpp
@@ -518,29 +508,26 @@ msgid "Delta"
msgstr "Delta"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Channel"
-msgstr "Schimbați"
+msgstr "Canal"
#: core/os/input_event.cpp main/main.cpp
-#, fuzzy
msgid "Message"
-msgstr "Sincronizează Modificările Scriptului"
+msgstr "Mesaj"
#: core/os/input_event.cpp
-#, fuzzy
msgid "Pitch"
-msgstr "Dimensiune:"
+msgstr "Înclinație"
#: core/os/input_event.cpp scene/2d/cpu_particles_2d.cpp
#: scene/2d/physics_body_2d.cpp scene/3d/cpu_particles.cpp
#: scene/3d/physics_body.cpp scene/resources/particles_material.cpp
msgid "Velocity"
-msgstr ""
+msgstr "Viteză (velocity)"
#: core/os/input_event.cpp
msgid "Instrument"
-msgstr ""
+msgstr "Instrument"
#: core/os/input_event.cpp
msgid "Controller Number"
@@ -553,19 +540,16 @@ msgstr "Valoarea controlerului"
#: core/project_settings.cpp editor/editor_node.cpp main/main.cpp
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Application"
-msgstr "Acțiune"
+msgstr "Aplicație"
#: core/project_settings.cpp main/main.cpp
-#, fuzzy
msgid "Config"
-msgstr "Configurare Snap"
+msgstr "Configurare"
#: core/project_settings.cpp
-#, fuzzy
msgid "Project Settings Override"
-msgstr "Setări proiect..."
+msgstr "Suprascriere setări proiect"
#: core/project_settings.cpp core/resource.cpp
#: editor/animation_track_editor.cpp editor/editor_autoload_settings.cpp
@@ -596,29 +580,27 @@ msgstr "Execută"
#: core/project_settings.cpp editor/editor_node.cpp
#: editor/run_settings_dialog.cpp main/main.cpp
msgid "Main Scene"
-msgstr ""
+msgstr "Scena Principală"
#: core/project_settings.cpp
-#, fuzzy
msgid "Disable stdout"
-msgstr "Dezactivat"
+msgstr "Dezactivează stdout"
#: core/project_settings.cpp
-#, fuzzy
msgid "Disable stderr"
-msgstr "Dezactivat"
+msgstr "Dezactivează stderr"
#: core/project_settings.cpp
msgid "Use Hidden Project Data Directory"
-msgstr ""
+msgstr "Utilizează directorul de date de proiect ascuns"
#: core/project_settings.cpp
msgid "Use Custom User Dir"
-msgstr ""
+msgstr "Utilizează Director de Utilizator Personalizat"
#: core/project_settings.cpp
msgid "Custom User Dir Name"
-msgstr ""
+msgstr "Nume de Director de Utilizator Personalizat"
#: core/project_settings.cpp main/main.cpp
#: platform/javascript/export/export.cpp platform/osx/export/export.cpp
@@ -631,7 +613,7 @@ msgstr "Afișează Tot"
#: modules/opensimplex/noise_texture.cpp scene/2d/line_2d.cpp
#: scene/3d/label_3d.cpp scene/gui/text_edit.cpp scene/resources/texture.cpp
msgid "Width"
-msgstr ""
+msgstr "Lățime"
#: core/project_settings.cpp main/main.cpp modules/csg/csg_shape.cpp
#: modules/gltf/gltf_node.cpp modules/opensimplex/noise_texture.cpp
@@ -640,21 +622,19 @@ msgstr ""
#: scene/resources/font.cpp scene/resources/navigation_mesh.cpp
#: scene/resources/primitive_meshes.cpp scene/resources/texture.cpp
msgid "Height"
-msgstr ""
+msgstr "Înălțime"
#: core/project_settings.cpp
msgid "Always On Top"
-msgstr ""
+msgstr "Mereu Deasupra"
#: core/project_settings.cpp
-#, fuzzy
msgid "Test Width"
-msgstr "Stânga liniară"
+msgstr "Lățime de Test"
#: core/project_settings.cpp
-#, fuzzy
msgid "Test Height"
-msgstr "Se Testează"
+msgstr "Înălțime de Test"
#: core/project_settings.cpp editor/animation_track_editor.cpp
#: editor/editor_audio_buses.cpp main/main.cpp servers/audio_server.cpp
@@ -662,9 +642,8 @@ msgid "Audio"
msgstr "Sunet"
#: core/project_settings.cpp
-#, fuzzy
msgid "Default Bus Layout"
-msgstr "Încarcă Schema de Pistă Audio implicită."
+msgstr "Schema de Pistă Audio Implicită"
#: core/project_settings.cpp editor/editor_export.cpp
#: editor/editor_file_system.cpp editor/editor_node.cpp
@@ -687,73 +666,64 @@ msgstr "Căutare în extensii de fișiere"
#: core/project_settings.cpp
msgid "Script Templates Search Path"
-msgstr ""
+msgstr "Cale de Căutare pentru Șabloane de Scripturi"
#: core/project_settings.cpp
-#, fuzzy
msgid "Version Control Autoload On Startup"
-msgstr "Control versiune"
+msgstr "Încărcare Automată de Control al Versiunii la Pornire"
#: core/project_settings.cpp
-#, fuzzy
msgid "Version Control Plugin Name"
-msgstr "Control versiune"
+msgstr "Numele Pluginului de Control al Versiunii"
#: core/project_settings.cpp scene/2d/collision_object_2d.cpp
#: scene/3d/collision_object.cpp scene/gui/control.cpp
-#, fuzzy
msgid "Input"
-msgstr "Adaugă Intrare(Input)"
+msgstr "Intrare (Input)"
#: core/project_settings.cpp
msgid "UI Accept"
-msgstr ""
+msgstr "Acceptare (UI)"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Select"
-msgstr "Selectează"
+msgstr "Selectează (UI)"
#: core/project_settings.cpp
msgid "UI Cancel"
-msgstr "Anulare interfață utilizator"
+msgstr "Anulare (UI)"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Focus Next"
-msgstr "Cale focalizare"
+msgstr "Focalizează Urmatorul (UI)"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Focus Prev"
-msgstr "Cale focalizare"
+msgstr "Focalizează Anteriorul (UI)"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Left"
-msgstr "Mod Rotație"
+msgstr "Stânga (UI)"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Right"
-msgstr "Rotație poligon"
+msgstr "Dreapta (UI)"
#: core/project_settings.cpp
msgid "UI Up"
-msgstr ""
+msgstr "Sus (UI)"
#: core/project_settings.cpp
-#, fuzzy
msgid "UI Down"
-msgstr "Descarcă"
+msgstr "JUos (UI)"
#: core/project_settings.cpp
msgid "UI Page Up"
-msgstr "Pagina UI în sus"
+msgstr "Pagina Ssus (UI)"
#: core/project_settings.cpp
msgid "UI Page Down"
-msgstr ""
+msgstr "Pagină Jos (UI)"
#: core/project_settings.cpp
msgid "UI Home"
@@ -783,7 +753,7 @@ msgstr "Cadru Fizic %"
#: scene/3d/physics_body.cpp scene/resources/world.cpp
#: servers/physics/space_sw.cpp servers/physics_server.cpp
msgid "3D"
-msgstr ""
+msgstr "3D"
#: core/project_settings.cpp
#, fuzzy
@@ -800,7 +770,7 @@ msgstr "Creează un Frate de Coliziune Trimesh"
#: scene/main/viewport.cpp servers/visual/visual_server_scene.cpp
#: servers/visual_server.cpp
msgid "Rendering"
-msgstr ""
+msgstr "Randare"
#: core/project_settings.cpp drivers/gles2/rasterizer_storage_gles2.cpp
#: drivers/gles3/rasterizer_scene_gles3.cpp
@@ -850,17 +820,16 @@ msgid "Max Functions"
msgstr "Faceți Funcția"
#: core/project_settings.cpp scene/3d/vehicle_body.cpp
-#, fuzzy
msgid "Compression"
-msgstr "Setare expresie"
+msgstr "Compresie"
#: core/project_settings.cpp
msgid "Formats"
-msgstr ""
+msgstr "Formate"
#: core/project_settings.cpp
msgid "Zstd"
-msgstr ""
+msgstr "Zstd"
#: core/project_settings.cpp
msgid "Long Distance Matching"
@@ -905,11 +874,11 @@ msgstr "Pachet Peer Stream"
#: core/register_core_types.cpp
msgid "Max Buffer (Power of 2)"
-msgstr ""
+msgstr "Buffer Maxim (Putere de-a lui 2)"
#: core/register_core_types.cpp editor/editor_settings.cpp main/main.cpp
msgid "SSL"
-msgstr ""
+msgstr "SSL"
#: core/register_core_types.cpp main/main.cpp
#, fuzzy
@@ -941,7 +910,7 @@ msgstr "Resursă"
#: core/translation.cpp editor/project_settings_editor.cpp
msgid "Locale"
-msgstr ""
+msgstr "Local"
#: core/translation.cpp
#, fuzzy
@@ -986,17 +955,17 @@ msgstr "EiB"
#: drivers/gles3/rasterizer_scene_gles3.cpp
#: drivers/gles3/rasterizer_storage_gles3.cpp modules/gltf/gltf_state.cpp
msgid "Buffers"
-msgstr ""
+msgstr "Buffere"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
msgid "Canvas Polygon Buffer Size (KB)"
-msgstr ""
+msgstr "Dimensiune Buffer Poligon de Canvas (KB)"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp
msgid "Canvas Polygon Index Buffer Size (KB)"
-msgstr ""
+msgstr "Dimensiune Indice Buffer Poligon de Canvas (KB)"
#: drivers/gles2/rasterizer_canvas_base_gles2.cpp
#: drivers/gles3/rasterizer_canvas_base_gles3.cpp editor/editor_settings.cpp
@@ -1040,11 +1009,11 @@ msgstr "Utilizarea eșantionării bicubice"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Renderable Elements"
-msgstr ""
+msgstr "Numărul Maxim de Elemente Care se Pot Randa"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Renderable Lights"
-msgstr ""
+msgstr "Numărul Maxim de Lumini Care se Pot Randa"
#: drivers/gles3/rasterizer_scene_gles3.cpp
#, fuzzy
@@ -1053,7 +1022,7 @@ msgstr "Centrează Selecția"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Max Lights Per Object"
-msgstr ""
+msgstr "Numărul Maxim de Lumini per Obiect"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Subsurface Scattering"
@@ -1087,7 +1056,7 @@ msgstr ""
#: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp
msgid "High Quality"
-msgstr ""
+msgstr "Calitate Înaltă"
#: drivers/gles3/rasterizer_storage_gles3.cpp
msgid "Blend Shape Max Buffer Size (KB)"
@@ -1190,7 +1159,7 @@ msgstr "Rotație"
#: editor/animation_track_editor.cpp editor/script_editor_debugger.cpp
#: modules/visual_script/visual_script_nodes.cpp scene/gui/range.cpp
msgid "Value"
-msgstr ""
+msgstr "Valoare"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -1200,14 +1169,14 @@ msgstr "Cantitate:"
#: editor/animation_track_editor.cpp main/main.cpp
#: modules/mono/mono_gd/gd_mono.cpp
msgid "Args"
-msgstr ""
+msgstr "Argumente"
#: editor/animation_track_editor.cpp editor/editor_settings.cpp
#: editor/script_editor_debugger.cpp modules/gltf/gltf_accessor.cpp
#: modules/gltf/gltf_light.cpp modules/visual_script/visual_script_nodes.cpp
#: scene/3d/physics_body.cpp scene/resources/visual_shader_nodes.cpp
msgid "Type"
-msgstr ""
+msgstr "Tip"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -1380,7 +1349,7 @@ msgstr "Dimensiune:"
#: editor/scene_tree_editor.cpp editor/script_editor_debugger.cpp
#: modules/visual_script/visual_script_editor.cpp
msgid "Type:"
-msgstr ""
+msgstr "Tip:"
#: editor/animation_track_editor.cpp
#, fuzzy
@@ -1646,7 +1615,7 @@ msgstr "Anim Mutați Cheie"
#: servers/camera/camera_feed.cpp servers/physics_2d_server.cpp
#: servers/physics_server.cpp
msgid "Transform"
-msgstr ""
+msgstr "Transformă"
#: editor/animation_track_editor.cpp editor/editor_help.cpp
msgid "Methods"
@@ -2667,7 +2636,7 @@ msgstr "Nume nevalid."
#: editor/editor_autoload_settings.cpp
msgid "Cannot begin with a digit."
-msgstr ""
+msgstr "Nu poate începe cu o cifră"
#: editor/editor_autoload_settings.cpp
msgid "Valid characters:"
@@ -2949,7 +2918,7 @@ msgstr "Culoare uniformă."
#: editor/editor_export.cpp
msgid "64 Bits"
-msgstr ""
+msgstr "64 de biți"
#: editor/editor_export.cpp
msgid "Embed PCK"
@@ -3207,6 +3176,8 @@ msgstr "Opțiunii Extra:"
#: editor/editor_feature_profile.cpp
msgid "Create or import a profile to edit available classes and properties."
msgstr ""
+"Creează sau importă un profil pentru a edita clasele si proprietățile "
+"disponibile"
#: editor/editor_feature_profile.cpp
msgid "New profile name:"
@@ -3347,7 +3318,7 @@ msgstr "Comutați Fișiere Ascunse"
#: editor/editor_file_dialog.cpp
msgid "Disable Overwrite Warning"
-msgstr ""
+msgstr "Opreste suprascrierea avertizărilor"
#: editor/editor_file_dialog.cpp
msgid "Go Back"
@@ -3496,7 +3467,7 @@ msgstr "Proprietățile Temei"
#: scene/2d/cpu_particles_2d.cpp scene/3d/cpu_particles.cpp
#: scene/resources/gradient.cpp
msgid "Colors"
-msgstr ""
+msgstr "Culori"
#: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Constants"
@@ -3504,16 +3475,16 @@ msgstr "Constante"
#: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp
msgid "Fonts"
-msgstr ""
+msgstr "Fonturi"
#: editor/editor_help.cpp editor/plugins/theme_editor_plugin.cpp
#: platform/iphone/export/export.cpp
msgid "Icons"
-msgstr ""
+msgstr "Icoană"
#: editor/editor_help.cpp
msgid "Styles"
-msgstr ""
+msgstr "Stiluri"
#: editor/editor_help.cpp
msgid "Enumerations"
@@ -3645,7 +3616,7 @@ msgstr "Proprietate:"
#: editor/editor_inspector.cpp editor/editor_spin_slider.cpp
msgid "Label"
-msgstr ""
+msgstr "Etichetă"
#: editor/editor_inspector.cpp editor/editor_spin_slider.cpp
#: scene/resources/default_theme/default_theme.cpp
@@ -4213,14 +4184,14 @@ msgid "Unable to load addon script from path: '%s'."
msgstr "Nu a putut fi încărcat scriptul add-on din calea: '%s'."
#: editor/editor_node.cpp
-#, fuzzy
msgid ""
"Unable to load addon script from path: '%s'. This might be due to a code "
"error in that script.\n"
"Disabling the addon at '%s' to prevent further errors."
msgstr ""
"Imposibil de încărcat scriptul addon din cale: '%s' Se pare că există o "
-"eroare în cod, verificați sintaxa."
+"eroare în cod, verificați sintaxa.\n"
+"Dezactivez addon-ul de la '%s' pentru a preveni erori ulterioare."
#: editor/editor_node.cpp
msgid ""
@@ -7317,9 +7288,8 @@ msgid "Generating Lightmaps"
msgstr "Se Genereaza Lightmaps"
#: editor/import/resource_importer_scene.cpp
-#, fuzzy
msgid "Generating for Mesh:"
-msgstr "Se Generează pentru Mesh: "
+msgstr "Se Generează pentru Mesh:"
#: editor/import/resource_importer_scene.cpp
msgid "Running Custom Script..."
@@ -8967,36 +8937,32 @@ msgid "Center Top"
msgstr "Centrează Selecția"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Center Right"
-msgstr "Rotație poligon"
+msgstr "Centrează Dreapta"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Center Bottom"
-msgstr "Centrează Selecția"
+msgstr "Centrează Jos"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center"
-msgstr ""
+msgstr "Centrează"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Left Wide"
-msgstr "Stânga liniară"
+msgstr "Stânga Lat"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Top Wide"
-msgstr ""
+msgstr "Sus Lat"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Right Wide"
-msgstr "Dreapta liniară"
+msgstr "Dreapta Lat"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Bottom Wide"
-msgstr ""
+msgstr "Jos Lat"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "VCenter Wide"
@@ -9032,6 +8998,9 @@ msgid ""
"Project Camera Override\n"
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
+"Suprascrierea Camerei de Proiect\n"
+"Suprascrie camera proiectului care rulează cu camera de vizualizare a "
+"editorului."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9040,48 +9009,45 @@ msgid ""
"No project instance running. Run the project from the editor to use this "
"feature."
msgstr ""
+"Suprascrierea Camerei de Proiect\n"
+"Nicio instanță de proiect nu rulează. Rulați proiectul din editor pentru a "
+"utiliza această caracteristică."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Lock Selected"
-msgstr "Selectează"
+msgstr "Blochează Selecția"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unlock Selected"
-msgstr ""
+msgstr "Deblochează Selecția"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Group Selected"
-msgstr "Elminați Selecția"
+msgstr "Grupează Selecția"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Ungroup Selected"
-msgstr "Elminați Selecția"
+msgstr "Degrupați selecția"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Paste Pose"
msgstr "Lipește Postura"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Clear Guides"
-msgstr "Curăță Postura"
+msgstr "Elimină Ghidurile"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Create Custom Bone(s) from Node(s)"
-msgstr "Creează Puncte de Emisie Din Mesh"
+msgstr "Crează Oase personalizate din Noduri"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Clear Bones"
-msgstr "Curăță Postura"
+msgstr "Elimină Oase"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Make IK Chain"
@@ -9112,36 +9078,31 @@ msgstr "Selectare mod"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Drag: Rotate selected node around pivot."
-msgstr "Ștergeți pista selectată."
+msgstr "Trage: Rotește nodul selectat în jurul pivotului."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Move selected node."
-msgstr "Alt+Trage: Mutare"
+msgstr "Alt+Trage: Mută nodul selectat."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Alt+Drag: Scale selected node."
-msgstr "Alt+Trage: Mutare"
+msgstr "Alt+Trage: Scalează nodul selectat."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "V: Set selected node's pivot position."
-msgstr "Ștergeți pista selectată."
+msgstr "V: Setează poziția pivotului nodului selectat."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Alt+RMB: Show list of all nodes at position clicked, including locked."
msgstr ""
-"Arată o listă a tuturor obiectelor la poziția clickului\n"
-"(similar cu Alt+RMB în modul selectare)."
+"Alt+RMB: Arată o listă a tuturor nodurilor la poziția clickului, inclusiv "
+"cele blocate."
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "RMB: Add node at position clicked."
-msgstr ""
+msgstr "RMB: Adaugă nod la poziția clickului."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9155,13 +9116,12 @@ msgstr "Mod Rotație"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Scale Mode"
-msgstr "Mod Redimensionare (R)"
+msgstr "Mod Redimensionare"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Shift: Scale proportionally."
-msgstr ""
+msgstr "Shift: Redimensionare proporțională."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9189,21 +9149,18 @@ msgid "Toggle smart snapping."
msgstr "Comutați fixarea inteligentă."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Smart Snap"
-msgstr "Utilizează Snap"
+msgstr "Utilizează Snap Inteligent"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Toggle grid snapping."
msgstr "Comutare grilă fixare."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Grid Snap"
-msgstr "Snap Grilă"
+msgstr "Utilizează Snap Grilă"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Snapping Options"
msgstr "Opțiuni Snapping"
@@ -9212,9 +9169,8 @@ msgid "Use Rotation Snap"
msgstr "Folosește Rotația Snap"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Use Scale Snap"
-msgstr "Utilizează Snap"
+msgstr "Utilizează Snap Redimensionare"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Snap Relative"
@@ -9225,9 +9181,8 @@ msgid "Use Pixel Snap"
msgstr "Utilizează Pixel Snap"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Smart Snapping"
-msgstr "Snapping inteligent"
+msgstr "Snapping Inteligent"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9235,34 +9190,28 @@ msgid "Configure Snap..."
msgstr "Configurare Snap..."
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Snap to Parent"
-msgstr "Snap către părinte"
+msgstr "Snap către Părinte"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Snap to Node Anchor"
-msgstr "Snap către ancora nodului"
+msgstr "Snap către Ancora Nodului"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Snap to Node Sides"
-msgstr "Snap pe fețele nodului"
+msgstr "Snap pe Fețele Nodului"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Snap to Node Center"
-msgstr "Snap către ancora nodului"
+msgstr "Snap către Centrul Nodului"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Snap to Other Nodes"
-msgstr "Snap către alte noduri"
+msgstr "Snap către Alte Noduri"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Snap to Guides"
-msgstr "Snap pe ghizi"
+msgstr "Snap pe Ghiduri"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9271,9 +9220,8 @@ msgstr "Imobilizează obiectul selectat (nu poate fi mișcat)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Lock Selected Node(s)"
-msgstr "Selectează"
+msgstr "Blochează Nodurile Selectate"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9282,9 +9230,8 @@ msgstr "Remobilizează obiectul selectat (poate fi mișcat)."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Unlock Selected Node(s)"
-msgstr "Selectează"
+msgstr "Deblochează Nodurile Selectate"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9293,9 +9240,8 @@ msgstr "Asigură-te că nu pot fi selectați copiii obiectului."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Group Selected Node(s)"
-msgstr "Elminați Selecția"
+msgstr "Grupează Nodurile Selectate"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -9304,14 +9250,12 @@ msgstr "Restaurează abilitatea copiilor obiectului de a fi selectați."
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
-#, fuzzy
msgid "Ungroup Selected Node(s)"
-msgstr "Elminați Selecția"
+msgstr "Degrupează Nodurile Selectate"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Skeleton Options"
-msgstr "Singleton (Unicat)"
+msgstr "Opțiuni Schelet"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Bones"
@@ -9322,9 +9266,8 @@ msgid "Make Custom Bone(s) from Node(s)"
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Clear Custom Bones"
-msgstr "Curăță Oasele"
+msgstr "Curăță Oasele Personalizate"
#. TRANSLATORS: Noun, name of the 2D/3D View menus.
#: editor/plugins/canvas_item_editor_plugin.cpp
@@ -9333,23 +9276,20 @@ msgid "View"
msgstr "Perspectivă"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Show"
-msgstr "Arată Grila"
+msgstr "Arată"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Show When Snapping"
-msgstr "Snapping inteligent"
+msgstr "Arată Când Faci Snap"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Hide"
-msgstr ""
+msgstr "Ascunde"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Toggle Grid"
-msgstr "Comutare mod"
+msgstr "Comutare Grilă"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/polygon_2d_editor_plugin.cpp
@@ -9378,7 +9318,7 @@ msgstr "Arată Fereastra de Lucru"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Show Group And Lock Icons"
-msgstr ""
+msgstr "Arată Pictogramele de Grupare și Blocare"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Center Selection"
@@ -9390,7 +9330,7 @@ msgstr "Încadrează în Ecran Selecția"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Preview Canvas Scale"
-msgstr ""
+msgstr "Previzualizare Scară Canvas"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Layout"
@@ -9421,14 +9361,12 @@ msgid ""
msgstr ""
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Auto Insert Key"
-msgstr "Anim Inserați Cheie"
+msgstr "Inserare Automată a Cheii"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Animation Key and Pose Options"
-msgstr "Lungime Animație (în secunde)"
+msgstr "Optiuni pentru Chei Animație și Postură"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Insert Key (Existing Tracks)"
@@ -9443,9 +9381,8 @@ msgid "Clear Pose"
msgstr "Curăță Postura"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Add Node Here"
-msgstr "Adaugă punct"
+msgstr "Adaugă Nod Aici"
#: editor/plugins/canvas_item_editor_plugin.cpp
#, fuzzy
@@ -9467,49 +9404,43 @@ msgstr "Perspectivă Snap"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 3.125%"
-msgstr ""
+msgstr "Magnificare la 3.125%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 6.25%"
-msgstr ""
+msgstr "Magnificare la 6.25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 12.5%"
-msgstr ""
+msgstr "Magnificare la 12.5%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 25%"
-msgstr "Departare"
+msgstr "Magnificare la 25%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 50%"
-msgstr "Departare"
+msgstr "Magnificare la 50%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 100%"
-msgstr "Departare"
+msgstr "Magnificare la 100%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 200%"
-msgstr "Departare"
+msgstr "Magnificare la 200%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 400%"
-msgstr "Departare"
+msgstr "Magnificare la 400%"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Zoom to 800%"
-msgstr "Departare"
+msgstr "Magnificare la 800%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Zoom to 1600%"
-msgstr ""
+msgstr "Magnificare la 1600%"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid "Adding %s..."
@@ -9530,9 +9461,8 @@ msgid "Error instancing scene from %s"
msgstr "Eroare la instanțierea scenei din %s"
#: editor/plugins/canvas_item_editor_plugin.cpp
-#, fuzzy
msgid "Change Default Type"
-msgstr "Schimbă tipul implicit"
+msgstr "Schimbă Tipul Implicit"
#: editor/plugins/canvas_item_editor_plugin.cpp
msgid ""
@@ -9543,9 +9473,8 @@ msgstr ""
"Trage & lasă + Shift: Schimbă tipul nodului"
#: editor/plugins/collision_polygon_editor_plugin.cpp
-#, fuzzy
msgid "Create Polygon3D"
-msgstr "Crează Poligon"
+msgstr "Crează Poligon3D"
#: editor/plugins/collision_polygon_editor_plugin.cpp
msgid "Edit Poly"
@@ -9595,7 +9524,7 @@ msgstr "Mască de Emisie"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
msgid "Solid Pixels"
-msgstr ""
+msgstr "Pixeli Solizi"
#: editor/plugins/cpu_particles_2d_editor_plugin.cpp
#: editor/plugins/particles_2d_editor_plugin.cpp
@@ -9618,9 +9547,8 @@ msgid "Emission Colors"
msgstr "Culori de Emisie"
#: editor/plugins/cpu_particles_editor_plugin.cpp
-#, fuzzy
msgid "CPUParticles"
-msgstr "Particule"
+msgstr "ParticuleCPU"
#: editor/plugins/cpu_particles_editor_plugin.cpp
#: editor/plugins/particles_editor_plugin.cpp
@@ -9667,29 +9595,24 @@ msgid "Load Curve Preset"
msgstr "Încarcă Presetare a Curbei"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Add Point"
-msgstr "Adaugă punct"
+msgstr "Adaugă Punct"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Remove Point"
-msgstr "Elimină punct"
+msgstr "Elimină Punct"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Left Linear"
-msgstr "Stânga liniară"
+msgstr "Stânga Liniară"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Right Linear"
-msgstr "Dreapta liniară"
+msgstr "Dreapta Liniară"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Load Preset"
-msgstr "Încarcă presetare"
+msgstr "Încarcă Presetare"
#: editor/plugins/curve_editor_plugin.cpp
msgid "Remove Curve Point"
@@ -9704,9 +9627,8 @@ msgid "Hold Shift to edit tangents individually"
msgstr "Ține apăsat Shift pentru a edita individual tangentele"
#: editor/plugins/curve_editor_plugin.cpp
-#, fuzzy
msgid "Right click to add point"
-msgstr "Click Drept: Ștergere punct"
+msgstr "Click dreapta pentru adăugare punct"
#: editor/plugins/gi_probe_editor_plugin.cpp
msgid "Bake GI Probe"
@@ -9714,7 +9636,7 @@ msgstr "Procesează Sonda GI"
#: editor/plugins/gradient_editor_plugin.cpp
msgid "Gradient Edited"
-msgstr ""
+msgstr "Gradient Dditat"
#: editor/plugins/gradient_texture_2d_editor_plugin.cpp
msgid "Swap GradientTexture2D Fill Points"
@@ -9735,18 +9657,18 @@ msgstr "Comutare mod"
#: scene/gui/rich_text_label.cpp scene/gui/text_edit.cpp
#: scene/resources/primitive_meshes.cpp
msgid "Text"
-msgstr ""
+msgstr "Text"
#: editor/plugins/item_list_editor_plugin.cpp
#: editor/plugins/tile_set_editor_plugin.cpp main/main.cpp
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
#: scene/gui/button.cpp scene/gui/item_list.cpp
msgid "Icon"
-msgstr ""
+msgstr "Pictogramă"
#: editor/plugins/item_list_editor_plugin.cpp
msgid "ID"
-msgstr ""
+msgstr "ID"
#: editor/plugins/item_list_editor_plugin.cpp
#: scene/resources/default_theme/default_theme.cpp
@@ -11288,7 +11210,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
@@ -18656,14 +18578,12 @@ msgid "Var Name"
msgstr "Nume"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "VariableGet not found in script:"
-msgstr "Metoda nu a fost găsită în obiect: "
+msgstr "VariableGet nu a fost găsită în obiect:"
#: modules/visual_script/visual_script_nodes.cpp
-#, fuzzy
msgid "VariableSet not found in script:"
-msgstr "Metoda nu a fost găsită în obiect: "
+msgstr "Metoda VariableSet nu a fost găsită în obiect:"
#: modules/visual_script/visual_script_nodes.cpp
msgid "Preload"
@@ -19354,11 +19274,8 @@ msgid "Signing debug %s..."
msgstr ""
#: platform/android/export/export_plugin.cpp
-#, fuzzy
msgid "Signing release %s..."
-msgstr ""
-"Se Scanează Fișierele,\n"
-"Te Rog Așteaptă..."
+msgstr "Se semnează release-ul %s..."
#: platform/android/export/export_plugin.cpp
msgid "Could not find keystore, unable to export."
diff --git a/editor/translations/ru.po b/editor/translations/ru.po
index d746bb61ad..97e9723383 100644
--- a/editor/translations/ru.po
+++ b/editor/translations/ru.po
@@ -11029,7 +11029,7 @@ msgstr "Задний перÑпективный"
msgid " [auto]"
msgstr " [авто]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [порталы активны]"
diff --git a/editor/translations/si.po b/editor/translations/si.po
index d0fcba8cfd..af22d7b2d2 100644
--- a/editor/translations/si.po
+++ b/editor/translations/si.po
@@ -10744,7 +10744,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/sk.po b/editor/translations/sk.po
index 43c2fa6b5b..4f4e1107f3 100644
--- a/editor/translations/sk.po
+++ b/editor/translations/sk.po
@@ -12,13 +12,14 @@
# Anonymous <noreply@weblate.org>, 2020.
# Mario-projects-dev <m.vitek.mv@gmail.com>, 2021.
# Eliška Fichnová <eliska@fichna.sk>, 2021.
+# Adam Švidroň <adsvidro@gmail.com>, 2022.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2021-07-07 15:34+0000\n"
-"Last-Translator: Eliška Fichnová <eliska@fichna.sk>\n"
+"PO-Revision-Date: 2022-12-21 07:01+0000\n"
+"Last-Translator: Adam Švidroň <adsvidro@gmail.com>\n"
"Language-Team: Slovak <https://hosted.weblate.org/projects/godot-engine/"
"godot/sk/>\n"
"Language: sk\n"
@@ -26,7 +27,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.8-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -34,7 +35,7 @@ msgstr ""
#: core/bind/core_bind.cpp
msgid "Clipboard"
-msgstr ""
+msgstr "Schránka"
#: core/bind/core_bind.cpp
#, fuzzy
@@ -11289,7 +11290,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/sl.po b/editor/translations/sl.po
index 864dac1b8d..3605bbeaf5 100644
--- a/editor/translations/sl.po
+++ b/editor/translations/sl.po
@@ -11456,7 +11456,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/sq.po b/editor/translations/sq.po
index 1215b7dbcb..e4d3ef6732 100644
--- a/editor/translations/sq.po
+++ b/editor/translations/sq.po
@@ -11222,7 +11222,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/sr_Cyrl.po b/editor/translations/sr_Cyrl.po
index 419e33c494..c2d0ffe462 100644
--- a/editor/translations/sr_Cyrl.po
+++ b/editor/translations/sr_Cyrl.po
@@ -12040,7 +12040,7 @@ msgstr "ПерÑпективна пројекција"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/sr_Latn.po b/editor/translations/sr_Latn.po
index 7973756c7e..5693d06931 100644
--- a/editor/translations/sr_Latn.po
+++ b/editor/translations/sr_Latn.po
@@ -10752,7 +10752,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/sv.po b/editor/translations/sv.po
index 04965e6c69..dff36498be 100644
--- a/editor/translations/sv.po
+++ b/editor/translations/sv.po
@@ -25,15 +25,16 @@
# Leon <joel.lundborg@gmail.com>, 2021, 2022.
# Kent Jofur <kent.jofur@gmail.com>, 2021.
# Alex25820 <alexs25820@gmail.com>, 2021.
-# Björn Åkesson <bjorn.akesson@gmail.com>, 2022.
+# Björn Åkesson <bjorn.akesson@gmail.com>, 2022, 2023.
# Kenny Andersson <kenny@ordinary.se>, 2022.
+# Ludvig Svenonius <ludvig.svenonius@protonmail.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-09-29 19:16+0000\n"
-"Last-Translator: Kristoffer Grundström <swedishsailfishosuser@tutanota.com>\n"
+"PO-Revision-Date: 2023-01-20 11:20+0000\n"
+"Last-Translator: Ludvig Svenonius <ludvig.svenonius@protonmail.com>\n"
"Language-Team: Swedish <https://hosted.weblate.org/projects/godot-engine/"
"godot/sv/>\n"
"Language: sv\n"
@@ -41,7 +42,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.14.1\n"
+"X-Generator: Weblate 4.15.1\n"
#: core/bind/core_bind.cpp main/main.cpp
#, fuzzy
@@ -704,9 +705,8 @@ msgid "Script Templates Search Path"
msgstr "Sökväg för skriptmallar"
#: core/project_settings.cpp
-#, fuzzy
msgid "Version Control Autoload On Startup"
-msgstr "Versionshantering"
+msgstr "Automatisk Inläsning av Versionskontroll vid Start"
#: core/project_settings.cpp
#, fuzzy
@@ -8287,7 +8287,7 @@ msgstr ""
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Autoplay on Load"
-msgstr ""
+msgstr "Spela upp automatiskt efter inladdning"
#: editor/plugins/animation_player_editor_plugin.cpp
msgid "Enable Onion Skinning"
@@ -11363,7 +11363,7 @@ msgstr "Perspektiv"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
@@ -15031,19 +15031,19 @@ msgstr ""
#: editor/project_settings_editor.cpp
msgid "Physical Key"
-msgstr ""
+msgstr "Fysisk tangent"
#: editor/project_settings_editor.cpp
msgid "Key "
-msgstr "Nyckel "
+msgstr "Tangent "
#: editor/project_settings_editor.cpp
msgid "Joy Button"
-msgstr ""
+msgstr "Styrspaksknapp"
#: editor/project_settings_editor.cpp
msgid "Joy Axis"
-msgstr ""
+msgstr "Styrspaksaxel"
#: editor/project_settings_editor.cpp
msgid "Mouse Button"
@@ -15072,9 +15072,8 @@ msgid "Add Input Action Event"
msgstr ""
#: editor/project_settings_editor.cpp
-#, fuzzy
msgid "All Devices"
-msgstr "Enhet"
+msgstr "Alla Enheter"
#: editor/project_settings_editor.cpp
msgid " (Physical)"
@@ -20908,11 +20907,11 @@ msgstr ""
#: scene/2d/area_2d.cpp scene/3d/area.cpp
msgid "Monitoring"
-msgstr ""
+msgstr "Övervakning"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
msgid "Monitorable"
-msgstr ""
+msgstr "Övervakningsbar"
#: scene/2d/area_2d.cpp scene/3d/area.cpp
#, fuzzy
@@ -20985,7 +20984,7 @@ msgstr "Slå på/av Autoplay"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/audio/audio_stream_player.cpp
msgid "Stream Paused"
-msgstr ""
+msgstr "Pausad"
#: scene/2d/audio_stream_player_2d.cpp scene/3d/audio_stream_player_3d.cpp
#: scene/3d/light.cpp scene/3d/reflection_probe.cpp
@@ -25655,39 +25654,32 @@ msgid "Swap OK Cancel"
msgstr "Avbryt"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "Layer Names"
-msgstr "Namn"
+msgstr "Skiktnamn"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "2D Render"
-msgstr "Renderare:"
+msgstr "2D-Rendering"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "3D Render"
-msgstr "Renderare:"
+msgstr "3D-Rendering"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "2D Physics"
-msgstr "Fysik Bildruta %"
+msgstr "2D-Fysik"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "3D Physics"
-msgstr "Fysik Bildruta %"
+msgstr "3D-Fysik"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "2D Navigation"
-msgstr "Animations-Node"
+msgstr "2D-Navigation"
#: scene/register_scene_types.cpp
-#, fuzzy
msgid "3D Navigation"
-msgstr "Animations-Node"
+msgstr "3D-Navigation"
#: scene/register_scene_types.cpp
msgid "Use hiDPI"
diff --git a/editor/translations/te.po b/editor/translations/te.po
index 22474ca4ba..f8a1f82710 100644
--- a/editor/translations/te.po
+++ b/editor/translations/te.po
@@ -10590,7 +10590,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/th.po b/editor/translations/th.po
index 5f4ee76a4d..c41428e6d1 100644
--- a/editor/translations/th.po
+++ b/editor/translations/th.po
@@ -11270,7 +11270,7 @@ msgstr "เพอร์สเปà¸à¸—ีฟ"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/tl.po b/editor/translations/tl.po
index 670e52056d..fa5f9a9aea 100644
--- a/editor/translations/tl.po
+++ b/editor/translations/tl.po
@@ -10910,7 +10910,7 @@ msgstr ""
msgid " [auto]"
msgstr " [kusa]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [mga aktibong portal]"
diff --git a/editor/translations/tr.po b/editor/translations/tr.po
index ac4b509150..73fbaec2cb 100644
--- a/editor/translations/tr.po
+++ b/editor/translations/tr.po
@@ -11032,7 +11032,7 @@ msgstr "Arka Perspektif"
msgid " [auto]"
msgstr " [Oto]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [portallar aktif]"
diff --git a/editor/translations/uk.po b/editor/translations/uk.po
index f9a6c787a5..a8d989d5ee 100644
--- a/editor/translations/uk.po
+++ b/editor/translations/uk.po
@@ -17,21 +17,23 @@
# Микола Тимошенко <9081@ukr.net>, 2020.
# Miroslav <zinmirx@gmail.com>, 2020.
# IllusiveMan196 <hamsterrv@gmail.com>, 2021, 2022.
-# KazanskiyMaks <kazanskiy.maks@gmail.com>, 2022.
+# KazanskiyMaks <kazanskiy.maks@gmail.com>, 2022, 2023.
# МироÑлав <hlopukmyroslav@gmail.com>, 2022.
# Ostap <ostapbataj79@gmail.com>, 2022.
# Wald Sin <naaveranos@gmail.com>, 2022.
# Гліб Соколов <ramithes@i.ua>, 2022.
# Max Donchenko <maxx.donchenko@gmail.com>, 2022.
# Artem <artem@molotov.work>, 2022.
-# Teashrock <kajitsu22@gmail.com>, 2022.
+# Teashrock <kajitsu22@gmail.com>, 2022, 2023.
+# kirill7606 <k7606irill@gmail.com>, 2022.
+# Alex <anna.loban@yahoo.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Ukrainian (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-10-03 12:44+0000\n"
-"Last-Translator: Yuri Chornoivan <yurchor@ukr.net>\n"
+"PO-Revision-Date: 2023-01-08 09:47+0000\n"
+"Last-Translator: KazanskiyMaks <kazanskiy.maks@gmail.com>\n"
"Language-Team: Ukrainian <https://hosted.weblate.org/projects/godot-engine/"
"godot/uk/>\n"
"Language: uk\n"
@@ -40,7 +42,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.14.1\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -60,27 +62,27 @@ msgstr "Код виходу"
#: core/bind/core_bind.cpp
msgid "V-Sync Enabled"
-msgstr "Увімкнено верт. Ñинхронізацію"
+msgstr "Увімкнено вертикальну Ñинхронізацію"
#: core/bind/core_bind.cpp main/main.cpp
msgid "V-Sync Via Compositor"
-msgstr "Верт. Ñинхр. через заÑіб композиції"
+msgstr "Вертикальна ÑÐ¸Ð½Ñ…Ñ€Ð¾Ð½Ñ–Ð·Ð°Ñ†Ñ–Ñ Ñ‡ÐµÑ€ÐµÐ· заÑіб композиції"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Delta Smoothing"
-msgstr "Ð—Ð³Ð»Ð°Ð´Ð¶ÑƒÐ²Ð°Ð½Ð½Ñ Ñ€Ñ–Ð·Ð½Ð¸Ñ†Ñ–"
+msgstr "Дельта-згладжуваннÑ"
#: core/bind/core_bind.cpp
msgid "Low Processor Usage Mode"
-msgstr "Режим низького ÑÐ¿Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑора"
+msgstr "Режим низького викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑора"
#: core/bind/core_bind.cpp
msgid "Low Processor Usage Mode Sleep (µsec)"
-msgstr "ПриÑиплÑÐ½Ð½Ñ Ñƒ режимі низького ÑÐ¿Ð¾Ð¶Ð¸Ð²Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑора (мкÑ)"
+msgstr "Ð§Ð°Ñ Ñну в режимі низького викориÑÑ‚Ð°Ð½Ð½Ñ Ð¿Ñ€Ð¾Ñ†ÐµÑора (мкÑ)"
#: core/bind/core_bind.cpp main/main.cpp platform/uwp/os_uwp.cpp
msgid "Keep Screen On"
-msgstr "Залишити зневаджувач відкритим"
+msgstr "Ðе вимикати екран"
#: core/bind/core_bind.cpp
msgid "Min Window Size"
@@ -4533,7 +4535,7 @@ msgstr "Перезавантажити поточний проєкт"
#: editor/editor_node.cpp
msgid "Quit to Project List"
-msgstr "Вийти в ÑпиÑок проєктів"
+msgstr "Вийти до ÑпиÑку проєктів"
#: editor/editor_node.cpp
msgid "Deploy with Remote Debug"
@@ -5496,9 +5498,8 @@ msgid "Mouse Extra Buttons Navigate History"
msgstr "Додаткові кнопки миші Ð´Ð»Ñ Ð½Ð°Ð²Ñ–Ð³Ð°Ñ†Ñ–Ñ— журналом"
#: editor/editor_settings.cpp
-#, fuzzy
msgid "Drag And Drop Selection"
-msgstr "ПеретÑгніть виділене"
+msgstr "Ð’Ð¸Ð´Ñ–Ð»ÐµÐ½Ð½Ñ Drag And Drop"
#: editor/editor_settings.cpp
msgid "Stay In Script Editor On Node Selected"
@@ -10955,7 +10956,7 @@ msgstr "Задній перÑпективний"
msgid " [auto]"
msgstr " [авто]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [портали активні]"
@@ -14219,17 +14220,15 @@ msgid "Invalid project path (changed anything?)."
msgstr "Ðекоректний шлÑÑ… до проєкту (щоÑÑŒ змінилоÑÑ?)."
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
msgstr ""
-"Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ project.godot у каталозі проєкту (помилка %d). "
-"Можливо, файл вилучено або пошкоджено."
+"Ðе вдалоÑÑ Ð·Ð°Ð²Ð°Ð½Ñ‚Ð°Ð¶Ð¸Ñ‚Ð¸ проєкт у '%s' (помилка %d). Можливо, файл вилучено "
+"або пошкоджено."
#: editor/project_manager.cpp
-#, fuzzy
msgid "Couldn't save project at '%s' (error %d)."
-msgstr "Ðе вдалоÑÑ Ð²Ñ–Ð´ÐºÑ€Ð¸Ñ‚Ð¸ проєкт у «%s»."
+msgstr "Ðе вдалоÑÑ Ð·Ð±ÐµÑ€ÐµÐ³Ñ‚Ð¸ проєкт у '%s' (помилка %d)."
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
@@ -15272,18 +15271,16 @@ msgid "Make Local"
msgstr "Зробити локальним"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Enable Scene Unique Name(s)"
-msgstr "Увімкнути унікальну назву Ñцени"
+msgstr "Увімкнути Унікальні Ðазви Сцен(и)"
#: editor/scene_tree_dock.cpp
msgid "Unique names already used by another node in the scene:"
msgstr "Цю унікальну назву у Ñцені вже викориÑтано іншим вузлом:"
#: editor/scene_tree_dock.cpp
-#, fuzzy
msgid "Disable Scene Unique Name(s)"
-msgstr "Вимкнути унікальна назва Ñцени"
+msgstr "Вимкнути Унікальні Ðазви Сцен(и)"
#: editor/scene_tree_dock.cpp
msgid "New Scene Root"
@@ -16315,7 +16312,7 @@ msgstr "Середовище"
#: main/main.cpp
msgid "Default Clear Color"
-msgstr "Типовий колір очищеннÑ"
+msgstr "Типовий чиÑтий колір"
#: main/main.cpp
msgid "Boot Splash"
@@ -16848,12 +16845,10 @@ msgid "Sparse Indices Component Type"
msgstr "Тип компонентів індекÑів розÑіюваннÑ"
#: modules/gltf/gltf_accessor.cpp
-#, fuzzy
msgid "Sparse Values Buffer View"
-msgstr "Буферне Ð¿Ð¾Ð´Ð°Ð½Ð½Ñ Ñ€Ð¾Ð·Ñ€Ñ–Ð´Ð¶ÐµÐ½Ð¸Ñ… значень"
+msgstr "ПереглÑд буфера розріджених значень"
#: modules/gltf/gltf_accessor.cpp
-#, fuzzy
msgid "Sparse Values Byte Offset"
msgstr "Ð—Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ð±Ð°Ð¹Ñ‚Ñ–Ð² розріджених значень"
@@ -16879,7 +16874,7 @@ msgstr "Розмір Ð¿Ð¾Ð»Ñ Ð·Ð¾Ñ€Ñƒ"
#: modules/gltf/gltf_camera.cpp
msgid "Zfar"
-msgstr ""
+msgstr "Ð’Ñ–Ð´Ð´Ð°Ð»ÐµÐ½Ð½Ñ Ð¿Ð¾ Z"
#: modules/gltf/gltf_camera.cpp
msgid "Znear"
@@ -16982,20 +16977,22 @@ msgid "Joint I To Name"
msgstr "З'Ñ”Ð´Ð½Ð°Ð½Ð½Ñ I З Іменем"
#: modules/gltf/gltf_skin.cpp
+#, fuzzy
msgid "Godot Skin"
-msgstr ""
+msgstr "Godot текÑтура"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Diffuse Img"
-msgstr ""
+msgstr "РозÑÑ–Ñне зображеннÑ"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Diffuse Factor"
-msgstr ""
+msgstr "Фактор розÑіюваннÑ"
#: modules/gltf/gltf_spec_gloss.cpp
+#, fuzzy
msgid "Gloss Factor"
-msgstr ""
+msgstr "Фактор блиÑку"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Specular Factor"
@@ -17003,7 +17000,7 @@ msgstr "Коефіцієнт дзеркальноÑÑ‚Ñ–"
#: modules/gltf/gltf_spec_gloss.cpp
msgid "Spec Gloss Img"
-msgstr ""
+msgstr "Дзеркальне глÑнцеве зображеннÑ"
#: modules/gltf/gltf_state.cpp
msgid "Json"
@@ -17022,8 +17019,9 @@ msgid "GLB Data"
msgstr "Дані GLB"
#: modules/gltf/gltf_state.cpp
+#, fuzzy
msgid "Use Named Skin Binds"
-msgstr ""
+msgstr "ВикориÑтовуйте іменовані обшивки"
#: modules/gltf/gltf_state.cpp
msgid "Buffer Views"
@@ -17127,7 +17125,7 @@ msgstr "ÐавігаціÑ"
#: scene/3d/navigation_mesh_instance.cpp
#, fuzzy
msgid "Navigation Layers"
-msgstr "Поведінка навігації"
+msgstr "Ðавігаційні шари"
#: modules/gridmap/grid_map_editor_plugin.cpp
msgid "Next Plane"
@@ -17292,19 +17290,19 @@ msgstr "Запікати карти оÑвітленнÑ"
#: modules/lightmapper_cpu/register_types.cpp
msgid "Low Quality Ray Count"
-msgstr ""
+msgstr "КількіÑÑ‚ÑŒ променів низької ÑкоÑÑ‚Ñ–"
#: modules/lightmapper_cpu/register_types.cpp
msgid "Medium Quality Ray Count"
-msgstr ""
+msgstr "Ð¡ÐµÑ€ÐµÐ´Ð½Ñ ÑкіÑÑ‚ÑŒ підрахунку променів"
#: modules/lightmapper_cpu/register_types.cpp
msgid "High Quality Ray Count"
-msgstr ""
+msgstr "ВиÑока ÑкіÑÑ‚ÑŒ підрахунку променів"
#: modules/lightmapper_cpu/register_types.cpp
msgid "Ultra Quality Ray Count"
-msgstr ""
+msgstr "КількіÑÑ‚ÑŒ променів виÑокої ÑкоÑÑ‚Ñ–"
#: modules/minimp3/audio_stream_mp3.cpp
#: modules/minimp3/resource_importer_mp3.cpp
@@ -17315,7 +17313,7 @@ msgstr "Ð—Ð¼Ñ–Ñ‰ÐµÐ½Ð½Ñ Ñ†Ð¸ÐºÐ»Ñƒ"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "Eye Height"
-msgstr ""
+msgstr "ВиÑота очей"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "IOD"
@@ -17331,7 +17329,7 @@ msgstr "ПереглÑд без тіней"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "Oversample"
-msgstr ""
+msgstr "Ðадвибірка"
#: modules/mobile_vr/mobile_vr_interface.cpp
msgid "K1"
@@ -17354,19 +17352,16 @@ msgid "Auto Update Project"
msgstr "Проєкт без назви"
#: modules/mono/godotsharp_dirs.cpp
-#, fuzzy
msgid "Assembly Name"
-msgstr "Показана назва"
+msgstr "Ðазва збірки"
#: modules/mono/godotsharp_dirs.cpp
-#, fuzzy
msgid "Solution Directory"
-msgstr "Виберіть каталог"
+msgstr "Каталог проєкту"
#: modules/mono/godotsharp_dirs.cpp
-#, fuzzy
msgid "C# Project Directory"
-msgstr "Виберіть каталог"
+msgstr "Каталог проєкту C#"
#: modules/mono/mono_gd/gd_mono_utils.cpp
msgid "End of inner exception stack trace"
@@ -17516,8 +17511,9 @@ msgid "IGD Service Type"
msgstr "Тип Ñлужби IGD"
#: modules/upnp/upnp_device.cpp
+#, fuzzy
msgid "IGD Our Addr"
-msgstr ""
+msgstr "IGD це Ðаша адреÑа"
#: modules/upnp/upnp_device.cpp
msgid "IGD Status"
@@ -18314,12 +18310,14 @@ msgid "Optional Features"
msgstr "Ðеобов'Ñзкові можливоÑÑ‚Ñ–"
#: modules/webxr/webxr_interface.cpp
+#, fuzzy
msgid "Requested Reference Space Types"
-msgstr ""
+msgstr "Запитані типи довідкового проÑтору"
#: modules/webxr/webxr_interface.cpp
+#, fuzzy
msgid "Reference Space Type"
-msgstr ""
+msgstr "Довідка типу проÑтору"
#: modules/webxr/webxr_interface.cpp
msgid "Visibility State"
@@ -18335,7 +18333,7 @@ msgstr "Стандартна прив'Ñзка XR"
#: platform/android/export/export.cpp
msgid "Android SDK Path"
-msgstr ""
+msgstr "ШлÑÑ… Android SDK"
#: platform/android/export/export.cpp
msgid "Debug Keystore"
@@ -18358,8 +18356,9 @@ msgid "Shutdown ADB On Exit"
msgstr ""
#: platform/android/export/export_plugin.cpp
+#, fuzzy
msgid "Launcher Icons"
-msgstr ""
+msgstr "Значки панелі запуÑку"
#: platform/android/export/export_plugin.cpp
#, fuzzy
@@ -18367,12 +18366,14 @@ msgid "Main 192 X 192"
msgstr "iPhone 120 X 120"
#: platform/android/export/export_plugin.cpp
+#, fuzzy
msgid "Adaptive Foreground 432 X 432"
-msgstr ""
+msgstr "адаптивний передній план 432 x 432"
#: platform/android/export/export_plugin.cpp
+#, fuzzy
msgid "Adaptive Background 432 X 432"
-msgstr ""
+msgstr "адаптивний задній план(фон) 432 x 432"
#: platform/android/export/export_plugin.cpp
msgid "Package name is missing."
@@ -18447,8 +18448,9 @@ msgid "Release Password"
msgstr "Пароль випуÑку"
#: platform/android/export/export_plugin.cpp
+#, fuzzy
msgid "One Click Deploy"
-msgstr ""
+msgstr "Ð Ð¾Ð·Ð³Ð¾Ñ€Ñ‚Ð°Ð½Ð½Ñ Ð² один клік"
#: platform/android/export/export_plugin.cpp
msgid "Clear Previous Install"
@@ -18729,10 +18731,13 @@ msgid "\"Min SDK\" should be a valid integer, but got \"%s\" which is invalid."
msgstr ""
#: platform/android/export/export_plugin.cpp
+#, fuzzy
msgid ""
"\"Min SDK\" cannot be lower than %d, which is the version needed by the "
"Godot library."
msgstr ""
+"\"Min SDK\" не може бути нижчим за %d, що Ñ” верÑією, необхідною Ð´Ð»Ñ "
+"бібліотеки Godot."
#: platform/android/export/export_plugin.cpp
#, fuzzy
@@ -18743,15 +18748,20 @@ msgstr ""
"збираннÑ»."
#: platform/android/export/export_plugin.cpp
+#, fuzzy
msgid ""
"\"Target SDK\" should be a valid integer, but got \"%s\" which is invalid."
msgstr ""
+"\"Target SDK\" має бути дійÑним цілим чиÑлом, але отримано \"%s\", Ñке не Ñ” "
+"дійÑним."
#: platform/android/export/export_plugin.cpp
msgid ""
"\"Target SDK\" %d is higher than the default version %d. This may work, but "
"wasn't tested and may be unstable."
msgstr ""
+"\"Target SDK\" %d вищий за Ñтандартну верÑÑ–ÑŽ %d. Це може працювати, але це "
+"не було перевірено та може бути неÑтабільним."
#: platform/android/export/export_plugin.cpp
#, fuzzy
@@ -18930,8 +18940,9 @@ msgid "The character '%s' is not allowed in Identifier."
msgstr "У назві ідентифікатора не можна викориÑтовувати Ñимволи «%s»."
#: platform/iphone/export/export.cpp
+#, fuzzy
msgid "Landscape Launch Screens"
-msgstr ""
+msgstr "Ðльбомні екрани запуÑку"
#: platform/iphone/export/export.cpp
#, fuzzy
@@ -18954,8 +18965,9 @@ msgid "iPad 2048 X 1536"
msgstr "iPad 152 X 152"
#: platform/iphone/export/export.cpp
+#, fuzzy
msgid "Portrait Launch Screens"
-msgstr ""
+msgstr "Портретні початкові екрани"
#: platform/iphone/export/export.cpp
#, fuzzy
@@ -18994,15 +19006,16 @@ msgstr "iPhone 120 X 120"
#: platform/iphone/export/export.cpp
msgid "App Store Team ID"
-msgstr ""
+msgstr "Ідентифікатор команди App Store"
#: platform/iphone/export/export.cpp
+#, fuzzy
msgid "Provisioning Profile UUID Debug"
-msgstr ""
+msgstr "ÐÐ°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ð¿Ñ€Ð¾Ñ„Ñ–Ð»ÑŽ UUID"
#: platform/iphone/export/export.cpp
msgid "Code Sign Identity Debug"
-msgstr ""
+msgstr "ÐÐ°Ð»Ð°Ð³Ð¾Ð´Ð¶ÐµÐ½Ð½Ñ Ñ–Ð´ÐµÐ½Ñ‚Ð¸Ñ„Ñ–ÐºÐ°Ñ†Ñ–Ñ— коду"
#: platform/iphone/export/export.cpp
msgid "Export Method Debug"
diff --git a/editor/translations/ur_PK.po b/editor/translations/ur_PK.po
index 1046f11996..bc15a001c9 100644
--- a/editor/translations/ur_PK.po
+++ b/editor/translations/ur_PK.po
@@ -10936,7 +10936,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/vi.po b/editor/translations/vi.po
index b4a5f4494b..0ff37e659e 100644
--- a/editor/translations/vi.po
+++ b/editor/translations/vi.po
@@ -11119,7 +11119,7 @@ msgstr "Phối cảnh"
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/zh_CN.po b/editor/translations/zh_CN.po
index 52f072e946..5b58752f63 100644
--- a/editor/translations/zh_CN.po
+++ b/editor/translations/zh_CN.po
@@ -92,7 +92,7 @@ msgstr ""
"Project-Id-Version: Chinese (Simplified) (Godot Engine)\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: 2018-01-20 12:15+0200\n"
-"PO-Revision-Date: 2022-12-05 08:51+0000\n"
+"PO-Revision-Date: 2022-12-28 00:54+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"
@@ -101,7 +101,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -145,15 +145,15 @@ msgstr "å±å¹•å¸¸äº®"
#: core/bind/core_bind.cpp
msgid "Min Window Size"
-msgstr "最å°çª—å£å¤§å°"
+msgstr "最å°çª—å£å°ºå¯¸"
#: core/bind/core_bind.cpp
msgid "Max Window Size"
-msgstr "最大窗å£å¤§å°"
+msgstr "最大窗å£å°ºå¯¸"
#: core/bind/core_bind.cpp
msgid "Screen Orientation"
-msgstr "窗å£æœå‘"
+msgstr "å±å¹•æœå‘"
#: core/bind/core_bind.cpp core/project_settings.cpp main/main.cpp
#: platform/uwp/os_uwp.cpp
@@ -1097,7 +1097,7 @@ msgstr "æƒé‡é‡‡æ ·"
#: drivers/gles3/rasterizer_scene_gles3.cpp
msgid "Voxel Cone Tracing"
-msgstr "体素椎追踪"
+msgstr "体素锥追踪"
#: drivers/gles3/rasterizer_scene_gles3.cpp scene/resources/environment.cpp
msgid "High Quality"
@@ -5843,7 +5843,7 @@ msgstr "骨骼轮廓颜色"
#: editor/editor_settings.cpp
msgid "Viewport Border Color"
-msgstr "视区边框颜色"
+msgstr "视å£è¾¹æ¡†é¢œè‰²"
#: editor/editor_settings.cpp
msgid "Constrain Editor View"
@@ -8685,7 +8685,7 @@ msgid ""
"Overrides the running project's camera with the editor viewport camera."
msgstr ""
"项目相机覆盖\n"
-"使用编辑器视图相机覆盖正在è¿è¡Œçš„项目中的相机。"
+"使用编辑器视å£ç›¸æœºè¦†ç›–正在è¿è¡Œçš„项目中的相机。"
#: editor/plugins/canvas_item_editor_plugin.cpp
#: editor/plugins/spatial_editor_plugin.cpp
@@ -10819,7 +10819,7 @@ msgstr "é€è§†åŽè§†å›¾"
msgid " [auto]"
msgstr " [自动]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [å…¥å£ç”Ÿæ•ˆ]"
@@ -11203,27 +11203,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"
@@ -11320,7 +11320,7 @@ msgstr "æ“作å°å·¥å…·ä¸é€æ˜Žåº¦"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Show Viewport Rotation Gizmo"
-msgstr "显示视区旋转å°å·¥å…·"
+msgstr "显示视å£æ—‹è½¬å°å·¥å…·"
#: editor/plugins/spatial_editor_plugin.cpp
msgid "Unnamed Gizmo"
@@ -14010,16 +14010,13 @@ msgid "Invalid project path (changed anything?)."
msgstr "项目路径无效(被外部修改?)。"
#: editor/project_manager.cpp
-#, fuzzy
msgid ""
"Couldn't load project at '%s' (error %d). It may be missing or corrupted."
-msgstr ""
-"无法在项目路径中加载 project.godot 文件(错误 %d)。该文件å¯èƒ½ç¼ºå¤±æˆ–å·²æŸå。"
+msgstr "无法加载ä½äºŽâ€œ%sâ€çš„项目(错误 %d)。项目å¯èƒ½ç¼ºå¤±æˆ–å·²æŸå。"
#: editor/project_manager.cpp
-#, fuzzy
msgid "Couldn't save project at '%s' (error %d)."
-msgstr "无法打开ä½äºŽâ€œ%sâ€çš„项目。"
+msgstr "无法ä¿å­˜ä½äºŽâ€œ%sâ€çš„项目(错误 %d)。"
#: editor/project_manager.cpp
msgid "Couldn't create project.godot in project path."
@@ -14934,7 +14931,7 @@ msgstr "将节点设置为根节点"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes and any children?"
-msgstr "是å¦åˆ é™¤èŠ‚点 “%s†åŠå…¶å­èŠ‚点?"
+msgstr "是å¦åˆ é™¤ %d 个节点åŠå…¶å­èŠ‚点?"
#: editor/scene_tree_dock.cpp
msgid "Delete %d nodes?"
@@ -19971,7 +19968,7 @@ msgstr "缩放"
#: scene/2d/camera_2d.cpp scene/main/canvas_layer.cpp
msgid "Custom Viewport"
-msgstr "自定义视区"
+msgstr "自定义视å£"
#: scene/2d/camera_2d.cpp scene/3d/camera.cpp scene/3d/interpolated_camera.cpp
#: scene/animation/animation_player.cpp scene/animation/animation_tree.cpp
@@ -22699,14 +22696,12 @@ msgid "AABB"
msgstr "AABB"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Sorting"
msgstr "排åº"
#: scene/3d/visual_instance.cpp
-#, fuzzy
msgid "Use AABB Center"
-msgstr "使用环境光"
+msgstr "使用 AABB 中心"
#: scene/3d/visual_instance.cpp scene/resources/navigation_mesh.cpp
msgid "Geometry"
@@ -23869,7 +23864,7 @@ msgstr "拉伸收缩"
#: scene/main/canvas_layer.cpp
msgid "Follow Viewport"
-msgstr "è·Ÿéšè§†åŒº"
+msgstr "è·Ÿéšè§†å£"
#: scene/main/http_request.cpp
msgid "Download File"
diff --git a/editor/translations/zh_HK.po b/editor/translations/zh_HK.po
index 8af64cfc4e..80c7658ff9 100644
--- a/editor/translations/zh_HK.po
+++ b/editor/translations/zh_HK.po
@@ -11433,7 +11433,7 @@ msgstr ""
msgid " [auto]"
msgstr ""
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr ""
diff --git a/editor/translations/zh_TW.po b/editor/translations/zh_TW.po
index dd54885310..4d04c45976 100644
--- a/editor/translations/zh_TW.po
+++ b/editor/translations/zh_TW.po
@@ -38,13 +38,14 @@
# Shi-Xun Hong <jimmy3421@gmail.com>, 2022.
# Hugel <qihu@nfschina.com>, 2022.
# nitenook <admin@alterbaum.net>, 2022.
+# Edison Lee <edisonlee@edisonlee55.com>, 2023.
msgid ""
msgstr ""
"Project-Id-Version: Godot Engine editor\n"
"Report-Msgid-Bugs-To: https://github.com/godotengine/godot\n"
"POT-Creation-Date: \n"
-"PO-Revision-Date: 2022-10-16 07:25+0000\n"
-"Last-Translator: BinotaLIU <me@binota.org>\n"
+"PO-Revision-Date: 2023-01-14 10:06+0000\n"
+"Last-Translator: Edison Lee <edisonlee@edisonlee55.com>\n"
"Language-Team: Chinese (Traditional) <https://hosted.weblate.org/projects/"
"godot-engine/godot/zh_Hant/>\n"
"Language: zh_TW\n"
@@ -52,7 +53,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.15-dev\n"
+"X-Generator: Weblate 4.15.1-dev\n"
#: core/bind/core_bind.cpp main/main.cpp
msgid "Tablet Driver"
@@ -1154,7 +1155,7 @@ msgstr "旋轉"
#: editor/animation_track_editor.cpp editor/script_editor_debugger.cpp
#: modules/visual_script/visual_script_nodes.cpp scene/gui/range.cpp
msgid "Value"
-msgstr "數值"
+msgstr "值"
#: editor/animation_track_editor.cpp
msgid "Arg Count"
@@ -10771,7 +10772,7 @@ msgstr "é€è¦–後視圖"
msgid " [auto]"
msgstr " [自動]"
-#. TRANSLATORS: This will be appended to the view name when Portal Occulusion is enabled.
+#. TRANSLATORS: This will be appended to the view name when Portal Occlusion is enabled.
#: editor/plugins/spatial_editor_plugin.cpp
msgid " [portals active]"
msgstr " [å…¥å£ç”Ÿæ•ˆ]"
@@ -17787,9 +17788,8 @@ msgid "ShiftRight %s"
msgstr "å°‡ %s å‘å³ç§»å‹•"
#: modules/visual_script/visual_script_func_nodes.cpp
-#, fuzzy
msgid "BitAnd %s"
-msgstr "新增 %"
+msgstr ""
#: modules/visual_script/visual_script_func_nodes.cpp
#, fuzzy
@@ -18557,9 +18557,8 @@ msgstr "「Target Sdkã€ç‰ˆæœ¬å¿…須高於或于「Min Sdkã€ç‰ˆæœ¬ä¸€è‡´ã€‚"
#: platform/android/export/export_plugin.cpp platform/osx/export/export.cpp
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Code Signing"
-msgstr "訊號"
+msgstr "程å¼ç¢¼ç°½ç« "
#: platform/android/export/export_plugin.cpp
msgid ""
@@ -18766,11 +18765,11 @@ msgstr ""
#: platform/iphone/export/export.cpp
msgid "App Store Team ID"
-msgstr ""
+msgstr "App Store 團隊 ID"
#: platform/iphone/export/export.cpp
msgid "Provisioning Profile UUID Debug"
-msgstr ""
+msgstr "部署æ述檔 UUID åµéŒ¯"
#: platform/iphone/export/export.cpp
msgid "Code Sign Identity Debug"
@@ -18848,19 +18847,16 @@ msgid "Accessible From iTunes Sharing"
msgstr ""
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
-#, fuzzy
msgid "Privacy"
-msgstr "實體按éµ"
+msgstr "éš±ç§"
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
-#, fuzzy
msgid "Camera Usage Description"
-msgstr "說明"
+msgstr "相機使用æè¿°"
#: platform/iphone/export/export.cpp platform/osx/export/export.cpp
-#, fuzzy
msgid "Microphone Usage Description"
-msgstr "屬性說明"
+msgstr "麥克風使用æè¿°"
#: platform/iphone/export/export.cpp
#, fuzzy
@@ -18933,9 +18929,8 @@ msgid "Custom BG Color"
msgstr "剪下節點"
#: platform/iphone/export/export.cpp
-#, fuzzy
msgid "Export Icons"
-msgstr "展開全部"
+msgstr "匯出圖示"
#: platform/iphone/export/export.cpp platform/javascript/export/export.cpp
#: platform/osx/export/export.cpp
@@ -19017,7 +19012,7 @@ msgstr ""
#: platform/javascript/export/export.cpp
msgid "HTML"
-msgstr ""
+msgstr "HTML"
#: platform/javascript/export/export.cpp
#, fuzzy
@@ -19052,7 +19047,7 @@ msgstr ""
#: platform/javascript/export/export.cpp
msgid "Offline Page"
-msgstr ""
+msgstr "離線é é¢"
#: platform/javascript/export/export.cpp
msgid "Icon 144 X 144"
@@ -19084,16 +19079,15 @@ msgstr ""
#: platform/javascript/export/export.cpp
msgid "HTTP Host"
-msgstr ""
+msgstr "HTTP 主機"
#: platform/javascript/export/export.cpp
msgid "HTTP Port"
-msgstr ""
+msgstr "HTTP 連接埠"
#: platform/javascript/export/export.cpp
-#, fuzzy
msgid "Use SSL"
-msgstr "使用å¸é™„"
+msgstr "使用 SSL"
#: platform/javascript/export/export.cpp
msgid "SSL Key"
@@ -19159,9 +19153,8 @@ msgid "Invalid entitlements file."
msgstr "無效的副檔å。"
#: platform/osx/export/codesign.cpp
-#, fuzzy
msgid "Invalid executable file."
-msgstr "無效的副檔å。"
+msgstr "無效的執行檔。"
#: platform/osx/export/codesign.cpp
msgid "Can't resize signature load command."
@@ -19229,24 +19222,21 @@ msgid "Removable Volumes Usage Description"
msgstr ""
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
-#, fuzzy
msgid "Codesign"
-msgstr "節點"
+msgstr "程å¼ç¢¼ç°½ç« "
#: platform/osx/export/export.cpp platform/uwp/export/export.cpp
#: platform/windows/export/export.cpp
-#, fuzzy
msgid "Identity"
-msgstr "å‘左縮排"
+msgstr "身分"
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
-#, fuzzy
msgid "Timestamp"
-msgstr "時間"
+msgstr "時間戳"
#: platform/osx/export/export.cpp
msgid "Hardened Runtime"
-msgstr ""
+msgstr "Hardened Runtime"
#: platform/osx/export/export.cpp
#, fuzzy
@@ -19259,9 +19249,8 @@ msgid "Entitlements"
msgstr "Gizmo"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Custom File"
-msgstr "剪下節點"
+msgstr "自訂檔案"
#: platform/osx/export/export.cpp
msgid "Allow JIT Code Execution"
@@ -19281,75 +19270,64 @@ msgid "Disable Library Validation"
msgstr "å·²åœç”¨çš„按鈕"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Audio Input"
-msgstr "新增輸入"
+msgstr "音æºè¼¸å…¥"
#: platform/osx/export/export.cpp
msgid "Address Book"
-msgstr ""
+msgstr "地å€ç°¿"
#: platform/osx/export/export.cpp
msgid "Calendars"
-msgstr ""
+msgstr "日曆"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Photos Library"
-msgstr "匯出函å¼åº«"
+msgstr "照片圖庫"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Apple Events"
-msgstr "新增事件"
+msgstr "Apple 活動"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Debugging"
msgstr "åµéŒ¯"
#: platform/osx/export/export.cpp
msgid "App Sandbox"
-msgstr ""
+msgstr "應用程å¼æ²™ç›’"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Network Server"
-msgstr "網路分æžå·¥å…·"
+msgstr "網路伺æœå™¨"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Network Client"
-msgstr "網路分æžå·¥å…·"
+msgstr "網路客戶端"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Device USB"
-msgstr "è£ç½®"
+msgstr "è£ç½® USB"
#: platform/osx/export/export.cpp
msgid "Device Bluetooth"
-msgstr ""
+msgstr "è£ç½®è—芽"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Files Downloads"
-msgstr "下載"
+msgstr "檔案下載"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Files Pictures"
-msgstr "功能"
+msgstr "檔案圖片"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Files Music"
-msgstr "檔案"
+msgstr "檔案音樂"
#: platform/osx/export/export.cpp
-#, fuzzy
msgid "Files Movies"
-msgstr "篩é¸åœ–å¡Š"
+msgstr "檔案影片"
#: platform/osx/export/export.cpp platform/windows/export/export.cpp
#, fuzzy
@@ -19362,15 +19340,15 @@ msgstr "公證"
#: platform/osx/export/export.cpp
msgid "Apple ID Name"
-msgstr ""
+msgstr "Apple ID å稱"
#: platform/osx/export/export.cpp
msgid "Apple ID Password"
-msgstr ""
+msgstr "Apple ID 密碼"
#: platform/osx/export/export.cpp
msgid "Apple Team ID"
-msgstr ""
+msgstr "Apple 團隊 ID"
#: platform/osx/export/export.cpp
msgid "Could not open icon file \"%s\"."
@@ -20004,7 +19982,7 @@ msgstr ""
#: platform/windows/export/export.cpp
msgid "Wine"
-msgstr ""
+msgstr "Wine"
#: platform/x11/export/export.cpp
msgid "32-bit executables cannot have embedded data >= 4 GiB."
@@ -27006,7 +26984,7 @@ msgstr "æ··åˆ (Mix)"
#: servers/audio/effects/audio_effect_compressor.cpp
msgid "Sidechain"
-msgstr ""
+msgstr "å´éˆ"
#: servers/audio/effects/audio_effect_delay.cpp
msgid "Tap 1"
diff --git a/main/main.cpp b/main/main.cpp
index 7ba5ffab2a..b9cb755cbf 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -1677,10 +1677,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->_allow_hidpi = GLOBAL_DEF("display/window/dpi/allow_hidpi", true);
OS::get_singleton()->_allow_layered = GLOBAL_DEF("display/window/per_pixel_transparency/allowed", false);
+#ifdef TOOLS_ENABLED
if (editor || project_manager) {
- // The editor and project manager always detect and use hiDPI if needed
+ // The editor and project manager always detect and use hiDPI if needed.
OS::get_singleton()->_allow_hidpi = true;
+ // Disable Vulkan overlays in editor, they cause various issues.
+ OS::get_singleton()->set_environment("DISABLE_MANGOHUD", "1"); // GH-57403.
+ OS::get_singleton()->set_environment("DISABLE_RTSS_LAYER", "1"); // GH-57937.
+ OS::get_singleton()->set_environment("DISABLE_VKBASALT", "1");
+ } else {
+ // Re-allow using Vulkan overlays, disabled while using the editor.
+ OS::get_singleton()->unset_environment("DISABLE_MANGOHUD");
+ OS::get_singleton()->unset_environment("DISABLE_RTSS_LAYER");
+ OS::get_singleton()->unset_environment("DISABLE_VKBASALT");
}
+#endif
if (rtm == -1) {
rtm = GLOBAL_DEF("rendering/driver/threads/thread_model", OS::RENDER_THREAD_SAFE);
@@ -2114,7 +2125,7 @@ Error Main::setup2(Thread::ID p_main_tid_override) {
#endif
}
-#ifdef TOOLS_ENABLED
+#if defined(TOOLS_ENABLED) && defined(MACOS_ENABLED)
if (OS::get_singleton()->get_bundle_icon_path().is_empty()) {
Ref<Image> icon = memnew(Image(app_icon_png));
DisplayServer::get_singleton()->set_icon(icon);
@@ -2420,6 +2431,14 @@ bool Main::start() {
ERR_FAIL_COND_V_MSG(da.is_null(), false, "Argument supplied to --doctool must be a valid directory path.");
}
+#ifndef MODULE_MONO_ENABLED
+ // Hack to define .NET-specific project settings even on non-.NET builds,
+ // so that we don't lose their descriptions and default values in DocTools.
+ // Default values should be synced with mono_gd/gd_mono.cpp.
+ GLOBAL_DEF("dotnet/project/assembly_name", "");
+ GLOBAL_DEF("dotnet/project/solution_directory", "");
+#endif
+
Error err;
DocTools doc;
doc.generate(doc_base);
@@ -3030,6 +3049,9 @@ bool Main::iteration() {
PhysicsServer2D::get_singleton()->flush_queries();
if (OS::get_singleton()->get_main_loop()->physics_process(physics_step * time_scale)) {
+ PhysicsServer3D::get_singleton()->end_sync();
+ PhysicsServer2D::get_singleton()->end_sync();
+
exit = true;
break;
}
diff --git a/main/performance.cpp b/main/performance.cpp
index 869a947b2a..e24a3673b9 100644
--- a/main/performance.cpp
+++ b/main/performance.cpp
@@ -316,6 +316,7 @@ uint64_t Performance::get_monitor_modification_time() {
Performance::Performance() {
_process_time = 0;
_physics_process_time = 0;
+ _navigation_process_time = 0;
_monitor_modification_time = 0;
singleton = this;
}
diff --git a/misc/hooks/asmessage.applescript b/misc/hooks/asmessage.applescript
new file mode 100644
index 0000000000..15ba94dc37
--- /dev/null
+++ b/misc/hooks/asmessage.applescript
@@ -0,0 +1,59 @@
+on run argv
+ set vButtons to { "OK" }
+ set vButtonCodes to { 0 }
+ set vDbutton to "OK"
+ set vText to ""
+ set vTitle to ""
+ set vTimeout to -1
+
+ repeat with i from 1 to length of argv
+ try
+ set vArg to item i of argv
+ if vArg = "-buttons" then
+ set vButtonsAndCodes to my fSplit(item (i + 1) of argv, ",")
+ set vButtons to {}
+ set vButtonCodes to {}
+ repeat with j from 1 to length of vButtonsAndCodes
+ set vBtn to my fSplit(item j of vButtonsAndCodes, ":")
+ copy (item 1 of vBtn) to the end of the vButtons
+ copy (item 2 of vBtn) to the end of the vButtonCodes
+ end repeat
+ else if vArg = "-title" then
+ set vTitle to item (i + 1) of argv
+ else if vArg = "-center" then
+ -- not supported
+ else if vArg = "-default" then
+ set vDbutton to item (i + 1) of argv
+ else if vArg = "-geometry" then
+ -- not supported
+ else if vArg = "-nearmouse" then
+ -- not supported
+ else if vArg = "-timeout" then
+ set vTimeout to item (i + 1) of argv as integer
+ else if vArg = "-file" then
+ set vText to read (item (i + 1) of argv) as string
+ else if vArg = "-text" then
+ set vText to item (i + 1) of argv
+ end if
+ end try
+ end repeat
+
+ set vDlg to display dialog vText buttons vButtons default button vDbutton with title vTitle giving up after vTimeout with icon stop
+ set vRet to button returned of vDlg
+ repeat with i from 1 to length of vButtons
+ set vBtn to item i of vButtons
+ if vBtn = vRet
+ return item i of vButtonCodes
+ end if
+ end repeat
+
+ return 0
+end run
+
+on fSplit(vString, vDelimiter)
+ set oldDelimiters to AppleScript's text item delimiters
+ set AppleScript's text item delimiters to vDelimiter
+ set vArray to every text item of vString
+ set AppleScript's text item delimiters to oldDelimiters
+ return vArray
+end fSplit
diff --git a/misc/hooks/pre-commit-black b/misc/hooks/pre-commit-black
index b7335685ae..bbad6a690a 100755
--- a/misc/hooks/pre-commit-black
+++ b/misc/hooks/pre-commit-black
@@ -34,6 +34,9 @@ XMSG=`which xmessage 2>/dev/null`
# Path to powershell (Windows only)
PWSH=`which powershell 2>/dev/null`
+# Path to osascript (macOS only)
+OSA=`which osascript 2>/dev/null`
+
##################################################################
# There should be no need to change anything below this line.
@@ -69,6 +72,10 @@ if [ ! -x "$BLACK" ] ; then
elif [ -x "$XMSG" ] ; then
$XMSG -center -title "Error" "Error: black executable not found."
exit 1
+ elif [ -x "$OSA" ] ; then
+ asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")"
+ $OSA "$asmessage" -center -title "Error" --text "Error: black executable not found."
+ exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "Error: black executable not found."
@@ -159,6 +166,16 @@ while true; do
else
yn="N"
fi
+ elif [ -x "$OSA" ] ; then
+ asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")"
+ choice=`$OSA "$asmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"`
+ if [ "$choice" = "100" ] ; then
+ yn="Y"
+ elif [ "$choice" = "200" ] ; then
+ yn="S"
+ else
+ yn="N"
+ fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
@@ -171,7 +188,7 @@ while true; do
yn="N"
fi
else
- printf "Error: zenity, xmessage, or powershell executable not found.\n"
+ printf "Error: zenity, xmessage, osascript, or powershell executable not found.\n"
exit 1
fi
else
diff --git a/misc/hooks/pre-commit-clang-format b/misc/hooks/pre-commit-clang-format
index 9570d5120b..fd0213c175 100755
--- a/misc/hooks/pre-commit-clang-format
+++ b/misc/hooks/pre-commit-clang-format
@@ -47,6 +47,9 @@ XMSG=`which xmessage 2>/dev/null`
# Path to powershell (Windows only)
PWSH=`which powershell 2>/dev/null`
+# Path to osascript (macOS only)
+OSA=`which osascript 2>/dev/null`
+
##################################################################
# There should be no need to change anything below this line.
@@ -89,6 +92,10 @@ if [ ! -x "$CLANG_FORMAT" ] ; then
elif [ -x "$XMSG" ] ; then
$XMSG -center -title "Error" "$message"
exit 1
+ elif [ -x "$OSA" ] ; then
+ asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")"
+ $OSA "$asmessage" -center -title "Error" --text "$message"
+ exit 1
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -center -title "Error" --text "$message"
@@ -199,6 +206,16 @@ while true; do
else
yn="N"
fi
+ elif [ -x "$OSA" ] ; then
+ asmessage="$(canonicalize_filename "$(dirname -- "$0")/asmessage.applescript")"
+ choice=`$OSA "$asmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"`
+ if [ "$choice" = "100" ] ; then
+ yn="Y"
+ elif [ "$choice" = "200" ] ; then
+ yn="S"
+ else
+ yn="N"
+ fi
elif [ \( \( "$OSTYPE" = "msys" \) -o \( "$OSTYPE" = "win32" \) \) -a \( -x "$PWSH" \) ]; then
winmessage="$(canonicalize_filename "$(dirname -- "$0")/winmessage.ps1")"
$PWSH -noprofile -executionpolicy bypass -file "$winmessage" -file "$patch" -buttons "Apply":100,"Apply and stage":200,"Do not apply":0 -center -default "Do not apply" -geometry 800x600 -title "Do you want to apply that patch?"
@@ -211,7 +228,7 @@ while true; do
yn="N"
fi
else
- printf "Error: zenity, xmessage, or powershell executable not found.\n"
+ printf "Error: zenity, xmessage, osascript, or powershell executable not found.\n"
exit 1
fi
else
diff --git a/modules/astcenc/SCsub b/modules/astcenc/SCsub
new file mode 100644
index 0000000000..0f04f2bc28
--- /dev/null
+++ b/modules/astcenc/SCsub
@@ -0,0 +1,55 @@
+#!/usr/bin/env python
+
+Import("env")
+Import("env_modules")
+
+env_astcenc = env_modules.Clone()
+
+# Thirdparty source files
+
+thirdparty_obj = []
+
+thirdparty_dir = "#thirdparty/astcenc/"
+thirdparty_sources = [
+ "astcenc_averages_and_directions.cpp",
+ "astcenc_block_sizes.cpp",
+ "astcenc_color_quantize.cpp",
+ "astcenc_color_unquantize.cpp",
+ "astcenc_compress_symbolic.cpp",
+ "astcenc_compute_variance.cpp",
+ "astcenc_decompress_symbolic.cpp",
+ "astcenc_diagnostic_trace.cpp",
+ "astcenc_entry.cpp",
+ "astcenc_find_best_partitioning.cpp",
+ "astcenc_ideal_endpoints_and_weights.cpp",
+ "astcenc_image.cpp",
+ "astcenc_integer_sequence.cpp",
+ "astcenc_mathlib.cpp",
+ "astcenc_mathlib_softfloat.cpp",
+ "astcenc_partition_tables.cpp",
+ "astcenc_percentile_tables.cpp",
+ "astcenc_pick_best_endpoint_format.cpp",
+ "astcenc_platform_isa_detection.cpp",
+ "astcenc_quantization.cpp",
+ "astcenc_symbolic_physical.cpp",
+ "astcenc_weight_align.cpp",
+ "astcenc_weight_quant_xfer_tables.cpp",
+]
+thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
+
+env_astcenc.Prepend(CPPPATH=[thirdparty_dir])
+
+env_thirdparty = env_astcenc.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_astcenc.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/astcenc/config.py b/modules/astcenc/config.py
new file mode 100644
index 0000000000..eb565b85b9
--- /dev/null
+++ b/modules/astcenc/config.py
@@ -0,0 +1,6 @@
+def can_build(env, platform):
+ return env.editor_build
+
+
+def configure(env):
+ pass
diff --git a/modules/astcenc/image_compress_astcenc.cpp b/modules/astcenc/image_compress_astcenc.cpp
new file mode 100644
index 0000000000..ce10201343
--- /dev/null
+++ b/modules/astcenc/image_compress_astcenc.cpp
@@ -0,0 +1,251 @@
+/**************************************************************************/
+/* image_compress_astcenc.cpp */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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_astcenc.h"
+
+#include "core/os/os.h"
+#include "core/string/print_string.h"
+
+#include <astcenc.h>
+
+void _compress_astc(Image *r_img, float p_lossy_quality, Image::ASTCFormat p_format) {
+ 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.
+ }
+
+ bool is_hdr = false;
+ if ((img_format >= Image::FORMAT_RH) && (img_format <= Image::FORMAT_RGBE9995)) {
+ is_hdr = true;
+ r_img->convert(Image::FORMAT_RGBAF);
+ } else {
+ r_img->convert(Image::FORMAT_RGBA8);
+ }
+
+ // Determine encoder output format from our enum.
+
+ Image::Format target_format = Image::FORMAT_RGBA8;
+ astcenc_profile profile = ASTCENC_PRF_LDR;
+ unsigned int block_x = 4;
+ unsigned int block_y = 4;
+
+ if (p_format == Image::ASTCFormat::ASTC_FORMAT_4x4) {
+ if (is_hdr) {
+ target_format = Image::FORMAT_ASTC_4x4_HDR;
+ profile = ASTCENC_PRF_HDR;
+ } else {
+ target_format = Image::FORMAT_ASTC_4x4;
+ }
+ } else if (p_format == Image::ASTCFormat::ASTC_FORMAT_8x8) {
+ if (is_hdr) {
+ target_format = Image::FORMAT_ASTC_8x8_HDR;
+ profile = ASTCENC_PRF_HDR;
+ } else {
+ target_format = Image::FORMAT_ASTC_8x8;
+ }
+ block_x = 8;
+ block_y = 8;
+ }
+
+ // Compress image data and (if required) mipmaps.
+
+ const bool mipmaps = r_img->has_mipmaps();
+ int width = r_img->get_width();
+ int height = r_img->get_height();
+
+ print_verbose(vformat("astcenc: Encoding image size %dx%d to format %s%s.", width, height, Image::get_format_name(target_format), mipmaps ? ", with mipmaps" : ""));
+
+ // Initialize astcenc.
+
+ astcenc_config config;
+ config.block_x = block_x;
+ config.block_y = block_y;
+ config.profile = profile;
+ const float quality = ASTCENC_PRE_MEDIUM;
+
+ astcenc_error status = astcenc_config_init(profile, block_x, block_y, block_x, quality, 0, &config);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: Configuration initialization failed: %s.", astcenc_get_error_string(status)));
+
+ // Context allocation.
+
+ astcenc_context *context;
+ const unsigned int thread_count = OS::get_singleton()->get_processor_count();
+
+ status = astcenc_context_alloc(&config, thread_count, &context);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: Context allocation failed: %s.", astcenc_get_error_string(status)));
+
+ // Compress image.
+
+ Vector<uint8_t> image_data = r_img->get_data();
+ uint8_t *slices = image_data.ptrw();
+
+ astcenc_image image;
+ image.dim_x = width;
+ image.dim_y = height;
+ image.dim_z = 1;
+ image.data_type = ASTCENC_TYPE_U8;
+ if (is_hdr) {
+ image.data_type = ASTCENC_TYPE_F32;
+ }
+ image.data = reinterpret_cast<void **>(&slices);
+
+ // Compute the number of ASTC blocks in each dimension.
+ unsigned int block_count_x = (width + block_x - 1) / block_x;
+ unsigned int block_count_y = (height + block_y - 1) / block_y;
+ size_t comp_len = block_count_x * block_count_y * 16;
+
+ Vector<uint8_t> compressed_data;
+ compressed_data.resize(comp_len);
+ compressed_data.fill(0);
+
+ const astcenc_swizzle swizzle = {
+ ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A
+ };
+
+ status = astcenc_compress_image(context, &image, &swizzle, compressed_data.ptrw(), comp_len, 0);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: ASTC image compression failed: %s.", astcenc_get_error_string(status)));
+
+ // Replace original image with compressed one.
+
+ r_img->set_data(width, height, mipmaps, target_format, compressed_data);
+
+ print_verbose(vformat("astcenc: Encoding took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
+}
+
+void _decompress_astc(Image *r_img) {
+ uint64_t start_time = OS::get_singleton()->get_ticks_msec();
+
+ // Determine decompression parameters from image format.
+
+ Image::Format img_format = r_img->get_format();
+ bool is_hdr = false;
+ unsigned int block_x = 0;
+ unsigned int block_y = 0;
+ if (img_format == Image::FORMAT_ASTC_4x4) {
+ block_x = 4;
+ block_y = 4;
+ is_hdr = false;
+ } else if (img_format == Image::FORMAT_ASTC_4x4_HDR) {
+ block_x = 4;
+ block_y = 4;
+ is_hdr = true;
+ } else if (img_format == Image::FORMAT_ASTC_8x8) {
+ block_x = 8;
+ block_y = 8;
+ is_hdr = false;
+ } else if (img_format == Image::FORMAT_ASTC_8x8_HDR) {
+ block_x = 8;
+ block_y = 8;
+ is_hdr = true;
+ } else {
+ ERR_FAIL_MSG("astcenc: Cannot decompress Image with a non-ASTC format.");
+ }
+
+ // Initialize astcenc.
+
+ astcenc_profile profile = ASTCENC_PRF_LDR;
+ if (is_hdr) {
+ profile = ASTCENC_PRF_HDR;
+ }
+ astcenc_config config;
+ const float quality = ASTCENC_PRE_MEDIUM;
+
+ astcenc_error status = astcenc_config_init(profile, block_x, block_y, block_x, quality, 0, &config);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: Configuration initialization failed: %s.", astcenc_get_error_string(status)));
+
+ // Context allocation.
+
+ astcenc_context *context = nullptr;
+ const unsigned int thread_count = OS::get_singleton()->get_processor_count();
+
+ status = astcenc_context_alloc(&config, thread_count, &context);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: Context allocation failed: %s.", astcenc_get_error_string(status)));
+
+ // Decompress image.
+
+ const bool mipmaps = r_img->has_mipmaps();
+ int width = r_img->get_width();
+ int height = r_img->get_height();
+
+ astcenc_image image;
+ image.dim_x = width;
+ image.dim_y = height;
+ image.dim_z = 1;
+ image.data_type = ASTCENC_TYPE_U8;
+ Image::Format target_format = Image::FORMAT_RGBA8;
+ if (is_hdr) {
+ target_format = Image::FORMAT_RGBAF;
+ image.data_type = ASTCENC_TYPE_F32;
+ }
+
+ Vector<uint8_t> image_data = r_img->get_data();
+
+ Vector<uint8_t> new_image_data;
+ new_image_data.resize(Image::get_image_data_size(width, height, target_format, false));
+ new_image_data.fill(0);
+ uint8_t *slices = new_image_data.ptrw();
+ image.data = reinterpret_cast<void **>(&slices);
+
+ const astcenc_swizzle swizzle = {
+ ASTCENC_SWZ_R, ASTCENC_SWZ_G, ASTCENC_SWZ_B, ASTCENC_SWZ_A
+ };
+
+ status = astcenc_decompress_image(context, image_data.ptr(), image_data.size(), &image, &swizzle, 0);
+ ERR_FAIL_COND_MSG(status != ASTCENC_SUCCESS,
+ vformat("astcenc: ASTC decompression failed: %s.", astcenc_get_error_string(status)));
+ ERR_FAIL_COND_MSG(image.dim_z > 1,
+ "astcenc: ASTC decompression failed because this is a 3D texture, which is not supported.");
+
+ // Replace original image with compressed one.
+
+ Image::Format image_format = Image::FORMAT_RGBA8;
+ if (image.data_type == ASTCENC_TYPE_F32) {
+ image_format = Image::FORMAT_RGBAF;
+ } else if (image.data_type == ASTCENC_TYPE_U8) {
+ image_format = Image::FORMAT_RGBA8;
+ } else if (image.data_type == ASTCENC_TYPE_F16) {
+ image_format = Image::FORMAT_RGBAH;
+ } else {
+ ERR_FAIL_MSG("astcenc: ASTC decompression failed with an unknown format.");
+ }
+
+ r_img->set_data(image.dim_x, image.dim_y, mipmaps, image_format, new_image_data);
+
+ print_verbose(vformat("astcenc: Decompression took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
+}
diff --git a/editor/array_property_edit.h b/modules/astcenc/image_compress_astcenc.h
index 6e34a06943..a197a91e0d 100644
--- a/editor/array_property_edit.h
+++ b/modules/astcenc/image_compress_astcenc.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* array_property_edit.h */
+/* image_compress_astcenc.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,42 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef ARRAY_PROPERTY_EDIT_H
-#define ARRAY_PROPERTY_EDIT_H
+#ifndef IMAGE_COMPRESS_ASTCENC_H
+#define IMAGE_COMPRESS_ASTCENC_H
-#include "scene/main/node.h"
+#include "core/io/image.h"
-class ArrayPropertyEdit : public RefCounted {
- GDCLASS(ArrayPropertyEdit, RefCounted);
+void _compress_astc(Image *r_img, float p_lossy_quality, Image::ASTCFormat p_format);
+void _decompress_astc(Image *r_img);
- int page;
- ObjectID obj;
- StringName property;
- String vtypes;
- String subtype_hint_string;
- PropertyHint subtype_hint;
- Variant::Type subtype;
- Variant get_array() const;
- Variant::Type default_type;
-
- void _notif_change();
- void _set_size(int p_size);
- void _set_value(int p_idx, const Variant &p_value);
-
- bool _dont_undo_redo();
-
-protected:
- static void _bind_methods();
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- void edit(Object *p_obj, const StringName &p_prop, const String &p_hint_string, Variant::Type p_deftype);
-
- Node *get_node();
-
- ArrayPropertyEdit();
-};
-
-#endif // ARRAY_PROPERTY_EDIT_H
+#endif // IMAGE_COMPRESS_ASTCENC_H
diff --git a/editor/dictionary_property_edit.h b/modules/astcenc/register_types.cpp
index 197bb394d4..0bb1c3432f 100644
--- a/editor/dictionary_property_edit.h
+++ b/modules/astcenc/register_types.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* dictionary_property_edit.h */
+/* register_types.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,37 +28,21 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef DICTIONARY_PROPERTY_EDIT_H
-#define DICTIONARY_PROPERTY_EDIT_H
+#include "register_types.h"
-#include "scene/main/node.h"
+#include "image_compress_astcenc.h"
-class DictionaryPropertyEdit : public RefCounted {
- GDCLASS(DictionaryPropertyEdit, RefCounted);
+void initialize_astcenc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
- ObjectID obj;
- StringName property;
+ Image::_image_compress_astc_func = _compress_astc;
+ Image::_image_decompress_astc = _decompress_astc;
+}
- void _notif_change();
- void _set_key(const Variant &p_old_key, const Variant &p_new_key);
- void _set_value(const Variant &p_key, const Variant &p_value);
-
- Variant get_dictionary() const;
-
- bool _dont_undo_redo();
-
-protected:
- static void _bind_methods();
- bool _set(const StringName &p_name, const Variant &p_value);
- bool _get(const StringName &p_name, Variant &r_ret) const;
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- void edit(Object *p_obj, const StringName &p_prop);
-
- Node *get_node();
-
- DictionaryPropertyEdit();
-};
-
-#endif // DICTIONARY_PROPERTY_EDIT_H
+void uninitialize_astcenc_module(ModuleInitializationLevel p_level) {
+ if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
+ return;
+ }
+}
diff --git a/scene/resources/skeleton_modification_3d_stackholder.h b/modules/astcenc/register_types.h
index da39044f97..636da9ff8b 100644
--- a/scene/resources/skeleton_modification_3d_stackholder.h
+++ b/modules/astcenc/register_types.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* skeleton_modification_3d_stackholder.h */
+/* register_types.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,32 +28,12 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef SKELETON_MODIFICATION_3D_STACKHOLDER_H
-#define SKELETON_MODIFICATION_3D_STACKHOLDER_H
+#ifndef ASTCENC_REGISTER_TYPES_H
+#define ASTCENC_REGISTER_TYPES_H
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
+#include "modules/register_module_types.h"
-class SkeletonModification3DStackHolder : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DStackHolder, SkeletonModification3D);
+void initialize_astcenc_module(ModuleInitializationLevel p_level);
+void uninitialize_astcenc_module(ModuleInitializationLevel p_level);
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- Ref<SkeletonModificationStack3D> held_modification_stack;
-
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_held_modification_stack(Ref<SkeletonModificationStack3D> p_held_stack);
- Ref<SkeletonModificationStack3D> get_held_modification_stack() const;
-
- SkeletonModification3DStackHolder();
- ~SkeletonModification3DStackHolder();
-};
-
-#endif // SKELETON_MODIFICATION_3D_STACKHOLDER_H
+#endif // ASTCENC_REGISTER_TYPES_H
diff --git a/modules/bmp/image_loader_bmp.cpp b/modules/bmp/image_loader_bmp.cpp
index 3b789a235f..5b451fbf6b 100644
--- a/modules/bmp/image_loader_bmp.cpp
+++ b/modules/bmp/image_loader_bmp.cpp
@@ -58,6 +58,13 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
ERR_FAIL_COND_V_MSG(height % 8 != 0, ERR_UNAVAILABLE,
vformat("1-bpp BMP images must have a height that is a multiple of 8, but the imported BMP is %d pixels tall.", int(height)));
+ } else if (bits_per_pixel == 2) {
+ // Requires bit unpacking...
+ ERR_FAIL_COND_V_MSG(width % 4 != 0, ERR_UNAVAILABLE,
+ vformat("2-bpp BMP images must have a width that is a multiple of 4, but the imported BMP is %d pixels wide.", int(width)));
+ ERR_FAIL_COND_V_MSG(height % 4 != 0, ERR_UNAVAILABLE,
+ vformat("2-bpp BMP images must have a height that is a multiple of 4, but the imported BMP is %d pixels tall.", int(height)));
+
} else if (bits_per_pixel == 4) {
// Requires bit unpacking...
ERR_FAIL_COND_V_MSG(width % 2 != 0, ERR_UNAVAILABLE,
@@ -88,7 +95,7 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
const uint32_t line_width = (width_bytes + 3) & ~3;
// The actual data traversal is determined by
- // the data width in case of 8/4/1 bit images
+ // the data width in case of 8/4/2/1 bit images
const uint32_t w = bits_per_pixel >= 24 ? width : width_bytes;
const uint8_t *line = p_buffer + (line_width * (height - 1));
const uint8_t *end_buffer = p_buffer + p_header.bmp_file_header.bmp_file_size - p_header.bmp_file_header.bmp_file_offset;
@@ -114,6 +121,17 @@ Error ImageLoaderBMP::convert_to_image(Ref<Image> p_image,
index += 8;
line_ptr += 1;
} break;
+ case 2: {
+ uint8_t color_index = *line_ptr;
+
+ write_buffer[index + 0] = (color_index >> 6) & 3;
+ write_buffer[index + 1] = (color_index >> 4) & 3;
+ write_buffer[index + 2] = (color_index >> 2) & 3;
+ write_buffer[index + 3] = color_index & 3;
+
+ index += 4;
+ line_ptr += 1;
+ } break;
case 4: {
uint8_t color_index = *line_ptr;
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index 61787691a3..2c533cb36d 100644
--- a/modules/csg/editor/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -217,7 +217,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Sphere Shape Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
ur->add_undo_method(s, "set_radius", p_restore);
@@ -231,7 +231,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Change Box Shape Size"));
ur->add_do_method(s, "set_size", s->get_size());
ur->add_undo_method(s, "set_size", p_restore);
@@ -249,7 +249,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Cylinder Radius"));
ur->add_do_method(s, "set_radius", s->get_radius());
@@ -274,7 +274,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
return;
}
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
if (p_id == 0) {
ur->create_action(TTR("Change Torus Inner Radius"));
ur->add_do_method(s, "set_inner_radius", s->get_inner_radius());
diff --git a/modules/etcpak/image_compress_etcpak.cpp b/modules/etcpak/image_compress_etcpak.cpp
index b5192bd664..a6aeec54cc 100644
--- a/modules/etcpak/image_compress_etcpak.cpp
+++ b/modules/etcpak/image_compress_etcpak.cpp
@@ -33,8 +33,8 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
-#include "thirdparty/etcpak/ProcessDxtc.hpp"
-#include "thirdparty/etcpak/ProcessRGB.hpp"
+#include <ProcessDxtc.hpp>
+#include <ProcessRGB.hpp>
EtcpakType _determine_etc_type(Image::UsedChannels p_channels) {
switch (p_channels) {
@@ -130,7 +130,7 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua
} else if (p_compresstype == EtcpakType::ETCPAK_TYPE_DXT5) {
target_format = Image::FORMAT_DXT5;
} else {
- ERR_FAIL_MSG("Invalid or unsupported Etcpak compression format.");
+ ERR_FAIL_MSG("Invalid or unsupported etcpak compression format, not ETC or DXT.");
}
// Compress image data and (if required) mipmaps.
@@ -171,7 +171,7 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua
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)));
+ print_verbose(vformat("etcpak: Encoding image size %dx%d to format %s%s.", width, height, Image::get_format_name(target_format), mipmaps ? ", with mipmaps" : ""));
int dest_size = Image::get_image_data_size(width, height, target_format, mipmaps);
Vector<uint8_t> dest_data;
@@ -232,12 +232,12 @@ void _compress_etcpak(EtcpakType p_compresstype, Image *r_img, float p_lossy_qua
} 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.");
+ ERR_FAIL_MSG("etcpak: Invalid or unsupported compression format.");
}
}
// Replace original image with compressed one.
r_img->set_data(width, height, mipmaps, target_format, dest_data);
- print_verbose(vformat("ETCPAK encode took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
+ print_verbose(vformat("etcpak: Encoding took %s ms.", rtos(OS::get_singleton()->get_ticks_msec() - start_time)));
}
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index fd748ea569..3fe741a582 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -553,6 +553,7 @@
@icon("res://path/to/class/icon.svg")
[/codeblock]
[b]Note:[/b] Only the script can have a custom icon. Inner classes are not supported.
+ [b]Note:[/b] As annotations describe their subject, the [code]@icon[/code] annotation must be placed before the class definition and inheritance.
</description>
</annotation>
<annotation name="@onready">
@@ -585,6 +586,7 @@
@tool
extends Node
[/codeblock]
+ [b]Note:[/b] As annotations describe their subject, the [code]@tool[/code] annotation must be placed before the class definition and inheritance.
</description>
</annotation>
<annotation name="@warning_ignore" qualifiers="vararg">
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 8246c96c15..1a102bd16f 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -11,12 +11,6 @@
<link title="GDScript documentation index">$DOCS_URL/tutorials/scripting/gdscript/index.html</link>
</tutorials>
<methods>
- <method name="get_as_byte_code" qualifiers="const">
- <return type="PackedByteArray" />
- <description>
- Returns byte code for the script source code.
- </description>
- </method>
<method name="new" qualifiers="vararg">
<return type="Variant" />
<description>
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 28f478e9cd..ffe01eaa18 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -1007,17 +1007,6 @@ void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
void GDScript::_bind_methods() {
ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new"));
-
- ClassDB::bind_method(D_METHOD("get_as_byte_code"), &GDScript::get_as_byte_code);
-}
-
-Vector<uint8_t> GDScript::get_as_byte_code() const {
- return Vector<uint8_t>();
-};
-
-// TODO: Fully remove this. There's not this kind of "bytecode" anymore.
-Error GDScript::load_byte_code(const String &p_path) {
- return ERR_COMPILATION_FAILED;
}
void GDScript::set_path(const String &p_path, bool p_take_over) {
@@ -2647,8 +2636,6 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str
Error err;
Ref<GDScript> scr = GDScriptCache::get_full_script(p_path, err, "", p_cache_mode == CACHE_MODE_IGNORE);
- // TODO: Reintroduce binary and encrypted scripts.
-
if (scr.is_null()) {
// Don't fail loading because of parsing error.
scr.instantiate();
@@ -2663,9 +2650,6 @@ Ref<Resource> ResourceFormatLoaderGDScript::load(const String &p_path, const Str
void ResourceFormatLoaderGDScript::get_recognized_extensions(List<String> *p_extensions) const {
p_extensions->push_back("gd");
- // TODO: Reintroduce binary and encrypted scripts.
- // p_extensions->push_back("gdc");
- // p_extensions->push_back("gde");
}
bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
@@ -2674,8 +2658,7 @@ bool ResourceFormatLoaderGDScript::handles_type(const String &p_type) const {
String ResourceFormatLoaderGDScript::get_resource_type(const String &p_path) const {
String el = p_path.get_extension().to_lower();
- // TODO: Reintroduce binary and encrypted scripts.
- if (el == "gd" /*|| el == "gdc" || el == "gde"*/) {
+ if (el == "gd") {
return "GDScript";
}
return "";
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index a53785a98d..71184ac2da 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -250,9 +250,6 @@ public:
virtual void set_path(const String &p_path, bool p_take_over = false) override;
String get_script_path() const;
Error load_source_code(const String &p_path);
- Error load_byte_code(const String &p_path);
-
- Vector<uint8_t> get_as_byte_code() const;
bool get_property_default_value(const StringName &p_property, Variant &r_value) const override;
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 1b488d560c..e04a962dcb 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1722,21 +1722,52 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
if (list_resolved) {
variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
variable_type.kind = GDScriptParser::DataType::BUILTIN;
- variable_type.builtin_type = Variant::INT; // Can this ever be a float or something else?
- p_for->variable->set_datatype(variable_type);
+ variable_type.builtin_type = Variant::INT;
} else if (p_for->list) {
resolve_node(p_for->list, false);
- if (p_for->list->datatype.has_container_element_type()) {
- variable_type = p_for->list->datatype.get_container_element_type();
- variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
- } else if (p_for->list->datatype.is_typed_container_type()) {
- variable_type = p_for->list->datatype.get_typed_container_type();
- variable_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
- } else {
- // Last resort
- // TODO: Must other cases be handled? Must we mark as unsafe?
- variable_type.type_source = GDScriptParser::DataType::UNDETECTED;
+ GDScriptParser::DataType list_type = p_for->list->get_datatype();
+ if (!list_type.is_hard_type()) {
+ mark_node_unsafe(p_for->list);
+ }
+ if (list_type.is_variant()) {
+ variable_type.kind = GDScriptParser::DataType::VARIANT;
+ mark_node_unsafe(p_for->list);
+ } else if (list_type.has_container_element_type()) {
+ variable_type = list_type.get_container_element_type();
+ variable_type.type_source = list_type.type_source;
+ } else if (list_type.is_typed_container_type()) {
+ variable_type = list_type.get_typed_container_type();
+ variable_type.type_source = list_type.type_source;
+ } else if (list_type.builtin_type == Variant::INT || list_type.builtin_type == Variant::FLOAT || list_type.builtin_type == Variant::STRING) {
+ variable_type.type_source = list_type.type_source;
+ variable_type.kind = GDScriptParser::DataType::BUILTIN;
+ variable_type.builtin_type = list_type.builtin_type;
+ } else if (list_type.builtin_type == Variant::VECTOR2I || list_type.builtin_type == Variant::VECTOR3I) {
+ variable_type.type_source = list_type.type_source;
+ variable_type.kind = GDScriptParser::DataType::BUILTIN;
+ variable_type.builtin_type = Variant::INT;
+ } else if (list_type.builtin_type == Variant::VECTOR2 || list_type.builtin_type == Variant::VECTOR3) {
+ variable_type.type_source = list_type.type_source;
+ variable_type.kind = GDScriptParser::DataType::BUILTIN;
+ variable_type.builtin_type = Variant::FLOAT;
+ } else if (list_type.builtin_type == Variant::OBJECT) {
+ GDScriptParser::DataType return_type;
+ List<GDScriptParser::DataType> par_types;
+ int default_arg_count = 0;
+ bool is_static = false;
+ bool is_vararg = false;
+ if (get_function_signature(p_for->list, false, list_type, CoreStringNames::get_singleton()->_iter_get, return_type, par_types, default_arg_count, is_static, is_vararg)) {
+ variable_type = return_type;
+ variable_type.type_source = list_type.type_source;
+ } else if (!list_type.is_hard_type()) {
+ variable_type.kind = GDScriptParser::DataType::VARIANT;
+ } else {
+ push_error(vformat(R"(Unable to iterate on object of type "%s".)", list_type.to_string()), p_for->list);
+ }
+ } else if (list_type.builtin_type == Variant::ARRAY || list_type.builtin_type == Variant::DICTIONARY || !list_type.is_hard_type()) {
variable_type.kind = GDScriptParser::DataType::VARIANT;
+ } else {
+ push_error(vformat(R"(Unable to iterate on value of type "%s".)", list_type.to_string()), p_for->list);
}
}
if (p_for->variable) {
@@ -2910,8 +2941,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base_set_class(GDScriptParser::Ide
p_identifier->set_datatype(p_identifier_datatype);
Error err = OK;
- GDScript *scr = GDScriptCache::get_full_script(p_identifier_datatype.script_path, err).ptr();
- ERR_FAIL_COND_MSG(err != OK, "Error while getting full script.");
+ GDScript *scr = GDScriptCache::get_shallow_script(p_identifier_datatype.script_path, err).ptr();
+ ERR_FAIL_COND_MSG(err != OK, vformat(R"(Error while getting cache for script "%s".)", p_identifier_datatype.script_path));
scr = scr->find_class(p_identifier_datatype.class_type->fqcn);
p_identifier->reduced_value = scr;
p_identifier->is_constant = true;
@@ -3140,7 +3171,7 @@ void GDScriptAnalyzer::reduce_identifier(GDScriptParser::IdentifierNode *p_ident
for (int i = 0; i < current_enum->values.size(); i++) {
const GDScriptParser::EnumNode::Value &element = current_enum->values[i];
if (element.identifier->name == p_identifier->name) {
- StringName enum_name = current_enum->identifier->name ? current_enum->identifier->name : UNNAMED_ENUM;
+ StringName enum_name = current_enum->identifier ? current_enum->identifier->name : UNNAMED_ENUM;
GDScriptParser::DataType type = make_enum_type(enum_name, parser->current_class->fqcn, false);
if (element.parent_enum->identifier) {
type.enum_type = element.parent_enum->identifier->name;
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 77c6690d20..d63a1b4536 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -213,7 +213,7 @@ static bool _have_exact_arguments(const MethodBind *p_method, const Vector<GDScr
}
GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root, bool p_initializer, const GDScriptCodeGenerator::Address &p_index_addr) {
- if (p_expression->is_constant && !p_expression->get_datatype().is_meta_type) {
+ if (p_expression->is_constant && !(p_expression->get_datatype().is_meta_type && p_expression->get_datatype().kind == GDScriptParser::DataType::CLASS)) {
return codegen.add_constant(p_expression->reduced_value);
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 0a1ae46927..3fc0924b4c 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -80,7 +80,7 @@ Ref<Script> GDScriptLanguage::make_template(const String &p_template, const Stri
}
processed_template = processed_template.replace("_BASE_", p_base_class_name)
- .replace("_CLASS_", p_class_name)
+ .replace("_CLASS_", p_class_name.to_pascal_case())
.replace("_TS_", _get_indentation());
scr->set_source_code(processed_template);
return scr;
@@ -1275,6 +1275,14 @@ static void _find_identifiers(const GDScriptParser::CompletionContext &p_context
}
r_result.insert(option.display, option);
}
+
+ // Global classes
+ List<StringName> global_classes;
+ ScriptServer::get_global_class_list(&global_classes);
+ for (const StringName &E : global_classes) {
+ ScriptLanguage::CodeCompletionOption option(E, ScriptLanguage::CODE_COMPLETION_KIND_CLASS, ScriptLanguage::LOCATION_OTHER_USER_CODE);
+ r_result.insert(option.display, option);
+ }
}
static GDScriptCompletionIdentifier _type_from_variant(const Variant &p_value) {
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 97d5c1d8b2..f5d3306376 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -540,43 +540,28 @@ void GDScriptParser::parse_program() {
head = alloc_node<ClassNode>();
head->fqcn = script_path;
current_class = head;
+ bool can_have_class_or_extends = true;
- // If we happen to parse an annotation before extends or class_name keywords, track it.
- // @tool is allowed, but others should fail.
- AnnotationNode *premature_annotation = nullptr;
-
- if (match(GDScriptTokenizer::Token::ANNOTATION)) {
- // Check for @tool, script-level, or standalone annotation.
+ while (match(GDScriptTokenizer::Token::ANNOTATION)) {
AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL);
if (annotation != nullptr) {
- if (annotation->name == SNAME("@tool")) {
- // TODO: don't allow @tool anywhere else. (Should all script annotations be the first thing?).
- _is_tool = true;
- if (previous.type != GDScriptTokenizer::Token::NEWLINE) {
- push_error(R"(Expected newline after "@tool" annotation.)");
- }
- // @tool annotation has no specific target.
- annotation->apply(this, nullptr);
- } else if (annotation->applies_to(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE)) {
- premature_annotation = annotation;
- if (previous.type != GDScriptTokenizer::Token::NEWLINE) {
- push_error(R"(Expected newline after a standalone annotation.)");
- }
+ if (annotation->applies_to(AnnotationInfo::SCRIPT)) {
annotation->apply(this, head);
} else {
- premature_annotation = annotation;
annotation_stack.push_back(annotation);
+ // This annotation must appear after script-level annotations
+ // and class_name/extends (ex: could be @onready or @export),
+ // so we stop looking for script-level stuff.
+ can_have_class_or_extends = false;
+ break;
}
}
}
- for (bool should_break = false; !should_break;) {
+ while (can_have_class_or_extends) {
// Order here doesn't matter, but there should be only one of each at most.
switch (current.type) {
case GDScriptTokenizer::Token::CLASS_NAME:
- if (premature_annotation != nullptr) {
- push_error(R"("class_name" should be used before annotations (except @tool).)");
- }
advance();
if (head->identifier != nullptr) {
push_error(R"("class_name" can only be used once.)");
@@ -585,9 +570,6 @@ void GDScriptParser::parse_program() {
}
break;
case GDScriptTokenizer::Token::EXTENDS:
- if (premature_annotation != nullptr) {
- push_error(R"("extends" should be used before annotations (except @tool).)");
- }
advance();
if (head->extends_used) {
push_error(R"("extends" can only be used once.)");
@@ -597,7 +579,8 @@ void GDScriptParser::parse_program() {
}
break;
default:
- should_break = true;
+ // No tokens are allowed between script annotations and class/extends.
+ can_have_class_or_extends = false;
break;
}
@@ -606,21 +589,6 @@ void GDScriptParser::parse_program() {
}
}
- if (match(GDScriptTokenizer::Token::ANNOTATION)) {
- // Check for a script-level, or standalone annotation.
- AnnotationNode *annotation = parse_annotation(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE | AnnotationInfo::CLASS_LEVEL);
- if (annotation != nullptr) {
- if (annotation->applies_to(AnnotationInfo::SCRIPT | AnnotationInfo::STANDALONE)) {
- if (previous.type != GDScriptTokenizer::Token::NEWLINE) {
- push_error(R"(Expected newline after a standalone annotation.)");
- }
- annotation->apply(this, head);
- } else {
- annotation_stack.push_back(annotation);
- }
- }
- }
-
parse_class_body(true);
complete_extents(head);
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index edb2e8117a..b9e6921034 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -107,6 +107,7 @@ void GDScriptTextDocument::didSave(const Variant &p_param) {
} else {
scr->reload(true);
}
+ scr->update_exports();
ScriptEditor::get_singleton()->update_docs_from_script(scr);
}
}
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index 33b5ae6942..b6feaadccf 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -71,21 +71,18 @@ class EditorExportGDScript : public EditorExportPlugin {
public:
virtual void _export_file(const String &p_path, const String &p_type, const HashSet<String> &p_features) override {
- int script_mode = EditorExportPreset::MODE_SCRIPT_COMPILED;
String script_key;
const Ref<EditorExportPreset> &preset = get_export_preset();
if (preset.is_valid()) {
- script_mode = preset->get_script_export_mode();
script_key = preset->get_script_encryption_key().to_lower();
}
- if (!p_path.ends_with(".gd") || script_mode == EditorExportPreset::MODE_SCRIPT_TEXT) {
+ if (!p_path.ends_with(".gd")) {
return;
}
- // TODO: Re-add compiled GDScript on export.
return;
}
diff --git a/modules/gdscript/tests/README.md b/modules/gdscript/tests/README.md
index 6e54085962..361d586d32 100644
--- a/modules/gdscript/tests/README.md
+++ b/modules/gdscript/tests/README.md
@@ -4,5 +4,5 @@ The `scripts/` folder contains integration tests in the form of GDScript files
and output files.
See the
-[Integration tests for GDScript documentation](https://docs.godotengine.org/en/latest/development/cpp/unit_testing.html#integration-tests-for-gdscript)
+[Integration tests for GDScript documentation](https://docs.godotengine.org/en/latest/contributing/development/core_and_modules/unit_testing.html#integration-tests-for-gdscript)
for information about creating and running GDScript integration tests.
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd
new file mode 100644
index 0000000000..cf56a0a933
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.gd
@@ -0,0 +1,6 @@
+const constant_float = 1.0
+
+func test():
+ for x in constant_float:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out
new file mode 100644
index 0000000000..e309831b3e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_float.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "float" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd
new file mode 100644
index 0000000000..5ee8ac19e1
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.gd
@@ -0,0 +1,6 @@
+const constant_int = 1
+
+func test():
+ for x in constant_int:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out
new file mode 100644
index 0000000000..54c190cf8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_constant_int.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "int" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd
new file mode 100644
index 0000000000..b3db4f3b49
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.gd
@@ -0,0 +1,6 @@
+enum { enum_value = 1 }
+
+func test():
+ for x in enum_value:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out
new file mode 100644
index 0000000000..54c190cf8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_enum_value.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "int" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd
new file mode 100644
index 0000000000..87c54f7402
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.gd
@@ -0,0 +1,6 @@
+func test():
+ var hard_float := 1.0
+
+ for x in hard_float:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out
new file mode 100644
index 0000000000..e309831b3e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_float.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "float" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd
new file mode 100644
index 0000000000..2a43f5a930
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.gd
@@ -0,0 +1,6 @@
+func test():
+ var hard_int := 1
+
+ for x in hard_int:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out
new file mode 100644
index 0000000000..54c190cf8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_int.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "int" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd
new file mode 100644
index 0000000000..c3920d35b3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.gd
@@ -0,0 +1,14 @@
+class Iterator:
+ func _iter_init(_count):
+ return true
+ func _iter_next(_count):
+ return false
+ func _iter_get(_count) -> StringName:
+ return &'custom'
+
+func test():
+ var hard_iterator := Iterator.new()
+
+ for x in hard_iterator:
+ if x is int:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out
new file mode 100644
index 0000000000..a48591a3b4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_iterator.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "StringName" so it can't be of type "int".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd
new file mode 100644
index 0000000000..b36d87aabe
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.gd
@@ -0,0 +1,6 @@
+func test():
+ var hard_string := 'a'
+
+ for x in hard_string:
+ if x is int:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out
new file mode 100644
index 0000000000..92c5ebc599
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_hard_string.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "String" so it can't be of type "int".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd
new file mode 100644
index 0000000000..060a8bedf9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.gd
@@ -0,0 +1,3 @@
+func test():
+ for x in true:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out
new file mode 100644
index 0000000000..94cb038885
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_bool.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Unable to iterate on value of type "bool".
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd
new file mode 100644
index 0000000000..6cfc822482
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.gd
@@ -0,0 +1,4 @@
+func test():
+ for x in 1:
+ if x is String:
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out
new file mode 100644
index 0000000000..54c190cf8a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/for_loop_on_literal_int.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Expression is of type "int" so it can't be of type "String".
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd
new file mode 100644
index 0000000000..f351fc1f7b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.gd
@@ -0,0 +1,7 @@
+enum {
+ V1,
+ V2 = V1,
+}
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out
new file mode 100644
index 0000000000..d73c5eb7cd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/enum_unnamed_depend.out
@@ -0,0 +1 @@
+GDTEST_OK
diff --git a/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd
new file mode 100644
index 0000000000..7b74be6f2c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.gd
@@ -0,0 +1,15 @@
+func test():
+ var variant_int: Variant = 1
+ var weak_int = 1
+
+ for x in variant_int:
+ if x is String:
+ print('never')
+ print(x)
+
+ for x in weak_int:
+ if x is String:
+ print('never')
+ print(x)
+
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out
new file mode 100644
index 0000000000..7677671cfd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/for_loop_on_variant.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+0
+0
+ok
diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd
index 179e454073..0085b3f367 100644
--- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.gd
@@ -1,6 +1,6 @@
-# Error here. `class_name` should be used *before* annotations, not after (except @tool).
-@icon("res://path/to/optional/icon.svg")
+# Error here. Annotations should be used before `class_name`, not after.
class_name HelloWorld
+@icon("res://path/to/optional/icon.svg")
func test():
pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out
index 02b33c8692..a598ff8424 100644
--- a/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out
+++ b/modules/gdscript/tests/scripts/parser/errors/class_name_after_annotation.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-"class_name" should be used before annotations (except @tool).
+Annotation "@icon" is not allowed in this level.
diff --git a/modules/gdscript/tests/scripts/parser/features/class_name.gd b/modules/gdscript/tests/scripts/parser/features/class_name.gd
index 8bd188e247..19009e433d 100644
--- a/modules/gdscript/tests/scripts/parser/features/class_name.gd
+++ b/modules/gdscript/tests/scripts/parser/features/class_name.gd
@@ -1,5 +1,5 @@
-class_name HelloWorld
@icon("res://path/to/optional/icon.svg")
+class_name HelloWorld
func test():
pass
diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd
new file mode 100644
index 0000000000..81355e0255
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.gd
@@ -0,0 +1,51 @@
+const constant_float = 1.0
+const constant_int = 1
+enum { enum_value = 1 }
+
+class Iterator:
+ func _iter_init(_count):
+ return true
+ func _iter_next(_count):
+ return false
+ func _iter_get(_count) -> StringName:
+ return &'custom'
+
+func test():
+ var hard_float := 1.0
+ var hard_int := 1
+ var hard_string := '0'
+ var hard_iterator := Iterator.new()
+
+ var variant_float: Variant = hard_float
+ var variant_int: Variant = hard_int
+ var variant_string: Variant = hard_string
+ var variant_iterator: Variant = hard_iterator
+
+ for i in 1.0:
+ print(typeof(i) == TYPE_FLOAT)
+ for i in 1:
+ print(typeof(i) == TYPE_INT)
+ for i in 'a':
+ print(typeof(i) == TYPE_STRING)
+ for i in Iterator.new():
+ print(typeof(i) == TYPE_STRING_NAME)
+
+ for i in hard_float:
+ print(typeof(i) == TYPE_FLOAT)
+ for i in hard_int:
+ print(typeof(i) == TYPE_INT)
+ for i in hard_string:
+ print(typeof(i) == TYPE_STRING)
+ for i in hard_iterator:
+ print(typeof(i) == TYPE_STRING_NAME)
+
+ for i in variant_float:
+ print(typeof(i) == TYPE_FLOAT)
+ for i in variant_int:
+ print(typeof(i) == TYPE_INT)
+ for i in variant_string:
+ print(typeof(i) == TYPE_STRING)
+ for i in variant_iterator:
+ print(typeof(i) == TYPE_STRING_NAME)
+
+ print('ok')
diff --git a/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out
new file mode 100644
index 0000000000..b3e82d52ef
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/for_loop_iterator_types.out
@@ -0,0 +1,14 @@
+GDTEST_OK
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+true
+ok
diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index f313f4b28f..d7e8141eb1 100644
--- a/modules/gltf/doc_classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
@@ -15,7 +15,7 @@
<param index="2" name="state" type="GLTFState" />
<param index="3" name="flags" type="int" default="0" />
<description>
- Takes a [PackedByteArray] defining a gLTF and returns a [GLTFState] object through the [param state] parameter.
+ Takes a [PackedByteArray] defining a GLTF and imports the data to the given [GLTFState] object through the [param state] parameter.
[b]Note:[/b] The [param base_path] tells [method append_from_buffer] where to find dependencies and can be empty.
</description>
</method>
@@ -26,7 +26,7 @@
<param index="2" name="flags" type="int" default="0" />
<param index="3" name="base_path" type="String" default="&quot;&quot;" />
<description>
- Takes a path to a gLTF file and returns a [GLTFState] object through the [param state] parameter.
+ Takes a path to a GLTF file and imports the data at that file path to the given [GLTFState] object through the [param state] parameter.
[b]Note:[/b] The [param base_path] tells [method append_from_file] where to find dependencies and can be empty.
</description>
</method>
@@ -36,14 +36,14 @@
<param index="1" name="state" type="GLTFState" />
<param index="2" name="flags" type="int" default="0" />
<description>
- Takes a Godot Engine scene node and returns a [GLTFState] object through the [param state] parameter.
+ Takes a Godot Engine scene node and exports it and its descendants to the given [GLTFState] object through the [param state] parameter.
</description>
</method>
<method name="generate_buffer">
<return type="PackedByteArray" />
<param index="0" name="state" type="GLTFState" />
<description>
- Takes a [GLTFState] object through the [param state] parameter and returns a gLTF [PackedByteArray].
+ Takes a [GLTFState] object through the [param state] parameter and returns a GLTF [PackedByteArray].
</description>
</method>
<method name="generate_scene">
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 788a70f640..5634c51c61 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -3124,10 +3124,11 @@ Error GLTFDocument::_parse_images(Ref<GLTFState> p_state, const String &p_base_p
// API for that in Godot, so we'd have to load as a buffer (i.e. embedded in
// the material), so we do this only as fallback.
Ref<Texture2D> texture = ResourceLoader::load(uri);
+ String extension = uri.get_extension().to_lower();
if (texture.is_valid()) {
p_state->images.push_back(texture);
continue;
- } else if (mimetype == "image/png" || mimetype == "image/jpeg") {
+ } else if (mimetype == "image/png" || mimetype == "image/jpeg" || extension == "png" || extension == "jpg" || extension == "jpeg") {
// Fallback to loading as byte array.
// This enables us to support the spec's requirement that we honor mimetype
// regardless of file URI.
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index 67bb99de16..183190460e 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -461,7 +461,7 @@ void GridMapEditor::_delete_selection() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Delete Selection"));
for (int i = selection.begin.x; i <= selection.end.x; i++) {
for (int j = selection.begin.y; j <= selection.end.y; j++) {
@@ -482,7 +482,7 @@ void GridMapEditor::_fill_selection() {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Fill Selection"));
for (int i = selection.begin.x; i <= selection.end.x; i++) {
for (int j = selection.begin.y; j <= selection.end.y; j++) {
@@ -576,7 +576,7 @@ void GridMapEditor::_do_paste() {
rot = node->get_basis_with_orthogonal_index(paste_indicator.orientation);
Vector3 ofs = paste_indicator.current - paste_indicator.click;
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Paste Selection"));
for (const ClipboardItem &item : clipboard_items) {
@@ -664,7 +664,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
} else {
if ((mb->get_button_index() == MouseButton::RIGHT && input_action == INPUT_ERASE) || (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_PAINT)) {
if (set_items.size()) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("GridMap Paint"));
for (const SetItem &si : set_items) {
undo_redo->add_do_method(node, "set_cell_item", si.position, si.new_value, si.new_orientation);
@@ -686,7 +686,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
}
if (mb->get_button_index() == MouseButton::LEFT && input_action == INPUT_SELECT) {
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("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);
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index e39127e0a1..7606465b8a 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -113,6 +113,11 @@ void CSharpLanguage::init() {
BindingsGenerator::handle_cmdline_args(cmdline_args);
#endif
+ GLOBAL_DEF("dotnet/project/assembly_name", "");
+#ifdef TOOLS_ENABLED
+ GLOBAL_DEF("dotnet/project/solution_directory", "");
+#endif
+
gdmono = memnew(GDMono);
gdmono->initialize();
diff --git a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
index 745a8b73f8..db96003baf 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Export/ExportPlugin.cs
@@ -17,6 +17,8 @@ namespace GodotTools.Export
{
public partial class ExportPlugin : EditorExportPlugin
{
+ public override string _GetName() => "C#";
+
private List<string> _tempFolders = new List<string>();
public void RegisterExportSettings()
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index de10c04e31..08147d9f6a 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -411,8 +411,6 @@ namespace GodotTools
_editorSettings = editorInterface.GetEditorSettings();
- GodotSharpDirs.RegisterProjectSettings();
-
_errorDialog = new AcceptDialog();
editorBaseControl.AddChild(_errorDialog);
diff --git a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
index 4e892be55c..7624989092 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Internals/GodotSharpDirs.cs
@@ -48,12 +48,6 @@ namespace GodotTools.Internals
}
}
- public static void RegisterProjectSettings()
- {
- GlobalDef("dotnet/project/assembly_name", "");
- GlobalDef("dotnet/project/solution_directory", "");
- }
-
public static void DetermineProjectLocation()
{
static string DetermineProjectName()
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index c0d88553ad..03cbfda1bd 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -1864,12 +1864,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append("\n" OPEN_BLOCK_L1);
if (getter) {
- p_output.append(INDENT2 "get\n"
-
- // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
- "#pragma warning disable CS0618 // Disable warning about obsolete method\n"
-
- OPEN_BLOCK_L2 INDENT3);
+ p_output.append(INDENT2 "get\n" OPEN_BLOCK_L2 INDENT3);
p_output.append("return ");
p_output.append(getter->proxy_name + "(");
@@ -1884,21 +1879,11 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(itos(p_iprop.index));
}
}
- p_output.append(");\n"
-
- CLOSE_BLOCK_L2
-
- // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
- "#pragma warning restore CS0618\n");
+ p_output.append(");\n" CLOSE_BLOCK_L2);
}
if (setter) {
- p_output.append(INDENT2 "set\n"
-
- // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
- "#pragma warning disable CS0618 // Disable warning about obsolete method\n"
-
- OPEN_BLOCK_L2 INDENT3);
+ p_output.append(INDENT2 "set\n" OPEN_BLOCK_L2 INDENT3);
p_output.append(setter->proxy_name + "(");
if (p_iprop.index != -1) {
@@ -1912,12 +1897,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
p_output.append(itos(p_iprop.index) + ", ");
}
}
- p_output.append("value);\n"
-
- CLOSE_BLOCK_L2
-
- // TODO Remove this once we make accessor methods private/internal (they will no longer be marked as obsolete after that)
- "#pragma warning restore CS0618\n");
+ p_output.append("value);\n" CLOSE_BLOCK_L2);
}
p_output.append(CLOSE_BLOCK_L1);
@@ -3056,12 +3036,10 @@ bool BindingsGenerator::_populate_object_type_interfaces() {
HashMap<StringName, StringName>::Iterator accessor = accessor_methods.find(imethod.cname);
if (accessor) {
- const PropertyInterface *accessor_property = itype.find_property_by_name(accessor->value);
-
- // We only deprecate an accessor method if it's in the same class as the property. It's easier this way, but also
- // we don't know if an accessor method in a different class could have other purposes, so better leave those untouched.
- imethod.is_deprecated = true;
- imethod.deprecation_message = imethod.proxy_name + " is deprecated. Use the " + accessor_property->proxy_name + " property instead.";
+ // We only make internal an accessor method if it's in the same class as the property.
+ // It's easier this way, but also we don't know if an accessor method in a different class
+ // could have other purposes, so better leave those untouched.
+ imethod.is_internal = true;
}
if (itype.class_doc) {
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
index a2916d4ae8..0e46b63b59 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/AABB.cs
@@ -437,48 +437,25 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the <see cref="AABB"/> overlaps with <paramref name="with"/>
/// (i.e. they have at least one point in common).
- ///
- /// If <paramref name="includeBorders"/> is <see langword="true"/>,
- /// they will also be considered overlapping if their borders touch,
- /// even without intersection.
/// </summary>
/// <param name="with">The other <see cref="AABB"/> to check for intersections with.</param>
- /// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>
/// A <see langword="bool"/> for whether or not they are intersecting.
/// </returns>
- public readonly bool Intersects(AABB with, bool includeBorders = false)
+ public readonly bool Intersects(AABB with)
{
- if (includeBorders)
- {
- if (_position.x > with._position.x + with._size.x)
- return false;
- if (_position.x + _size.x < with._position.x)
- return false;
- if (_position.y > with._position.y + with._size.y)
- return false;
- if (_position.y + _size.y < with._position.y)
- return false;
- if (_position.z > with._position.z + with._size.z)
- return false;
- if (_position.z + _size.z < with._position.z)
- return false;
- }
- else
- {
- if (_position.x >= with._position.x + with._size.x)
- return false;
- if (_position.x + _size.x <= with._position.x)
- return false;
- if (_position.y >= with._position.y + with._size.y)
- return false;
- if (_position.y + _size.y <= with._position.y)
- return false;
- if (_position.z >= with._position.z + with._size.z)
- return false;
- if (_position.z + _size.z <= with._position.z)
- return false;
- }
+ if (_position.x >= with._position.x + with._size.x)
+ return false;
+ if (_position.x + _size.x <= with._position.x)
+ return false;
+ if (_position.y >= with._position.y + with._size.y)
+ return false;
+ if (_position.y + _size.y <= with._position.y)
+ return false;
+ if (_position.z >= with._position.z + with._size.z)
+ return false;
+ if (_position.z + _size.z <= with._position.z)
+ return false;
return true;
}
@@ -586,6 +563,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this <see cref="AABB"/> is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return _position.IsFinite() && _size.IsFinite();
+ }
+
+ /// <summary>
/// Returns a larger <see cref="AABB"/> that contains this <see cref="AABB"/> and <paramref name="with"/>.
/// </summary>
/// <param name="with">The other <see cref="AABB"/>.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
index 5d390a298d..b57317e1d0 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Basis.cs
@@ -120,31 +120,6 @@ namespace Godot
}
/// <summary>
- /// The scale of this basis.
- /// </summary>
- /// <value>Equivalent to the lengths of each column vector, but negative if the determinant is negative.</value>
- public Vector3 Scale
- {
- readonly get
- {
- real_t detSign = Mathf.Sign(Determinant());
- return detSign * new Vector3
- (
- Column0.Length(),
- Column1.Length(),
- Column2.Length()
- );
- }
- set
- {
- value /= Scale; // Value becomes what's called "delta_scale" in core.
- Column0 *= value.x;
- Column1 *= value.y;
- Column2 *= value.z;
- }
- }
-
- /// <summary>
/// Access whole columns in the form of <see cref="Vector3"/>.
/// </summary>
/// <param name="column">Which column vector.</param>
@@ -493,12 +468,6 @@ namespace Godot
}
}
- /// <summary>
- /// Returns the basis's rotation in the form of a quaternion.
- /// See <see cref="GetEuler"/> if you need Euler angles, but keep in
- /// mind that quaternions should generally be preferred to Euler angles.
- /// </summary>
- /// <returns>A <see cref="Quaternion"/> representing the basis's rotation.</returns>
internal readonly Quaternion GetQuaternion()
{
real_t trace = Row0[0] + Row1[1] + Row2[2];
@@ -573,106 +542,18 @@ namespace Godot
}
/// <summary>
- /// Get rows by index. Rows are not very useful for user code,
- /// but are more efficient for some internal calculations.
- /// </summary>
- /// <param name="index">Which row.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="index"/> is not 0, 1 or 2.
- /// </exception>
- /// <returns>One of <c>Row0</c>, <c>Row1</c>, or <c>Row2</c>.</returns>
- public readonly Vector3 GetRow(int index)
- {
- switch (index)
- {
- case 0:
- return Row0;
- case 1:
- return Row1;
- case 2:
- return Row2;
- default:
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- }
-
- /// <summary>
- /// Sets rows by index. Rows are not very useful for user code,
- /// but are more efficient for some internal calculations.
+ /// Assuming that the matrix is the combination of a rotation and scaling,
+ /// return the absolute value of scaling factors along each axis.
/// </summary>
- /// <param name="index">Which row.</param>
- /// <param name="value">The vector to set the row to.</param>
- /// <exception cref="ArgumentOutOfRangeException">
- /// <paramref name="index"/> is not 0, 1 or 2.
- /// </exception>
- public void SetRow(int index, Vector3 value)
+ public readonly Vector3 GetScale()
{
- switch (index)
- {
- case 0:
- Row0 = value;
- return;
- case 1:
- Row1 = value;
- return;
- case 2:
- Row2 = value;
- return;
- default:
- throw new ArgumentOutOfRangeException(nameof(index));
- }
- }
-
- /// <summary>
- /// This function considers a discretization of rotations into
- /// 24 points on unit sphere, lying along the vectors (x, y, z) with
- /// each component being either -1, 0, or 1, and returns the index
- /// of the point best representing the orientation of the object.
- /// It is mainly used by the <see cref="GridMap"/> editor.
- ///
- /// For further details, refer to the Godot source code.
- /// </summary>
- /// <returns>The orthogonal index.</returns>
- public readonly int GetOrthogonalIndex()
- {
- var orth = this;
-
- for (int i = 0; i < 3; i++)
- {
- for (int j = 0; j < 3; j++)
- {
- var row = orth.GetRow(i);
-
- real_t v = row[j];
-
- if (v > 0.5f)
- {
- v = 1.0f;
- }
- else if (v < -0.5f)
- {
- v = -1.0f;
- }
- else
- {
- v = 0f;
- }
-
- row[j] = v;
-
- orth.SetRow(i, row);
- }
- }
-
- for (int i = 0; i < 24; i++)
- {
- if (orth == _orthoBases[i])
- {
- return i;
- }
- }
-
- return 0;
+ real_t detSign = Mathf.Sign(Determinant());
+ return detSign * new Vector3
+ (
+ Column0.Length(),
+ Column1.Length(),
+ Column2.Length()
+ );
}
/// <summary>
@@ -709,6 +590,16 @@ namespace Godot
);
}
+ /// <summary>
+ /// Returns <see langword="true"/> if this basis is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Row0.IsFinite() && Row1.IsFinite() && Row2.IsFinite();
+ }
+
internal readonly Basis Lerp(Basis to, real_t weight)
{
Basis b = this;
@@ -896,7 +787,7 @@ namespace Godot
/// <param name="quaternion">The quaternion to create the basis from.</param>
public Basis(Quaternion quaternion)
{
- real_t s = 2.0f / quaternion.LengthSquared;
+ real_t s = 2.0f / quaternion.LengthSquared();
real_t xs = quaternion.x * s;
real_t ys = quaternion.y * s;
@@ -925,26 +816,26 @@ namespace Godot
public Basis(Vector3 axis, real_t angle)
{
Vector3 axisSq = new Vector3(axis.x * axis.x, axis.y * axis.y, axis.z * axis.z);
- real_t cosine = Mathf.Cos(angle);
- Row0.x = axisSq.x + cosine * (1.0f - axisSq.x);
- Row1.y = axisSq.y + cosine * (1.0f - axisSq.y);
- Row2.z = axisSq.z + cosine * (1.0f - axisSq.z);
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+
+ Row0.x = axisSq.x + cos * (1.0f - axisSq.x);
+ Row1.y = axisSq.y + cos * (1.0f - axisSq.y);
+ Row2.z = axisSq.z + cos * (1.0f - axisSq.z);
- real_t sine = Mathf.Sin(angle);
- real_t t = 1.0f - cosine;
+ real_t t = 1.0f - cos;
real_t xyzt = axis.x * axis.y * t;
- real_t zyxs = axis.z * sine;
+ real_t zyxs = axis.z * sin;
Row0.y = xyzt - zyxs;
Row1.x = xyzt + zyxs;
xyzt = axis.x * axis.z * t;
- zyxs = axis.y * sine;
+ zyxs = axis.y * sin;
Row0.z = xyzt + zyxs;
Row2.x = xyzt - zyxs;
xyzt = axis.y * axis.z * t;
- zyxs = axis.x * sine;
+ zyxs = axis.x * sin;
Row1.z = xyzt - zyxs;
Row2.y = xyzt + zyxs;
}
@@ -967,8 +858,20 @@ namespace Godot
// We need to assign the struct fields here first so we can't do it that way...
}
- // Arguments are named such that xy is equal to calling x.y
- internal Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz)
+ /// <summary>
+ /// Constructs a transformation matrix from the given components.
+ /// Arguments are named such that xy is equal to calling <c>x.y</c>.
+ /// </summary>
+ /// <param name="xx">The X component of the X column vector, accessed via <c>b.x.x</c> or <c>[0][0]</c>.</param>
+ /// <param name="yx">The X component of the Y column vector, accessed via <c>b.y.x</c> or <c>[1][0]</c>.</param>
+ /// <param name="zx">The X component of the Z column vector, accessed via <c>b.z.x</c> or <c>[2][0]</c>.</param>
+ /// <param name="xy">The Y component of the X column vector, accessed via <c>b.x.y</c> or <c>[0][1]</c>.</param>
+ /// <param name="yy">The Y component of the Y column vector, accessed via <c>b.y.y</c> or <c>[1][1]</c>.</param>
+ /// <param name="zy">The Y component of the Z column vector, accessed via <c>b.y.y</c> or <c>[2][1]</c>.</param>
+ /// <param name="xz">The Z component of the X column vector, accessed via <c>b.x.y</c> or <c>[0][2]</c>.</param>
+ /// <param name="yz">The Z component of the Y column vector, accessed via <c>b.y.y</c> or <c>[1][2]</c>.</param>
+ /// <param name="zz">The Z component of the Z column vector, accessed via <c>b.y.y</c> or <c>[2][2]</c>.</param>
+ public Basis(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz)
{
Row0 = new Vector3(xx, yx, zx);
Row1 = new Vector3(xy, yy, zy);
@@ -982,19 +885,29 @@ namespace Godot
/// <param name="order">The order to compose the Euler angles.</param>
public static Basis FromEuler(Vector3 euler, EulerOrder order = EulerOrder.Yxz)
{
- real_t c, s;
-
- c = Mathf.Cos(euler.x);
- s = Mathf.Sin(euler.x);
- Basis xmat = new Basis(new Vector3(1, 0, 0), new Vector3(0, c, s), new Vector3(0, -s, c));
+ (real_t sin, real_t cos) = Mathf.SinCos(euler.x);
+ Basis xmat = new Basis
+ (
+ new Vector3(1, 0, 0),
+ new Vector3(0, cos, sin),
+ new Vector3(0, -sin, cos)
+ );
- c = Mathf.Cos(euler.y);
- s = Mathf.Sin(euler.y);
- Basis ymat = new Basis(new Vector3(c, 0, -s), new Vector3(0, 1, 0), new Vector3(s, 0, c));
+ (sin, cos) = Mathf.SinCos(euler.y);
+ Basis ymat = new Basis
+ (
+ new Vector3(cos, 0, -sin),
+ new Vector3(0, 1, 0),
+ new Vector3(sin, 0, cos)
+ );
- c = Mathf.Cos(euler.z);
- s = Mathf.Sin(euler.z);
- Basis zmat = new Basis(new Vector3(c, s, 0), new Vector3(-s, c, 0), new Vector3(0, 0, 1));
+ (sin, cos) = Mathf.SinCos(euler.z);
+ Basis zmat = new Basis
+ (
+ new Vector3(cos, sin, 0),
+ new Vector3(-sin, cos, 0),
+ new Vector3(0, 0, 1)
+ );
switch (order)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
index 4075a878d2..2effdecf40 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Color.cs
@@ -359,24 +359,6 @@ namespace Godot
}
/// <summary>
- /// Returns the result of the linear interpolation between
- /// this color and <paramref name="to"/> by color amount <paramref name="weight"/>.
- /// </summary>
- /// <param name="to">The destination color for interpolation.</param>
- /// <param name="weight">A color with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The resulting color of the interpolation.</returns>
- public readonly Color Lerp(Color to, Color weight)
- {
- return new Color
- (
- (float)Mathf.Lerp(r, to.r, weight.r),
- (float)Mathf.Lerp(g, to.g, weight.g),
- (float)Mathf.Lerp(b, to.b, weight.b),
- (float)Mathf.Lerp(a, to.a, weight.a)
- );
- }
-
- /// <summary>
/// Returns the color converted to the sRGB color space.
/// This method assumes the original color is in the linear color space.
/// See also <see cref="SrgbToLinear"/> which performs the opposite operation.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
index 3f9e986f62..b2cb0f5e6b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Mathf.cs
@@ -440,6 +440,17 @@ namespace Godot
}
/// <summary>
+ /// Returns whether <paramref name="s"/> is a finite value, i.e. it is not
+ /// <see cref="NaN"/>, positive infinite, or negative infinity.
+ /// </summary>
+ /// <param name="s">The value to check.</param>
+ /// <returns>A <see langword="bool"/> for whether or not the value is a finite value.</returns>
+ public static bool IsFinite(real_t s)
+ {
+ return real_t.IsFinite(s);
+ }
+
+ /// <summary>
/// Returns whether <paramref name="s"/> is an infinity value (either positive infinity or negative infinity).
/// </summary>
/// <param name="s">The value to check.</param>
@@ -460,10 +471,11 @@ namespace Godot
}
/// <summary>
- /// Returns <see langword="true"/> if <paramref name="s"/> is approximately zero.
+ /// Returns <see langword="true"/> if <paramref name="s"/> is zero or almost zero.
/// The comparison is done using a tolerance calculation with <see cref="Epsilon"/>.
///
- /// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with one value as zero.
+ /// This method is faster than using <see cref="IsEqualApprox(real_t, real_t)"/> with
+ /// one value as zero.
/// </summary>
/// <param name="s">The value to check.</param>
/// <returns>A <see langword="bool"/> for whether or not the value is nearly zero.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
index ea05c1547c..72a1868964 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/MathfEx.cs
@@ -83,6 +83,17 @@ namespace Godot
}
/// <summary>
+ /// Returns the sine and cosine of angle <paramref name="s"/> in radians.
+ /// </summary>
+ /// <param name="s">The angle in radians.</param>
+ /// <returns>The sine and cosine of that angle.</returns>
+ public static (real_t Sin, real_t Cos) SinCos(real_t s)
+ {
+ (double sin, double cos) = Math.SinCos(s);
+ return ((real_t)sin, (real_t)cos);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if <paramref name="a"/> and <paramref name="b"/> are approximately
/// equal to each other.
/// The comparison is done using the provided tolerance value.
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
index 42c6b0a37e..8a125e3c73 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Plane.cs
@@ -15,7 +15,7 @@ namespace Godot
private Vector3 _normal;
/// <summary>
- /// The normal of the plane, which must be normalized.
+ /// The normal of the plane, which must be a unit vector.
/// In the scalar equation of the plane <c>ax + by + cz = d</c>, this is
/// the vector <c>(a, b, c)</c>, where <c>d</c> is the <see cref="D"/> property.
/// </summary>
@@ -85,23 +85,6 @@ namespace Godot
public real_t D { get; set; }
/// <summary>
- /// The center of the plane, the point where the normal line intersects the plane.
- /// </summary>
- /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value>
- public Vector3 Center
- {
- readonly get
- {
- return _normal * D;
- }
- set
- {
- _normal = value.Normalized();
- D = value.Length();
- }
- }
-
- /// <summary>
/// Returns the shortest distance from this plane to the position <paramref name="point"/>.
/// </summary>
/// <param name="point">The position to use for the calculation.</param>
@@ -112,6 +95,16 @@ namespace Godot
}
/// <summary>
+ /// Returns the center of the plane, the point on the plane closest to the origin.
+ /// The point where the normal line going through the origin intersects the plane.
+ /// </summary>
+ /// <value>Equivalent to <see cref="Normal"/> multiplied by <see cref="D"/>.</value>
+ public readonly Vector3 GetCenter()
+ {
+ return _normal * D;
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if point is inside the plane.
/// Comparison uses a custom minimum tolerance threshold.
/// </summary>
@@ -155,7 +148,7 @@ namespace Godot
/// <param name="from">The start of the ray.</param>
/// <param name="dir">The direction of the ray, normalized.</param>
/// <returns>The intersection, or <see langword="null"/> if none is found.</returns>
- public readonly Vector3? IntersectRay(Vector3 from, Vector3 dir)
+ public readonly Vector3? IntersectsRay(Vector3 from, Vector3 dir)
{
real_t den = _normal.Dot(dir);
@@ -183,7 +176,7 @@ namespace Godot
/// <param name="begin">The start of the line segment.</param>
/// <param name="end">The end of the line segment.</param>
/// <returns>The intersection, or <see langword="null"/> if none is found.</returns>
- public readonly Vector3? IntersectSegment(Vector3 begin, Vector3 end)
+ public readonly Vector3? IntersectsSegment(Vector3 begin, Vector3 end)
{
Vector3 segment = begin - end;
real_t den = _normal.Dot(segment);
@@ -205,6 +198,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this plane is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return _normal.IsFinite() && Mathf.IsFinite(D);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if <paramref name="point"/> is located above the plane.
/// </summary>
/// <param name="point">The point to check.</param>
@@ -280,10 +283,21 @@ namespace Godot
}
/// <summary>
+ /// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector.
+ /// The plane will intersect the origin.
+ /// </summary>
+ /// <param name="normal">The normal of the plane, must be a unit vector.</param>
+ public Plane(Vector3 normal)
+ {
+ _normal = normal;
+ D = 0;
+ }
+
+ /// <summary>
/// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and
/// the plane's distance to the origin <paramref name="d"/>.
/// </summary>
- /// <param name="normal">The normal of the plane, must be normalized.</param>
+ /// <param name="normal">The normal of the plane, must be a unit vector.</param>
/// <param name="d">The plane's distance from the origin. This value is typically non-negative.</param>
public Plane(Vector3 normal, real_t d)
{
@@ -295,7 +309,7 @@ namespace Godot
/// Constructs a <see cref="Plane"/> from a <paramref name="normal"/> vector and
/// a <paramref name="point"/> on the plane.
/// </summary>
- /// <param name="normal">The normal of the plane, must be normalized.</param>
+ /// <param name="normal">The normal of the plane, must be a unit vector.</param>
/// <param name="point">The point on the plane.</param>
public Plane(Vector3 normal, Vector3 point)
{
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
index fd37f8d9e8..f11b3c553a 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Projection.cs
@@ -381,14 +381,14 @@ namespace Godot
}
real_t radians = Mathf.DegToRad(fovyDegrees / (real_t)2.0);
real_t deltaZ = zFar - zNear;
- real_t sine = Mathf.Sin(radians);
+ (real_t sin, real_t cos) = Mathf.SinCos(radians);
- if ((deltaZ == 0) || (sine == 0) || (aspect == 0))
+ if ((deltaZ == 0) || (sin == 0) || (aspect == 0))
{
return Zero;
}
- real_t cotangent = Mathf.Cos(radians) / sine;
+ real_t cotangent = cos / sin;
Projection proj = Projection.Identity;
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
index bd0dea0c1c..8e4f9178f7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Quaternion.cs
@@ -97,27 +97,6 @@ namespace Godot
}
/// <summary>
- /// Returns the length (magnitude) of the quaternion.
- /// </summary>
- /// <seealso cref="LengthSquared"/>
- /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value>
- public readonly real_t Length
- {
- get { return Mathf.Sqrt(LengthSquared); }
- }
-
- /// <summary>
- /// Returns the squared length (squared magnitude) of the quaternion.
- /// This method runs faster than <see cref="Length"/>, so prefer it if
- /// you need to compare quaternions or need the squared length for some formula.
- /// </summary>
- /// <value>Equivalent to <c>Dot(this)</c>.</value>
- public readonly real_t LengthSquared
- {
- get { return Dot(this); }
- }
-
- /// <summary>
/// Returns the angle between this quaternion and <paramref name="to"/>.
/// This is the magnitude of the angle you would need to rotate
/// by to get from one to the other.
@@ -340,12 +319,22 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this quaternion is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z) && Mathf.IsFinite(w);
+ }
+
+ /// <summary>
/// Returns whether the quaternion is normalized or not.
/// </summary>
/// <returns>A <see langword="bool"/> for whether the quaternion is normalized or not.</returns>
public readonly bool IsNormalized()
{
- return Mathf.Abs(LengthSquared - 1) <= Mathf.Epsilon;
+ return Mathf.Abs(LengthSquared() - 1) <= Mathf.Epsilon;
}
public readonly Quaternion Log()
@@ -355,12 +344,33 @@ namespace Godot
}
/// <summary>
+ /// Returns the length (magnitude) of the quaternion.
+ /// </summary>
+ /// <seealso cref="LengthSquared"/>
+ /// <value>Equivalent to <c>Mathf.Sqrt(LengthSquared)</c>.</value>
+ public readonly real_t Length()
+ {
+ return Mathf.Sqrt(LengthSquared());
+ }
+
+ /// <summary>
+ /// Returns the squared length (squared magnitude) of the quaternion.
+ /// This method runs faster than <see cref="Length"/>, so prefer it if
+ /// you need to compare quaternions or need the squared length for some formula.
+ /// </summary>
+ /// <value>Equivalent to <c>Dot(this)</c>.</value>
+ public readonly real_t LengthSquared()
+ {
+ return Dot(this);
+ }
+
+ /// <summary>
/// Returns a copy of the quaternion, normalized to unit length.
/// </summary>
/// <returns>The normalized quaternion.</returns>
public readonly Quaternion Normalized()
{
- return this / Length;
+ return this / Length();
}
/// <summary>
@@ -532,14 +542,13 @@ namespace Godot
}
else
{
- real_t sinAngle = Mathf.Sin(angle * 0.5f);
- real_t cosAngle = Mathf.Cos(angle * 0.5f);
- real_t s = sinAngle / d;
+ (real_t sin, real_t cos) = Mathf.SinCos(angle * 0.5f);
+ real_t s = sin / d;
x = axis.x * s;
y = axis.y * s;
z = axis.z * s;
- w = cosAngle;
+ w = cos;
}
}
@@ -583,12 +592,9 @@ namespace Godot
// Conversion to quaternion as listed in https://ntrs.nasa.gov/archive/nasa/casi.ntrs.nasa.gov/19770024290.pdf (page A-6)
// a3 is the angle of the first rotation, following the notation in this reference.
- real_t cosA1 = Mathf.Cos(halfA1);
- real_t sinA1 = Mathf.Sin(halfA1);
- real_t cosA2 = Mathf.Cos(halfA2);
- real_t sinA2 = Mathf.Sin(halfA2);
- real_t cosA3 = Mathf.Cos(halfA3);
- real_t sinA3 = Mathf.Sin(halfA3);
+ (real_t sinA1, real_t cosA1) = Mathf.SinCos(halfA1);
+ (real_t sinA2, real_t cosA2) = Mathf.SinCos(halfA2);
+ (real_t sinA3, real_t cosA3) = Mathf.SinCos(halfA3);
return new Quaternion(
(sinA1 * cosA2 * sinA3) + (cosA1 * sinA2 * cosA3),
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
index b0e0e75a34..1a8696d3bc 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2.cs
@@ -101,6 +101,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this <see cref="Rect2"/> is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public bool IsFinite()
+ {
+ return _position.IsFinite() && _size.IsFinite();
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if this <see cref="Rect2"/> completely encloses another one.
/// </summary>
/// <param name="b">The other <see cref="Rect2"/> that may be enclosed.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
index faee81a98a..cf8939a859 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Rect2i.cs
@@ -275,38 +275,19 @@ namespace Godot
/// <summary>
/// Returns <see langword="true"/> if the <see cref="Rect2i"/> overlaps with <paramref name="b"/>
/// (i.e. they have at least one point in common).
- ///
- /// If <paramref name="includeBorders"/> is <see langword="true"/>,
- /// they will also be considered overlapping if their borders touch,
- /// even without intersection.
/// </summary>
/// <param name="b">The other <see cref="Rect2i"/> to check for intersections with.</param>
- /// <param name="includeBorders">Whether or not to consider borders.</param>
/// <returns>A <see langword="bool"/> for whether or not they are intersecting.</returns>
- public readonly bool Intersects(Rect2i b, bool includeBorders = false)
+ public readonly bool Intersects(Rect2i b)
{
- if (includeBorders)
- {
- if (_position.x > b._position.x + b._size.x)
- return false;
- if (_position.x + _size.x < b._position.x)
- return false;
- if (_position.y > b._position.y + b._size.y)
- return false;
- if (_position.y + _size.y < b._position.y)
- return false;
- }
- else
- {
- if (_position.x >= b._position.x + b._size.x)
- return false;
- if (_position.x + _size.x <= b._position.x)
- return false;
- if (_position.y >= b._position.y + b._size.y)
- return false;
- if (_position.y + _size.y <= b._position.y)
- return false;
- }
+ if (_position.x >= b._position.x + b._size.x)
+ return false;
+ if (_position.x + _size.x <= b._position.x)
+ return false;
+ if (_position.y >= b._position.y + b._size.y)
+ return false;
+ if (_position.y + _size.y <= b._position.y)
+ return false;
return true;
}
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
index 756f71e5b2..fa060e3a53 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform2D.cs
@@ -32,45 +32,6 @@ namespace Godot
public Vector2 origin;
/// <summary>
- /// The rotation of this transformation matrix.
- /// </summary>
- /// <value>Getting is equivalent to calling <see cref="Mathf.Atan2(real_t, real_t)"/> with the values of <see cref="x"/>.</value>
- public real_t Rotation
- {
- readonly get
- {
- return Mathf.Atan2(x.y, x.x);
- }
- set
- {
- Vector2 scale = Scale;
- x.x = y.y = Mathf.Cos(value);
- x.y = y.x = Mathf.Sin(value);
- y.x *= -1;
- Scale = scale;
- }
- }
-
- /// <summary>
- /// The scale of this transformation matrix.
- /// </summary>
- /// <value>Equivalent to the lengths of each column vector, but Y is negative if the determinant is negative.</value>
- public Vector2 Scale
- {
- readonly get
- {
- real_t detSign = Mathf.Sign(BasisDeterminant());
- return new Vector2(x.Length(), detSign * y.Length());
- }
- set
- {
- value /= Scale; // Value becomes what's called "delta_scale" in core.
- x *= value.x;
- y *= value.y;
- }
- }
-
- /// <summary>
/// Access whole columns in the form of <see cref="Vector2"/>.
/// The third column is the <see cref="origin"/> vector.
/// </summary>
@@ -203,6 +164,23 @@ namespace Godot
}
/// <summary>
+ /// Returns the transform's rotation (in radians).
+ /// </summary>
+ public readonly real_t GetRotation()
+ {
+ return Mathf.Atan2(x.y, x.x);
+ }
+
+ /// <summary>
+ /// Returns the scale.
+ /// </summary>
+ public readonly Vector2 GetScale()
+ {
+ real_t detSign = Mathf.Sign(BasisDeterminant());
+ return new Vector2(x.Length(), detSign * y.Length());
+ }
+
+ /// <summary>
/// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>.
/// </summary>
/// <param name="transform">The other transform.</param>
@@ -210,15 +188,17 @@ namespace Godot
/// <returns>The interpolated transform.</returns>
public readonly Transform2D InterpolateWith(Transform2D transform, real_t weight)
{
- real_t r1 = Rotation;
- real_t r2 = transform.Rotation;
+ real_t r1 = GetRotation();
+ real_t r2 = transform.GetRotation();
- Vector2 s1 = Scale;
- Vector2 s2 = transform.Scale;
+ Vector2 s1 = GetScale();
+ Vector2 s2 = transform.GetScale();
// Slerp rotation
- var v1 = new Vector2(Mathf.Cos(r1), Mathf.Sin(r1));
- var v2 = new Vector2(Mathf.Cos(r2), Mathf.Sin(r2));
+ (real_t sin1, real_t cos1) = Mathf.SinCos(r1);
+ (real_t sin2, real_t cos2) = Mathf.SinCos(r2);
+ var v1 = new Vector2(cos1, sin1);
+ var v2 = new Vector2(cos2, sin2);
real_t dot = v1.Dot(v2);
@@ -235,7 +215,8 @@ namespace Godot
{
real_t angle = weight * Mathf.Acos(dot);
Vector2 v3 = (v2 - (v1 * dot)).Normalized();
- v = (v1 * Mathf.Cos(angle)) + (v3 * Mathf.Sin(angle));
+ (real_t sine, real_t cos) = Mathf.SinCos(angle);
+ v = (v1 * sine) + (v3 * cos);
}
// Extract parameters
@@ -271,6 +252,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this transform is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return x.IsFinite() && y.IsFinite() && origin.IsFinite();
+ }
+
+ /// <summary>
/// Returns the transform with the basis orthogonal (90 degrees),
/// and normalized axis vectors (scale of 1 or -1).
/// </summary>
@@ -423,7 +414,7 @@ namespace Godot
/// <summary>
/// Constructs a transformation matrix from the given components.
- /// Arguments are named such that xy is equal to calling x.y
+ /// Arguments are named such that xy is equal to calling <c>x.y</c>.
/// </summary>
/// <param name="xx">The X component of the X column vector, accessed via <c>t.x.x</c> or <c>[0][0]</c>.</param>
/// <param name="xy">The Y component of the X column vector, accessed via <c>t.x.y</c> or <c>[0][1]</c>.</param>
@@ -446,13 +437,34 @@ namespace Godot
/// <param name="origin">The origin vector, or column index 2.</param>
public Transform2D(real_t rotation, Vector2 origin)
{
- x.x = y.y = Mathf.Cos(rotation);
- x.y = y.x = Mathf.Sin(rotation);
+ (real_t sin, real_t cos) = Mathf.SinCos(rotation);
+ x.x = y.y = cos;
+ x.y = y.x = sin;
y.x *= -1;
this.origin = origin;
}
/// <summary>
+ /// Constructs a transformation matrix from a <paramref name="rotation"/> value,
+ /// <paramref name="scale"/> vector, <paramref name="skew"/> value, and
+ /// <paramref name="origin"/> vector.
+ /// </summary>
+ /// <param name="rotation">The rotation of the new transform, in radians.</param>
+ /// <param name="scale">The scale of the new transform.</param>
+ /// <param name="skew">The skew of the new transform, in radians.</param>
+ /// <param name="origin">The origin vector, or column index 2.</param>
+ public Transform2D(real_t rotation, Vector2 scale, real_t skew, Vector2 origin)
+ {
+ (real_t rotationSin, real_t rotationCos) = Mathf.SinCos(rotation);
+ (real_t rotationSkewSin, real_t rotationSkewCos) = Mathf.SinCos(rotation + skew);
+ x.x = rotationCos * scale.x;
+ y.y = rotationSkewCos * scale.y;
+ y.x = -rotationSkewSin * scale.y;
+ x.y = rotationSin * scale.x;
+ this.origin = origin;
+ }
+
+ /// <summary>
/// Composes these two transformation matrices by multiplying them
/// together. This has the effect of transforming the second transform
/// (the child) by the first transform (the parent).
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
index 39167bd116..6b2475fc59 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Transform3D.cs
@@ -115,16 +115,30 @@ namespace Godot
}
/// <summary>
- /// Interpolates this transform to the other <paramref name="transform"/> by <paramref name="weight"/>.
+ /// Returns a transform interpolated between this transform and another
+ /// <paramref name="transform"/> by a given <paramref name="weight"/>
+ /// (on the range of 0.0 to 1.0).
/// </summary>
/// <param name="transform">The other transform.</param>
/// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
/// <returns>The interpolated transform.</returns>
public readonly Transform3D InterpolateWith(Transform3D transform, real_t weight)
{
- Basis retBasis = basis.Lerp(transform.basis, weight);
- Vector3 retOrigin = origin.Lerp(transform.origin, weight);
- return new Transform3D(retBasis, retOrigin);
+ Vector3 sourceScale = basis.GetScale();
+ Quaternion sourceRotation = basis.GetRotationQuaternion();
+ Vector3 sourceLocation = origin;
+
+ Vector3 destinationScale = transform.basis.GetScale();
+ Quaternion destinationRotation = transform.basis.GetRotationQuaternion();
+ Vector3 destinationLocation = transform.origin;
+
+ var interpolated = new Transform3D();
+ Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized();
+ Vector3 scale = sourceScale.Lerp(destinationScale, weight);
+ interpolated.basis.SetQuaternionScale(quaternion, scale);
+ interpolated.origin = sourceLocation.Lerp(destinationLocation, weight);
+
+ return interpolated;
}
/// <summary>
@@ -140,6 +154,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this transform is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return basis.IsFinite() && origin.IsFinite();
+ }
+
+ /// <summary>
/// Returns a copy of the transform rotated such that its
/// -Z axis (forward) points towards the <paramref name="target"/> position.
///
@@ -223,34 +247,6 @@ namespace Godot
return new Transform3D(basis * tmpBasis, origin);
}
- /// <summary>
- /// Returns a transform spherically interpolated between this transform and
- /// another <paramref name="transform"/> by <paramref name="weight"/>.
- /// </summary>
- /// <param name="transform">The other transform.</param>
- /// <param name="weight">A value on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The interpolated transform.</returns>
- public readonly Transform3D SphericalInterpolateWith(Transform3D transform, real_t weight)
- {
- /* not sure if very "efficient" but good enough? */
-
- Vector3 sourceScale = basis.Scale;
- Quaternion sourceRotation = basis.GetRotationQuaternion();
- Vector3 sourceLocation = origin;
-
- Vector3 destinationScale = transform.basis.Scale;
- Quaternion destinationRotation = transform.basis.GetRotationQuaternion();
- Vector3 destinationLocation = transform.origin;
-
- var interpolated = new Transform3D();
- Quaternion quaternion = sourceRotation.Slerp(destinationRotation, weight).Normalized();
- Vector3 scale = sourceScale.Lerp(destinationScale, weight);
- interpolated.basis.SetQuaternionScale(quaternion, scale);
- interpolated.origin = sourceLocation.Lerp(destinationLocation, weight);
-
- return interpolated;
- }
-
private void SetLookAt(Vector3 eye, Vector3 target, Vector3 up)
{
// Make rotation matrix
@@ -346,15 +342,25 @@ namespace Godot
}
/// <summary>
- /// Constructs a transformation matrix from the given <paramref name="quaternion"/>
- /// and <paramref name="origin"/> vector.
+ /// Constructs a transformation matrix from the given components.
+ /// Arguments are named such that xy is equal to calling <c>basis.x.y</c>.
/// </summary>
- /// <param name="quaternion">The <see cref="Quaternion"/> to create the basis from.</param>
- /// <param name="origin">The origin vector, or column index 3.</param>
- public Transform3D(Quaternion quaternion, Vector3 origin)
+ /// <param name="xx">The X component of the X column vector, accessed via <c>t.basis.x.x</c> or <c>[0][0]</c>.</param>
+ /// <param name="yx">The X component of the Y column vector, accessed via <c>t.basis.y.x</c> or <c>[1][0]</c>.</param>
+ /// <param name="zx">The X component of the Z column vector, accessed via <c>t.basis.z.x</c> or <c>[2][0]</c>.</param>
+ /// <param name="xy">The Y component of the X column vector, accessed via <c>t.basis.x.y</c> or <c>[0][1]</c>.</param>
+ /// <param name="yy">The Y component of the Y column vector, accessed via <c>t.basis.y.y</c> or <c>[1][1]</c>.</param>
+ /// <param name="zy">The Y component of the Z column vector, accessed via <c>t.basis.y.y</c> or <c>[2][1]</c>.</param>
+ /// <param name="xz">The Z component of the X column vector, accessed via <c>t.basis.x.y</c> or <c>[0][2]</c>.</param>
+ /// <param name="yz">The Z component of the Y column vector, accessed via <c>t.basis.y.y</c> or <c>[1][2]</c>.</param>
+ /// <param name="zz">The Z component of the Z column vector, accessed via <c>t.basis.y.y</c> or <c>[2][2]</c>.</param>
+ /// <param name="ox">The X component of the origin vector, accessed via <c>t.origin.x</c> or <c>[2][0]</c>.</param>
+ /// <param name="oy">The Y component of the origin vector, accessed via <c>t.origin.y</c> or <c>[2][1]</c>.</param>
+ /// <param name="oz">The Z component of the origin vector, accessed via <c>t.origin.z</c> or <c>[2][2]</c>.</param>
+ public Transform3D(real_t xx, real_t yx, real_t zx, real_t xy, real_t yy, real_t zy, real_t xz, real_t yz, real_t zz, real_t ox, real_t oy, real_t oz)
{
- basis = new Basis(quaternion);
- this.origin = origin;
+ basis = new Basis(xx, yx, zx, xy, yy, zy, xz, yz, zz);
+ origin = new Vector3(ox, oy, oz);
}
/// <summary>
@@ -370,6 +376,29 @@ namespace Godot
}
/// <summary>
+ /// Constructs a transformation matrix from the given <paramref name="projection"/>
+ /// by trimming the last row of the projection matrix (<c>projection.x.w</c>,
+ /// <c>projection.y.w</c>, <c>projection.z.w</c>, and <c>projection.w.w</c>
+ /// are not copied over).
+ /// </summary>
+ /// <param name="projection">The <see cref="Projection"/> to create the transform from.</param>
+ public Transform3D(Projection projection)
+ {
+ basis = new Basis
+ (
+ projection.x.x, projection.y.x, projection.z.x,
+ projection.x.y, projection.y.y, projection.z.y,
+ projection.x.z, projection.y.z, projection.z.z
+ );
+ origin = new Vector3
+ (
+ projection.w.x,
+ projection.w.y,
+ projection.w.z
+ );
+ }
+
+ /// <summary>
/// Composes these two transformation matrices by multiplying them
/// together. This has the effect of transforming the second transform
/// (the child) by the first transform (the parent).
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
index 4c60080ee9..07cb34cadd 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2.cs
@@ -334,6 +334,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(x) && Mathf.IsFinite(y);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
@@ -380,24 +390,6 @@ namespace Godot
}
/// <summary>
- /// Returns the result of the linear interpolation between
- /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>.
- /// </summary>
- /// <param name="to">The destination vector for interpolation.</param>
- /// <param name="weight">
- /// A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.
- /// </param>
- /// <returns>The resulting vector of the interpolation.</returns>
- public readonly Vector2 Lerp(Vector2 to, Vector2 weight)
- {
- return new Vector2
- (
- Mathf.Lerp(x, to.x, weight.x),
- Mathf.Lerp(y, to.y, weight.y)
- );
- }
-
- /// <summary>
/// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>.
/// </summary>
/// <param name="length">The length to limit to.</param>
@@ -529,11 +521,12 @@ namespace Godot
/// <returns>The rotated vector.</returns>
public readonly Vector2 Rotated(real_t angle)
{
- real_t sine = Mathf.Sin(angle);
- real_t cosi = Mathf.Cos(angle);
- return new Vector2(
- x * cosi - y * sine,
- x * sine + y * cosi);
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+ return new Vector2
+ (
+ x * cos - y * sin,
+ x * sin + y * cos
+ );
}
/// <summary>
@@ -683,7 +676,8 @@ namespace Godot
/// <returns>The resulting vector.</returns>
public static Vector2 FromAngle(real_t angle)
{
- return new Vector2(Mathf.Cos(angle), Mathf.Sin(angle));
+ (real_t sin, real_t cos) = Mathf.SinCos(angle);
+ return new Vector2(cos, sin);
}
/// <summary>
@@ -989,6 +983,18 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
+ {
+ return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y);
+ }
+
+ /// <summary>
/// Serves as the hash function for <see cref="Vector2"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
index 91be548a21..740fedec66 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2i.cs
@@ -95,38 +95,6 @@ namespace Godot
}
/// <summary>
- /// Returns this vector's angle with respect to the X axis, or (1, 0) vector, in radians.
- ///
- /// Equivalent to the result of <see cref="Mathf.Atan2(real_t, real_t)"/> when
- /// called with the vector's <see cref="y"/> and <see cref="x"/> as parameters: <c>Mathf.Atan2(v.y, v.x)</c>.
- /// </summary>
- /// <returns>The angle of this vector, in radians.</returns>
- public readonly real_t Angle()
- {
- return Mathf.Atan2(y, x);
- }
-
- /// <summary>
- /// Returns the angle to the given vector, in radians.
- /// </summary>
- /// <param name="to">The other vector to compare this vector to.</param>
- /// <returns>The angle between the two vectors, in radians.</returns>
- public readonly real_t AngleTo(Vector2i to)
- {
- return Mathf.Atan2(Cross(to), Dot(to));
- }
-
- /// <summary>
- /// Returns the angle between the line connecting the two points and the X axis, in radians.
- /// </summary>
- /// <param name="to">The other vector to compare this vector to.</param>
- /// <returns>The angle between the two vectors, in radians.</returns>
- public readonly real_t AngleToPoint(Vector2i to)
- {
- return Mathf.Atan2(to.y - y, to.x - x);
- }
-
- /// <summary>
/// Returns the aspect ratio of this vector, the ratio of <see cref="x"/> to <see cref="y"/>.
/// </summary>
/// <returns>The <see cref="x"/> component divided by the <see cref="y"/> component.</returns>
@@ -153,48 +121,6 @@ namespace Godot
}
/// <summary>
- /// Returns the cross product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector.</param>
- /// <returns>The cross product vector.</returns>
- public readonly int Cross(Vector2i with)
- {
- return x * with.y - y * with.x;
- }
-
- /// <summary>
- /// Returns the squared distance between this vector and <paramref name="to"/>.
- /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
- /// you need to compare vectors or need the squared distance for some formula.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The squared distance between the two vectors.</returns>
- public readonly int DistanceSquaredTo(Vector2i to)
- {
- return (to - this).LengthSquared();
- }
-
- /// <summary>
- /// Returns the distance between this vector and <paramref name="to"/>.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The distance between the two vectors.</returns>
- public readonly real_t DistanceTo(Vector2i to)
- {
- return (to - this).Length();
- }
-
- /// <summary>
- /// Returns the dot product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector to use.</param>
- /// <returns>The dot product of the two vectors.</returns>
- public readonly int Dot(Vector2i with)
- {
- return x * with.x + y * with.y;
- }
-
- /// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <seealso cref="LengthSquared"/>
@@ -242,38 +168,6 @@ namespace Godot
}
/// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="mod"/>.
- /// </summary>
- /// <param name="mod">A value representing the divisor of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>.
- /// </returns>
- public readonly Vector2i PosMod(int mod)
- {
- Vector2i v = this;
- v.x = Mathf.PosMod(v.x, mod);
- v.y = Mathf.PosMod(v.y, mod);
- return v;
- }
-
- /// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="modv"/>'s components.
- /// </summary>
- /// <param name="modv">A vector representing the divisors of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components.
- /// </returns>
- public readonly Vector2i PosMod(Vector2i modv)
- {
- Vector2i v = this;
- v.x = Mathf.PosMod(v.x, modv.x);
- v.y = Mathf.PosMod(v.y, modv.y);
- return v;
- }
-
- /// <summary>
/// Returns a vector with each component set to one or negative one, depending
/// on the signs of this vector's components, or zero if the component is zero,
/// by calling <see cref="Mathf.Sign(int)"/> on each component.
@@ -287,16 +181,6 @@ namespace Godot
return v;
}
- /// <summary>
- /// Returns a perpendicular vector rotated 90 degrees counter-clockwise
- /// compared to the original, with the same length.
- /// </summary>
- /// <returns>The perpendicular vector.</returns>
- public readonly Vector2i Orthogonal()
- {
- return new Vector2i(y, -x);
- }
-
// Constants
private static readonly Vector2i _zero = new Vector2i(0, 0);
private static readonly Vector2i _one = new Vector2i(1, 1);
@@ -467,7 +351,7 @@ namespace Godot
/// with the components of the given <see langword="int"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(int)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
@@ -490,7 +374,7 @@ namespace Godot
/// with the components of the given <see cref="Vector2i"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(Vector2i)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
@@ -509,34 +393,6 @@ namespace Godot
}
/// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector2i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector2i operator &(Vector2i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector2i"/>
- /// and the given <see cref="Vector2i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector2i operator &(Vector2i vec, Vector2i andv)
- {
- vec.x &= andv.x;
- vec.y &= andv.y;
- return vec;
- }
-
- /// <summary>
/// Returns <see langword="true"/> if the vectors are equal.
/// </summary>
/// <param name="left">The left vector.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
index fefdee33a5..b017ba5853 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3.cs
@@ -331,6 +331,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
@@ -386,23 +396,6 @@ namespace Godot
}
/// <summary>
- /// Returns the result of the linear interpolation between
- /// this vector and <paramref name="to"/> by the vector amount <paramref name="weight"/>.
- /// </summary>
- /// <param name="to">The destination vector for interpolation.</param>
- /// <param name="weight">A vector with components on the range of 0.0 to 1.0, representing the amount of interpolation.</param>
- /// <returns>The resulting vector of the interpolation.</returns>
- public readonly Vector3 Lerp(Vector3 to, Vector3 weight)
- {
- return new Vector3
- (
- Mathf.Lerp(x, to.x, weight.x),
- Mathf.Lerp(y, to.y, weight.y),
- Mathf.Lerp(z, to.z, weight.z)
- );
- }
-
- /// <summary>
/// Returns the vector with a maximum length by limiting its length to <paramref name="length"/>.
/// </summary>
/// <param name="length">The length to limit to.</param>
@@ -1060,6 +1053,18 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
+ {
+ return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y) && Mathf.IsZeroApprox(z);
+ }
+
+ /// <summary>
/// Serves as the hash function for <see cref="Vector3"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
index e631a9f443..de0c6d27e7 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3i.cs
@@ -129,39 +129,6 @@ namespace Godot
}
/// <summary>
- /// Returns the squared distance between this vector and <paramref name="to"/>.
- /// This method runs faster than <see cref="DistanceTo"/>, so prefer it if
- /// you need to compare vectors or need the squared distance for some formula.
- /// </summary>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The squared distance between the two vectors.</returns>
- public readonly int DistanceSquaredTo(Vector3i to)
- {
- return (to - this).LengthSquared();
- }
-
- /// <summary>
- /// Returns the distance between this vector and <paramref name="to"/>.
- /// </summary>
- /// <seealso cref="DistanceSquaredTo(Vector3i)"/>
- /// <param name="to">The other vector to use.</param>
- /// <returns>The distance between the two vectors.</returns>
- public readonly real_t DistanceTo(Vector3i to)
- {
- return (to - this).Length();
- }
-
- /// <summary>
- /// Returns the dot product of this vector and <paramref name="with"/>.
- /// </summary>
- /// <param name="with">The other vector to use.</param>
- /// <returns>The dot product of the two vectors.</returns>
- public readonly int Dot(Vector3i with)
- {
- return x * with.x + y * with.y + z * with.z;
- }
-
- /// <summary>
/// Returns the length (magnitude) of this vector.
/// </summary>
/// <seealso cref="LengthSquared"/>
@@ -211,40 +178,6 @@ namespace Godot
}
/// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="mod"/>.
- /// </summary>
- /// <param name="mod">A value representing the divisor of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="mod"/>.
- /// </returns>
- public readonly Vector3i PosMod(int mod)
- {
- Vector3i v = this;
- v.x = Mathf.PosMod(v.x, mod);
- v.y = Mathf.PosMod(v.y, mod);
- v.z = Mathf.PosMod(v.z, mod);
- return v;
- }
-
- /// <summary>
- /// Returns a vector composed of the <see cref="Mathf.PosMod(int, int)"/> of this vector's components
- /// and <paramref name="modv"/>'s components.
- /// </summary>
- /// <param name="modv">A vector representing the divisors of the operation.</param>
- /// <returns>
- /// A vector with each component <see cref="Mathf.PosMod(int, int)"/> by <paramref name="modv"/>'s components.
- /// </returns>
- public readonly Vector3i PosMod(Vector3i modv)
- {
- Vector3i v = this;
- v.x = Mathf.PosMod(v.x, modv.x);
- v.y = Mathf.PosMod(v.y, modv.y);
- v.z = Mathf.PosMod(v.z, modv.z);
- return v;
- }
-
- /// <summary>
/// Returns a vector with each component set to one or negative one, depending
/// on the signs of this vector's components, or zero if the component is zero,
/// by calling <see cref="Mathf.Sign(int)"/> on each component.
@@ -455,7 +388,7 @@ namespace Godot
/// with the components of the given <see langword="int"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(int)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
@@ -479,7 +412,7 @@ namespace Godot
/// with the components of the given <see cref="Vector3i"/>.
/// This operation uses truncated division, which is often not desired
/// as it does not work well with negative numbers.
- /// Consider using <see cref="PosMod(Vector3i)"/> instead
+ /// Consider using <see cref="Mathf.PosMod(int, int)"/> instead
/// if you want to handle negative numbers.
/// </summary>
/// <example>
@@ -499,36 +432,6 @@ namespace Godot
}
/// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector3i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector3i operator &(Vector3i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- vec.z &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector3i"/>
- /// and the given <see cref="Vector3i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector3i operator &(Vector3i vec, Vector3i andv)
- {
- vec.x &= andv.x;
- vec.y &= andv.y;
- vec.z &= andv.z;
- return vec;
- }
-
- /// <summary>
/// Returns <see langword="true"/> if the vectors are equal.
/// </summary>
/// <param name="left">The left vector.</param>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
index 3191e8adc0..0f4528bb40 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4.cs
@@ -280,6 +280,16 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector is finite, by calling
+ /// <see cref="Mathf.IsFinite"/> on each component.
+ /// </summary>
+ /// <returns>Whether this vector is finite or not.</returns>
+ public readonly bool IsFinite()
+ {
+ return Mathf.IsFinite(x) && Mathf.IsFinite(y) && Mathf.IsFinite(z) && Mathf.IsFinite(w);
+ }
+
+ /// <summary>
/// Returns <see langword="true"/> if the vector is normalized, and <see langword="false"/> otherwise.
/// </summary>
/// <returns>A <see langword="bool"/> indicating whether or not the vector is normalized.</returns>
@@ -857,6 +867,18 @@ namespace Godot
}
/// <summary>
+ /// Returns <see langword="true"/> if this vector's values are approximately zero,
+ /// by running <see cref="Mathf.IsZeroApprox(real_t)"/> on each component.
+ /// This method is faster than using <see cref="IsEqualApprox"/> with one value
+ /// as a zero vector.
+ /// </summary>
+ /// <returns>Whether or not the vector is approximately zero.</returns>
+ public readonly bool IsZeroApprox()
+ {
+ return Mathf.IsZeroApprox(x) && Mathf.IsZeroApprox(y) && Mathf.IsZeroApprox(z) && Mathf.IsZeroApprox(w);
+ }
+
+ /// <summary>
/// Serves as the hash function for <see cref="Vector4"/>.
/// </summary>
/// <returns>A hash code for this vector.</returns>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
index 8146991fd7..00ecc64856 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4i.cs
@@ -433,38 +433,6 @@ namespace Godot
}
/// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector4i"/>
- /// and the given <see langword="int"/>.
- /// </summary>
- /// <param name="vec">The vector to AND with.</param>
- /// <param name="and">The integer to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector4i operator &(Vector4i vec, int and)
- {
- vec.x &= and;
- vec.y &= and;
- vec.z &= and;
- vec.w &= and;
- return vec;
- }
-
- /// <summary>
- /// Performs a bitwise AND operation with this <see cref="Vector4i"/>
- /// and the given <see cref="Vector4i"/>.
- /// </summary>
- /// <param name="vec">The left vector to AND with.</param>
- /// <param name="andv">The right vector to AND with.</param>
- /// <returns>The result of the bitwise AND.</returns>
- public static Vector4i operator &(Vector4i vec, Vector4i andv)
- {
- vec.x &= andv.x;
- vec.y &= andv.y;
- vec.z &= andv.z;
- vec.w &= andv.w;
- return vec;
- }
-
- /// <summary>
/// Returns <see langword="true"/> if the vectors are equal.
/// </summary>
/// <param name="left">The left vector.</param>
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 4ab41cfcb0..66e12a338a 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -142,7 +142,7 @@ void ReplicationEditor::_add_sync_property(String p_path) {
return;
}
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_singleton()->get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Add property to synchronizer"));
if (config.is_null()) {
@@ -250,14 +250,12 @@ ReplicationEditor::ReplicationEditor() {
tree->add_child(drop_label);
drop_label->set_anchors_and_offsets_preset(Control::PRESET_FULL_RECT);
- tree->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_CDU(tree, ReplicationEditor);
}
void ReplicationEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_update_config"), &ReplicationEditor::_update_config);
ClassDB::bind_method(D_METHOD("_update_checked", "property", "column", "checked"), &ReplicationEditor::_update_checked);
- ClassDB::bind_method("_can_drop_data_fw", &ReplicationEditor::_can_drop_data_fw);
- ClassDB::bind_method("_drop_data_fw", &ReplicationEditor::_drop_data_fw);
}
bool ReplicationEditor::_can_drop_data_fw(const Point2 &p_point, const Variant &p_data, Control *p_from) const {
@@ -357,7 +355,7 @@ void ReplicationEditor::_tree_item_edited() {
int column = tree->get_edited_column();
ERR_FAIL_COND(column < 1 || column > 2);
const NodePath prop = ti->get_metadata(0);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
bool value = ti->is_checked(column);
String method;
if (column == 1) {
@@ -397,7 +395,7 @@ void ReplicationEditor::_dialog_closed(bool p_confirmed) {
int idx = config->property_get_index(prop);
bool spawn = config->property_get_spawn(prop);
bool sync = config->property_get_sync(prop);
- Ref<EditorUndoRedoManager> &undo_redo = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Remove Property"));
undo_redo->add_do_method(config.ptr(), "remove_property", prop);
undo_redo->add_undo_method(config.ptr(), "add_property", prop, idx);
diff --git a/modules/multiplayer/multiplayer_spawner.cpp b/modules/multiplayer/multiplayer_spawner.cpp
index 7ed69a84d0..0aa54b69f9 100644
--- a/modules/multiplayer/multiplayer_spawner.cpp
+++ b/modules/multiplayer/multiplayer_spawner.cpp
@@ -199,10 +199,6 @@ void MultiplayerSpawner::_notification(int p_what) {
Node *node = Object::cast_to<Node>(ObjectDB::get_instance(E.key));
ERR_CONTINUE(!node);
node->disconnect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit));
- // This is unlikely, but might still crash the engine.
- if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready))) {
- node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready));
- }
get_multiplayer()->object_configuration_remove(node, this);
}
tracked_nodes.clear();
@@ -244,11 +240,11 @@ void MultiplayerSpawner::_track(Node *p_node, const Variant &p_argument, int p_s
if (!tracked_nodes.has(oid)) {
tracked_nodes[oid] = SpawnInfo(p_argument.duplicate(true), p_scene_id);
p_node->connect(SceneStringNames::get_singleton()->tree_exiting, callable_mp(this, &MultiplayerSpawner::_node_exit).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT);
- p_node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &MultiplayerSpawner::_node_ready).bind(p_node->get_instance_id()), CONNECT_ONE_SHOT);
+ _spawn_notify(p_node->get_instance_id());
}
}
-void MultiplayerSpawner::_node_ready(ObjectID p_id) {
+void MultiplayerSpawner::_spawn_notify(ObjectID p_id) {
get_multiplayer()->object_configuration_add(ObjectDB::get_instance(p_id), this);
}
diff --git a/modules/multiplayer/multiplayer_spawner.h b/modules/multiplayer/multiplayer_spawner.h
index 8d401a6818..8a54140e32 100644
--- a/modules/multiplayer/multiplayer_spawner.h
+++ b/modules/multiplayer/multiplayer_spawner.h
@@ -77,7 +77,7 @@ private:
void _track(Node *p_node, const Variant &p_argument, int p_scene_id = INVALID_ID);
void _node_added(Node *p_node);
void _node_exit(ObjectID p_id);
- void _node_ready(ObjectID p_id);
+ void _spawn_notify(ObjectID p_id);
Vector<String> _get_spawnable_scenes() const;
void _set_spawnable_scenes(const Vector<String> &p_scenes);
diff --git a/modules/multiplayer/scene_replication_interface.cpp b/modules/multiplayer/scene_replication_interface.cpp
index e1b7b0c346..233ff76c7d 100644
--- a/modules/multiplayer/scene_replication_interface.cpp
+++ b/modules/multiplayer/scene_replication_interface.cpp
@@ -125,6 +125,20 @@ void SceneReplicationInterface::on_reset() {
}
void SceneReplicationInterface::on_network_process() {
+ // Prevent endless stalling in case of unforseen spawn errors.
+ if (spawn_queue.size()) {
+ ERR_PRINT("An error happened during last spawn, this usually means the 'ready' signal was not emitted by the spawned node.");
+ for (const ObjectID &oid : spawn_queue) {
+ Node *node = get_id_as<Node>(oid);
+ ERR_CONTINUE(!node);
+ if (node->is_connected(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready))) {
+ node->disconnect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready));
+ }
+ }
+ spawn_queue.clear();
+ }
+
+ // Process timed syncs.
uint64_t msec = OS::get_singleton()->get_ticks_msec();
for (KeyValue<int, PeerInfo> &E : peers_info) {
const HashSet<ObjectID> to_sync = E.value.sync_nodes;
@@ -144,17 +158,39 @@ Error SceneReplicationInterface::on_spawn(Object *p_obj, Variant p_config) {
// Track node.
const ObjectID oid = node->get_instance_id();
TrackedNode &tobj = _track(oid);
+
+ // Spawn state needs to be callected after "ready", but the spawn order follows "enter_tree".
ERR_FAIL_COND_V(tobj.spawner != ObjectID(), ERR_ALREADY_IN_USE);
tobj.spawner = spawner->get_instance_id();
- spawned_nodes.insert(oid);
+ spawn_queue.insert(oid);
+ node->connect(SceneStringNames::get_singleton()->ready, callable_mp(this, &SceneReplicationInterface::_node_ready).bind(oid), Node::CONNECT_ONE_SHOT);
+ return OK;
+}
+
+void SceneReplicationInterface::_node_ready(const ObjectID &p_oid) {
+ ERR_FAIL_COND(!spawn_queue.has(p_oid)); // Bug.
- if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) {
- if (tobj.net_id == 0) {
- tobj.net_id = ++last_net_id;
+ // If we are a nested spawn, we need to wait until the parent is ready.
+ if (p_oid != *(spawn_queue.begin())) {
+ return;
+ }
+
+ for (const ObjectID &oid : spawn_queue) {
+ ERR_CONTINUE(!tracked_nodes.has(oid));
+
+ TrackedNode &tobj = tracked_nodes[oid];
+ MultiplayerSpawner *spawner = get_id_as<MultiplayerSpawner>(tobj.spawner);
+ ERR_CONTINUE(!spawner);
+
+ spawned_nodes.insert(oid);
+ if (multiplayer->has_multiplayer_peer() && spawner->is_multiplayer_authority()) {
+ if (tobj.net_id == 0) {
+ tobj.net_id = ++last_net_id;
+ }
+ _update_spawn_visibility(0, oid);
}
- _update_spawn_visibility(0, oid);
}
- return OK;
+ spawn_queue.clear();
}
Error SceneReplicationInterface::on_despawn(Object *p_obj, Variant p_config) {
diff --git a/modules/multiplayer/scene_replication_interface.h b/modules/multiplayer/scene_replication_interface.h
index a5e610cff6..cf45db2138 100644
--- a/modules/multiplayer/scene_replication_interface.h
+++ b/modules/multiplayer/scene_replication_interface.h
@@ -51,7 +51,6 @@ private:
bool operator==(const ObjectID &p_other) { return id == p_other; }
- _FORCE_INLINE_ MultiplayerSpawner *get_spawner() const { return spawner.is_valid() ? Object::cast_to<MultiplayerSpawner>(ObjectDB::get_instance(spawner)) : nullptr; }
TrackedNode() {}
TrackedNode(const ObjectID &p_id) { id = p_id; }
TrackedNode(const ObjectID &p_id, uint32_t p_net_id) {
@@ -75,7 +74,10 @@ private:
HashSet<ObjectID> spawned_nodes;
HashSet<ObjectID> sync_nodes;
- // Pending spawn information.
+ // Pending local spawn information (handles spawning nested nodes during ready).
+ HashSet<ObjectID> spawn_queue;
+
+ // Pending remote spawn information.
ObjectID pending_spawn;
int pending_spawn_remote = 0;
const uint8_t *pending_buffer = nullptr;
@@ -89,6 +91,7 @@ private:
TrackedNode &_track(const ObjectID &p_id);
void _untrack(const ObjectID &p_id);
+ void _node_ready(const ObjectID &p_oid);
void _send_sync(int p_peer, const HashSet<ObjectID> p_synchronizers, uint16_t p_sync_net_time, uint64_t p_msec);
Error _make_spawn_packet(Node *p_node, MultiplayerSpawner *p_spawner, int &r_len);
diff --git a/modules/ogg/ogg_packet_sequence.cpp b/modules/ogg/ogg_packet_sequence.cpp
index 0acaaf5fc9..d473f3b4a0 100644
--- a/modules/ogg/ogg_packet_sequence.cpp
+++ b/modules/ogg/ogg_packet_sequence.cpp
@@ -136,6 +136,8 @@ bool OggPacketSequencePlayback::next_ogg_packet(ogg_packet **p_packet) const {
ERR_FAIL_COND_V(data_version != ogg_packet_sequence->data_version, false);
ERR_FAIL_COND_V(ogg_packet_sequence->page_data.is_empty(), false);
ERR_FAIL_COND_V(ogg_packet_sequence->page_granule_positions.is_empty(), false);
+ ERR_FAIL_COND_V(page_cursor >= ogg_packet_sequence->page_data.size(), false);
+
// Move on to the next page if need be. This happens first to help simplify seek logic.
while (packet_cursor >= ogg_packet_sequence->page_data[page_cursor].size()) {
packet_cursor = 0;
diff --git a/modules/openxr/editor/openxr_action_editor.cpp b/modules/openxr/editor/openxr_action_editor.cpp
index e3fe06c6f7..586b0b0697 100644
--- a/modules/openxr/editor/openxr_action_editor.cpp
+++ b/modules/openxr/editor/openxr_action_editor.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "openxr_action_editor.h"
-#include "editor/editor_node.h"
void OpenXRActionEditor::_bind_methods() {
ClassDB::bind_method(D_METHOD("_do_set_name", "name"), &OpenXRActionEditor::_do_set_name);
@@ -125,7 +124,7 @@ void OpenXRActionEditor::_on_remove_action() {
}
OpenXRActionEditor::OpenXRActionEditor(Ref<OpenXRAction> p_action) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
action = p_action;
set_h_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/modules/openxr/editor/openxr_action_editor.h b/modules/openxr/editor/openxr_action_editor.h
index 8af5448aed..765b3ef378 100644
--- a/modules/openxr/editor/openxr_action_editor.h
+++ b/modules/openxr/editor/openxr_action_editor.h
@@ -43,7 +43,7 @@ class OpenXRActionEditor : public HBoxContainer {
GDCLASS(OpenXRActionEditor, HBoxContainer);
private:
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
Ref<OpenXRAction> action;
LineEdit *action_name = nullptr;
diff --git a/modules/openxr/editor/openxr_action_map_editor.cpp b/modules/openxr/editor/openxr_action_map_editor.cpp
index 12c95f8978..ad5a515a01 100644
--- a/modules/openxr/editor/openxr_action_map_editor.cpp
+++ b/modules/openxr/editor/openxr_action_map_editor.cpp
@@ -387,7 +387,7 @@ void OpenXRActionMapEditor::_clear_action_map() {
}
OpenXRActionMapEditor::OpenXRActionMapEditor() {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
set_custom_minimum_size(Size2(0.0, 300.0));
top_hb = memnew(HBoxContainer);
diff --git a/modules/openxr/editor/openxr_action_map_editor.h b/modules/openxr/editor/openxr_action_map_editor.h
index 47bfda3425..a04bae4a6e 100644
--- a/modules/openxr/editor/openxr_action_map_editor.h
+++ b/modules/openxr/editor/openxr_action_map_editor.h
@@ -48,7 +48,7 @@ class OpenXRActionMapEditor : public VBoxContainer {
GDCLASS(OpenXRActionMapEditor, VBoxContainer);
private:
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
String edited_path;
Ref<OpenXRActionMap> action_map;
diff --git a/modules/openxr/editor/openxr_action_set_editor.cpp b/modules/openxr/editor/openxr_action_set_editor.cpp
index 078d83f5f2..bcb0f5f8b1 100644
--- a/modules/openxr/editor/openxr_action_set_editor.cpp
+++ b/modules/openxr/editor/openxr_action_set_editor.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "openxr_action_set_editor.h"
-#include "editor/editor_node.h"
#include "openxr_action_editor.h"
void OpenXRActionSetEditor::_bind_methods() {
@@ -212,7 +211,7 @@ void OpenXRActionSetEditor::set_focus_on_entry() {
}
OpenXRActionSetEditor::OpenXRActionSetEditor(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRActionSet> p_action_set) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
action_map = p_action_map;
action_set = p_action_set;
diff --git a/modules/openxr/editor/openxr_action_set_editor.h b/modules/openxr/editor/openxr_action_set_editor.h
index 6040f7fb4e..129f800abe 100644
--- a/modules/openxr/editor/openxr_action_set_editor.h
+++ b/modules/openxr/editor/openxr_action_set_editor.h
@@ -44,7 +44,7 @@ class OpenXRActionSetEditor : public HBoxContainer {
GDCLASS(OpenXRActionSetEditor, HBoxContainer);
private:
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
Ref<OpenXRActionMap> action_map;
Ref<OpenXRActionSet> action_set;
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.cpp b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
index 76b0ae5a3c..6a848dd430 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.cpp
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.cpp
@@ -29,7 +29,6 @@
/**************************************************************************/
#include "openxr_interaction_profile_editor.h"
-#include "editor/editor_node.h"
#include "scene/gui/box_container.h"
#include "scene/gui/button.h"
#include "scene/gui/label.h"
@@ -141,7 +140,7 @@ void OpenXRInteractionProfileEditorBase::remove_all_bindings_for_action(Ref<Open
}
OpenXRInteractionProfileEditorBase::OpenXRInteractionProfileEditorBase(Ref<OpenXRActionMap> p_action_map, Ref<OpenXRInteractionProfile> p_interaction_profile) {
- undo_redo = EditorNode::get_undo_redo();
+ undo_redo = EditorUndoRedoManager::get_singleton();
action_map = p_action_map;
interaction_profile = p_interaction_profile;
diff --git a/modules/openxr/editor/openxr_interaction_profile_editor.h b/modules/openxr/editor/openxr_interaction_profile_editor.h
index 73dba71cbd..fa25a000a9 100644
--- a/modules/openxr/editor/openxr_interaction_profile_editor.h
+++ b/modules/openxr/editor/openxr_interaction_profile_editor.h
@@ -43,7 +43,7 @@ class OpenXRInteractionProfileEditorBase : public ScrollContainer {
GDCLASS(OpenXRInteractionProfileEditorBase, ScrollContainer);
protected:
- Ref<EditorUndoRedoManager> undo_redo;
+ EditorUndoRedoManager *undo_redo;
Ref<OpenXRInteractionProfile> interaction_profile;
Ref<OpenXRActionMap> action_map;
diff --git a/modules/openxr/extensions/openxr_opengl_extension.cpp b/modules/openxr/extensions/openxr_opengl_extension.cpp
index 6ce8f0805f..0d201161f1 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.cpp
+++ b/modules/openxr/extensions/openxr_opengl_extension.cpp
@@ -158,12 +158,14 @@ void *OpenXROpenGLExtension::set_session_create_and_get_next_pointer(void *p_nex
void OpenXROpenGLExtension::get_usable_swapchain_formats(Vector<int64_t> &p_usable_swap_chains) {
p_usable_swap_chains.push_back(GL_RGBA8);
+ p_usable_swap_chains.push_back(GL_SRGB8_ALPHA8);
}
void OpenXROpenGLExtension::get_usable_depth_formats(Vector<int64_t> &p_usable_depth_formats) {
p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT32F);
p_usable_depth_formats.push_back(GL_DEPTH24_STENCIL8);
p_usable_depth_formats.push_back(GL_DEPTH32F_STENCIL8);
+ p_usable_depth_formats.push_back(GL_DEPTH_COMPONENT24);
}
bool OpenXROpenGLExtension::get_swapchain_image_data(XrSwapchain p_swapchain, int64_t p_swapchain_format, uint32_t p_width, uint32_t p_height, uint32_t p_sample_count, uint32_t p_array_size, void **r_swapchain_graphics_data) {
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index d556f475d2..6b8f140923 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -560,6 +560,12 @@ void OpenXRAPI::destroy_instance() {
instance = XR_NULL_HANDLE;
}
enabled_extensions.clear();
+
+ if (graphics_extension != nullptr) {
+ unregister_extension_wrapper(graphics_extension);
+ memdelete(graphics_extension);
+ graphics_extension = nullptr;
+ }
}
bool OpenXRAPI::create_session() {
@@ -1347,6 +1353,10 @@ void OpenXRAPI::register_extension_wrapper(OpenXRExtensionWrapper *p_extension_w
registered_extension_wrappers.push_back(p_extension_wrapper);
}
+void OpenXRAPI::unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper) {
+ registered_extension_wrappers.erase(p_extension_wrapper);
+}
+
void OpenXRAPI::register_extension_metadata() {
for (OpenXRExtensionWrapper *extension_wrapper : registered_extension_wrappers) {
extension_wrapper->on_register_metadata();
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 5fb8de660e..52a1af5a09 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -312,6 +312,7 @@ public:
void set_xr_interface(OpenXRInterface *p_xr_interface);
static void register_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper);
+ static void unregister_extension_wrapper(OpenXRExtensionWrapper *p_extension_wrapper);
static void register_extension_metadata();
static void cleanup_extension_wrappers();
diff --git a/modules/openxr/register_types.cpp b/modules/openxr/register_types.cpp
index 4e2fe3dab5..1c4d53c43a 100644
--- a/modules/openxr/register_types.cpp
+++ b/modules/openxr/register_types.cpp
@@ -111,6 +111,10 @@ void initialize_openxr_module(ModuleInitializationLevel p_level) {
ERR_FAIL_NULL(openxr_api);
if (!openxr_api->initialize(Main::get_rendering_driver_name())) {
+ OS::get_singleton()->alert("OpenXR was requested but failed to start.\n"
+ "Please check if your HMD is connected.\n"
+ "When using Windows MR please note that WMR only has DirectX support, make sure SteamVR is your default OpenXR runtime.\n"
+ "Godot will start in normal mode.\n");
memdelete(openxr_api);
openxr_api = nullptr;
return;
diff --git a/modules/raycast/SCsub b/modules/raycast/SCsub
index 37c8a95905..209ebab388 100644
--- a/modules/raycast/SCsub
+++ b/modules/raycast/SCsub
@@ -96,7 +96,7 @@ if env["builtin_embree"]:
if not env.msvc:
# Flags synced with upstream gnu.cmake.
- if env["arch"] == "arm64" and env["platform"] == "linuxbsd":
+ if env["arch"] == "arm64" and env["platform"] == "linuxbsd" and not env["use_llvm"]:
env_thirdparty.Append(CXXFLAGS=["-flax-vector-conversions"])
env_thirdparty.Append(
diff --git a/modules/text_server_adv/text_server_adv.cpp b/modules/text_server_adv/text_server_adv.cpp
index e52b87741e..79ca4a7024 100644
--- a/modules/text_server_adv/text_server_adv.cpp
+++ b/modules/text_server_adv/text_server_adv.cpp
@@ -423,11 +423,7 @@ bool TextServerAdvanced::_load_support_data(const String &p_filename) {
return false;
}
uint64_t len = f->get_length();
-#ifdef GDEXTENSION
PackedByteArray icu_data = f->get_buffer(len);
-#else
- PackedByteArray icu_data = f->_get_buffer(len);
-#endif
UErrorCode err = U_ZERO_ERROR;
udata_setCommonData(icu_data.ptr(), &err);
@@ -476,11 +472,7 @@ bool TextServerAdvanced::_save_support_data(const String &p_filename) const {
PackedByteArray icu_data;
icu_data.resize(U_ICUDATA_SIZE);
memcpy(icu_data.ptrw(), U_ICUDATA_ENTRY_POINT, U_ICUDATA_SIZE);
-#ifdef GDEXTENSION
f->store_buffer(icu_data);
-#else
- f->_store_buffer(icu_data);
-#endif
return true;
#else
@@ -824,29 +816,17 @@ _FORCE_INLINE_ TextServerAdvanced::FontTexturePosition TextServerAdvanced::find_
// Could not find texture to fit, create one.
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(texsize);
-#else
texsize = next_power_of_2(texsize);
-#endif
if (p_msdf) {
texsize = MIN(texsize, 2048);
} else {
texsize = MIN(texsize, 1024);
}
if (mw > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(mw);
-#else
texsize = next_power_of_2(mw);
-#endif
}
if (mh > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(mh);
-#else
texsize = next_power_of_2(mh);
-#endif
}
ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
@@ -949,14 +929,14 @@ static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, con
return 0;
}
-void TextServerAdvanced::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
+void TextServerAdvanced::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
- int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
+ int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;
for (int col = 0; col < td->output->width(); ++col) {
- int x = (y % 2) ? td->output->width() - col - 1 : col;
- msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5));
+ int x = (p_y % 2) ? td->output->width() - col - 1 : col;
+ msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));
msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
}
@@ -1026,14 +1006,8 @@ _FORCE_INLINE_ TextServerAdvanced::FontGlyph TextServerAdvanced::rasterize_msdf(
td.projection = &projection;
td.distancePixelConversion = &distancePixelConversion;
-#ifdef GDEXTENSION
- for (int i = 0; i < h; i++) {
- _generateMTSDF_threaded(i, &td);
- }
-#else
- WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, SNAME("FontServerRasterizeMSDF"));
+ WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerAdvanced::_generateMTSDF_threaded, &td, h, -1, true, String("FontServerRasterizeMSDF"));
WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
-#endif
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
@@ -3680,6 +3654,7 @@ void TextServerAdvanced::full_copy(ShapedTextDataAdvanced *p_shaped) {
RID TextServerAdvanced::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
ShapedTextDataAdvanced *sd = memnew(ShapedTextDataAdvanced);
sd->hb_buffer = hb_buffer_create();
@@ -3705,6 +3680,7 @@ void TextServerAdvanced::_shaped_text_clear(const RID &p_shaped) {
void TextServerAdvanced::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
ShapedTextDataAdvanced *sd = shaped_owner.get_or_null(p_shaped);
+ ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
ERR_FAIL_COND(!sd);
MutexLock lock(sd->mutex);
@@ -3764,8 +3740,12 @@ void TextServerAdvanced::_shaped_text_set_bidi_override(const RID &p_shaped, con
}
sd->bidi_override.clear();
for (int i = 0; i < p_override.size(); i++) {
- if (p_override[i].get_type() == Variant::VECTOR2I) {
- sd->bidi_override.push_back(p_override[i]);
+ if (p_override[i].get_type() == Variant::VECTOR3I) {
+ const Vector3i &r = p_override[i];
+ sd->bidi_override.push_back(r);
+ } else if (p_override[i].get_type() == Variant::VECTOR2I) {
+ const Vector2i &r = p_override[i];
+ sd->bidi_override.push_back(Vector3i(r.x, r.y, DIRECTION_INHERITED));
}
}
invalidate(sd, false);
@@ -5570,8 +5550,31 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
sd->script_iter = memnew(ScriptIterator(sd->text, 0, sd->text.length()));
}
+ int base_para_direction = UBIDI_DEFAULT_LTR;
+ switch (sd->direction) {
+ case DIRECTION_LTR: {
+ sd->para_direction = DIRECTION_LTR;
+ base_para_direction = UBIDI_LTR;
+ } break;
+ case DIRECTION_RTL: {
+ sd->para_direction = DIRECTION_RTL;
+ base_para_direction = UBIDI_RTL;
+ } break;
+ case DIRECTION_INHERITED:
+ case DIRECTION_AUTO: {
+ UBiDiDirection direction = ubidi_getBaseDirection(data, sd->utf16.length());
+ if (direction != UBIDI_NEUTRAL) {
+ sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
+ base_para_direction = direction;
+ } else {
+ sd->para_direction = DIRECTION_LTR;
+ base_para_direction = UBIDI_DEFAULT_LTR;
+ }
+ } break;
+ }
+
if (sd->bidi_override.is_empty()) {
- sd->bidi_override.push_back(Vector2i(sd->start, sd->end));
+ sd->bidi_override.push_back(Vector3i(sd->start, sd->end, DIRECTION_INHERITED));
}
for (int ov = 0; ov < sd->bidi_override.size(); ov++) {
@@ -5587,23 +5590,22 @@ bool TextServerAdvanced::_shaped_text_shape(const RID &p_shaped) {
UBiDi *bidi_iter = ubidi_openSized(end, 0, &err);
ERR_FAIL_COND_V_MSG(U_FAILURE(err), false, u_errorName(err));
- switch (sd->direction) {
+ switch (static_cast<TextServer::Direction>(sd->bidi_override[ov].z)) {
case DIRECTION_LTR: {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_LTR, nullptr, &err);
- sd->para_direction = DIRECTION_LTR;
} break;
case DIRECTION_RTL: {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_RTL, nullptr, &err);
- sd->para_direction = DIRECTION_RTL;
+ } break;
+ case DIRECTION_INHERITED: {
+ ubidi_setPara(bidi_iter, data + start, end - start, base_para_direction, nullptr, &err);
} break;
case DIRECTION_AUTO: {
UBiDiDirection direction = ubidi_getBaseDirection(data + start, end - start);
if (direction != UBIDI_NEUTRAL) {
ubidi_setPara(bidi_iter, data + start, end - start, direction, nullptr, &err);
- sd->para_direction = (direction == UBIDI_RTL) ? DIRECTION_RTL : DIRECTION_LTR;
} else {
ubidi_setPara(bidi_iter, data + start, end - start, UBIDI_DEFAULT_LTR, nullptr, &err);
- sd->para_direction = DIRECTION_LTR;
}
} break;
}
diff --git a/modules/text_server_adv/text_server_adv.h b/modules/text_server_adv/text_server_adv.h
index e8a3a10ab8..c7fe46d554 100644
--- a/modules/text_server_adv/text_server_adv.h
+++ b/modules/text_server_adv/text_server_adv.h
@@ -72,7 +72,6 @@
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
-
#include <godot_cpp/templates/vector.hpp>
using namespace godot;
@@ -350,7 +349,7 @@ class TextServerAdvanced : public TextServerExtension {
_FORCE_INLINE_ bool _ensure_glyph(FontAdvanced *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
_FORCE_INLINE_ bool _ensure_cache_for_size(FontAdvanced *p_font_data, const Vector2i &p_size) const;
_FORCE_INLINE_ void _font_clear_cache(FontAdvanced *p_font_data);
- void _generateMTSDF_threaded(uint32_t y, void *p_td) const;
+ static void _generateMTSDF_threaded(void *p_td, uint32_t p_y);
_FORCE_INLINE_ Vector2i _get_size(const FontAdvanced *p_font_data, int p_size) const {
if (p_font_data->msdf) {
@@ -500,7 +499,7 @@ class TextServerAdvanced : public TextServerExtension {
/* Intermediate data */
Char16String utf16;
Vector<UBiDi *> bidi_iter;
- Vector<Vector2i> bidi_override;
+ Vector<Vector3i> bidi_override;
ScriptIterator *script_iter = nullptr;
hb_buffer_t *hb_buffer = nullptr;
diff --git a/modules/text_server_adv/thorvg_svg_in_ot.cpp b/modules/text_server_adv/thorvg_svg_in_ot.cpp
index 9354d3f9b3..1406e3aaa0 100644
--- a/modules/text_server_adv/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_adv/thorvg_svg_in_ot.cpp
@@ -88,24 +88,13 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
if (!gl_state.ready) {
Ref<XMLParser> parser;
parser.instantiate();
-#ifdef GDEXTENSION
- PackedByteArray data;
- data.resize(document->svg_document_length);
- memcpy(data.ptrw(), document->svg_document, document->svg_document_length);
- parser->open_buffer(data);
-#else
parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
-#endif
float aspect = 1.0f;
String xml_body;
while (parser->read() == OK) {
if (parser->has_attribute("id")) {
-#ifdef GDEXTENSION
const String &gl_name = parser->get_named_attribute_value("id");
-#else
- const String &gl_name = parser->get_attribute_value("id");
-#endif
if (gl_name.begins_with("glyph")) {
int dot_pos = gl_name.find(".");
int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int();
@@ -117,11 +106,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
}
if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") {
if (parser->has_attribute("viewBox")) {
-#ifdef GDEXTENSION
PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
-#else
- Vector<String> vb = parser->get_attribute_value("viewBox").split(" ");
-#endif
if (vb.size() == 4) {
aspect = vb[2].to_float() / vb[3].to_float();
@@ -129,19 +114,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
}
continue;
}
-#ifdef GDEXTENSION
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
- xml_body = xml_body + "<" + parser->get_node_name();
- for (int i = 0; i < parser->get_attribute_count(); i++) {
- xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\"";
- }
- xml_body = xml_body + ">";
- } else if (parser->get_node_type() == XMLParser::NODE_TEXT) {
- xml_body = xml_body + parser->get_node_data();
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
- xml_body = xml_body + "</" + parser->get_node_name() + ">";
- }
-#else
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
xml_body += vformat("<%s", parser->get_node_name());
for (int i = 0; i < parser->get_attribute_count(); i++) {
@@ -153,7 +125,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
xml_body += vformat("</%s>", parser->get_node_name());
}
-#endif
}
String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
@@ -175,11 +146,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
new_h = (new_w / aspect);
}
-#ifdef GDEXTENSION
gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
-#else
- gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body;
-#endif
picture = tvg::Picture::gen();
result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);
diff --git a/modules/text_server_fb/text_server_fb.cpp b/modules/text_server_fb/text_server_fb.cpp
index 034f88e387..b5d7d3a3cf 100644
--- a/modules/text_server_fb/text_server_fb.cpp
+++ b/modules/text_server_fb/text_server_fb.cpp
@@ -51,7 +51,6 @@ using namespace godot;
#include "core/error/error_macros.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
-#include "core/string/ucaps.h"
#include "modules/modules_enabled.gen.h" // For freetype, msdfgen, svg.
@@ -248,11 +247,7 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
// Could not find texture to fit, create one.
int texsize = MAX(p_data->size.x * p_data->oversampling * 8, 256);
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(texsize);
-#else
texsize = next_power_of_2(texsize);
-#endif
if (p_msdf) {
texsize = MIN(texsize, 2048);
@@ -260,18 +255,10 @@ _FORCE_INLINE_ TextServerFallback::FontTexturePosition TextServerFallback::find_
texsize = MIN(texsize, 1024);
}
if (mw > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(mw);
-#else
texsize = next_power_of_2(mw);
-#endif
}
if (mh > texsize) { // Special case, adapt to it?
-#ifdef GDEXTENSION
- texsize = Math::next_power_of_2(mh);
-#else
texsize = next_power_of_2(mh);
-#endif
}
ShelfPackTexture tex = ShelfPackTexture(texsize, texsize);
@@ -374,14 +361,14 @@ static int ft_cubic_to(const FT_Vector *control1, const FT_Vector *control2, con
return 0;
}
-void TextServerFallback::_generateMTSDF_threaded(uint32_t y, void *p_td) const {
+void TextServerFallback::_generateMTSDF_threaded(void *p_td, uint32_t p_y) {
MSDFThreadData *td = static_cast<MSDFThreadData *>(p_td);
msdfgen::ShapeDistanceFinder<msdfgen::OverlappingContourCombiner<msdfgen::MultiAndTrueDistanceSelector>> distanceFinder(*td->shape);
- int row = td->shape->inverseYAxis ? td->output->height() - y - 1 : y;
+ int row = td->shape->inverseYAxis ? td->output->height() - p_y - 1 : p_y;
for (int col = 0; col < td->output->width(); ++col) {
- int x = (y % 2) ? td->output->width() - col - 1 : col;
- msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, y + .5));
+ int x = (p_y % 2) ? td->output->width() - col - 1 : col;
+ msdfgen::Point2 p = td->projection->unproject(msdfgen::Point2(x + .5, p_y + .5));
msdfgen::MultiAndTrueDistance distance = distanceFinder.distance(p);
td->distancePixelConversion->operator()(td->output->operator()(x, row), distance);
}
@@ -451,14 +438,8 @@ _FORCE_INLINE_ TextServerFallback::FontGlyph TextServerFallback::rasterize_msdf(
td.projection = &projection;
td.distancePixelConversion = &distancePixelConversion;
-#ifdef GDEXTENSION
- for (int i = 0; i < h; i++) {
- _generateMTSDF_threaded(i, &td);
- }
-#else
- WorkerThreadPool::GroupID group_id = WorkerThreadPool::get_singleton()->add_template_group_task(this, &TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, SNAME("TextServerFBRenderMSDF"));
- WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_id);
-#endif
+ WorkerThreadPool::GroupID group_task = WorkerThreadPool::get_singleton()->add_native_group_task(&TextServerFallback::_generateMTSDF_threaded, &td, h, -1, true, String("TextServerFBRenderMSDF"));
+ WorkerThreadPool::get_singleton()->wait_for_group_task_completion(group_task);
msdfgen::msdfErrorCorrection(image, shape, projection, p_pixel_range, config);
@@ -2683,6 +2664,7 @@ void TextServerFallback::full_copy(ShapedTextDataFallback *p_shaped) {
RID TextServerFallback::_create_shaped_text(TextServer::Direction p_direction, TextServer::Orientation p_orientation) {
_THREAD_SAFE_METHOD_
+ ERR_FAIL_COND_V_MSG(p_direction == DIRECTION_INHERITED, RID(), "Invalid text direction.");
ShapedTextDataFallback *sd = memnew(ShapedTextDataFallback);
sd->direction = p_direction;
@@ -2706,6 +2688,7 @@ void TextServerFallback::_shaped_text_clear(const RID &p_shaped) {
}
void TextServerFallback::_shaped_text_set_direction(const RID &p_shaped, TextServer::Direction p_direction) {
+ ERR_FAIL_COND_MSG(p_direction == DIRECTION_INHERITED, "Invalid text direction.");
if (p_direction == DIRECTION_RTL) {
ERR_PRINT_ONCE("Right-to-left layout is not supported by this text server.");
}
@@ -4078,31 +4061,11 @@ double TextServerFallback::_shaped_text_get_underline_thickness(const RID &p_sha
}
String TextServerFallback::_string_to_upper(const String &p_string, const String &p_language) const {
- String upper = p_string;
-
- for (int i = 0; i <= upper.length(); i++) {
- const char32_t s = upper[i];
- const char32_t t = _find_upper(s);
- if (s != t) { // avoid copy on write
- upper[i] = t;
- }
- }
-
- return upper;
+ return p_string.to_upper();
}
String TextServerFallback::_string_to_lower(const String &p_string, const String &p_language) const {
- String lower = p_string;
-
- for (int i = 0; i <= lower.length(); i++) {
- const char32_t s = lower[i];
- const char32_t t = _find_lower(s);
- if (s != t) { // avoid copy on write
- lower[i] = t;
- }
- }
-
- return lower;
+ return p_string.to_lower();
}
PackedInt32Array TextServerFallback::_string_get_word_breaks(const String &p_string, const String &p_language, int p_chars_per_line) const {
diff --git a/modules/text_server_fb/text_server_fb.h b/modules/text_server_fb/text_server_fb.h
index b42f564534..9fb048a581 100644
--- a/modules/text_server_fb/text_server_fb.h
+++ b/modules/text_server_fb/text_server_fb.h
@@ -67,11 +67,11 @@
#include <godot_cpp/classes/image.hpp>
#include <godot_cpp/classes/image_texture.hpp>
#include <godot_cpp/classes/ref.hpp>
+#include <godot_cpp/classes/worker_thread_pool.hpp>
#include <godot_cpp/templates/hash_map.hpp>
#include <godot_cpp/templates/hash_set.hpp>
#include <godot_cpp/templates/rid_owner.hpp>
-#include <godot_cpp/templates/thread_work_pool.hpp>
#include <godot_cpp/templates/vector.hpp>
using namespace godot;
@@ -303,7 +303,7 @@ class TextServerFallback : public TextServerExtension {
_FORCE_INLINE_ bool _ensure_glyph(FontFallback *p_font_data, const Vector2i &p_size, int32_t p_glyph) const;
_FORCE_INLINE_ bool _ensure_cache_for_size(FontFallback *p_font_data, const Vector2i &p_size) const;
_FORCE_INLINE_ void _font_clear_cache(FontFallback *p_font_data);
- void _generateMTSDF_threaded(uint32_t y, void *p_td) const;
+ static void _generateMTSDF_threaded(void *p_td, uint32_t p_y);
_FORCE_INLINE_ Vector2i _get_size(const FontFallback *p_font_data, int p_size) const {
if (p_font_data->msdf) {
diff --git a/modules/text_server_fb/thorvg_svg_in_ot.cpp b/modules/text_server_fb/thorvg_svg_in_ot.cpp
index 9354d3f9b3..1406e3aaa0 100644
--- a/modules/text_server_fb/thorvg_svg_in_ot.cpp
+++ b/modules/text_server_fb/thorvg_svg_in_ot.cpp
@@ -88,24 +88,13 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
if (!gl_state.ready) {
Ref<XMLParser> parser;
parser.instantiate();
-#ifdef GDEXTENSION
- PackedByteArray data;
- data.resize(document->svg_document_length);
- memcpy(data.ptrw(), document->svg_document, document->svg_document_length);
- parser->open_buffer(data);
-#else
parser->_open_buffer((const uint8_t *)document->svg_document, document->svg_document_length);
-#endif
float aspect = 1.0f;
String xml_body;
while (parser->read() == OK) {
if (parser->has_attribute("id")) {
-#ifdef GDEXTENSION
const String &gl_name = parser->get_named_attribute_value("id");
-#else
- const String &gl_name = parser->get_attribute_value("id");
-#endif
if (gl_name.begins_with("glyph")) {
int dot_pos = gl_name.find(".");
int64_t gl_idx = gl_name.substr(5, (dot_pos > 0) ? dot_pos - 5 : -1).to_int();
@@ -117,11 +106,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
}
if (parser->get_node_type() == XMLParser::NODE_ELEMENT && parser->get_node_name() == "svg") {
if (parser->has_attribute("viewBox")) {
-#ifdef GDEXTENSION
PackedStringArray vb = parser->get_named_attribute_value("viewBox").split(" ");
-#else
- Vector<String> vb = parser->get_attribute_value("viewBox").split(" ");
-#endif
if (vb.size() == 4) {
aspect = vb[2].to_float() / vb[3].to_float();
@@ -129,19 +114,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
}
continue;
}
-#ifdef GDEXTENSION
- if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
- xml_body = xml_body + "<" + parser->get_node_name();
- for (int i = 0; i < parser->get_attribute_count(); i++) {
- xml_body = xml_body + " " + parser->get_attribute_name(i) + "=\"" + parser->get_attribute_value(i) + "\"";
- }
- xml_body = xml_body + ">";
- } else if (parser->get_node_type() == XMLParser::NODE_TEXT) {
- xml_body = xml_body + parser->get_node_data();
- } else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
- xml_body = xml_body + "</" + parser->get_node_name() + ">";
- }
-#else
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
xml_body += vformat("<%s", parser->get_node_name());
for (int i = 0; i < parser->get_attribute_count(); i++) {
@@ -153,7 +125,6 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
} else if (parser->get_node_type() == XMLParser::NODE_ELEMENT_END) {
xml_body += vformat("</%s>", parser->get_node_name());
}
-#endif
}
String temp_xml = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 0 0\">" + xml_body;
@@ -175,11 +146,7 @@ FT_Error tvg_svg_in_ot_preset_slot(FT_GlyphSlot p_slot, FT_Bool p_cache, FT_Poin
new_h = (new_w / aspect);
}
-#ifdef GDEXTENSION
gl_state.xml_code = "<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"" + rtos(min_x) + " " + rtos(min_y) + " " + rtos(new_w) + " " + rtos(new_h) + "\">" + xml_body;
-#else
- gl_state.xml_code = vformat("<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"%f %f %f %f\">", min_x, min_y, new_w, new_h) + xml_body;
-#endif
picture = tvg::Picture::gen();
result = picture->load(gl_state.xml_code.utf8().get_data(), gl_state.xml_code.utf8().length(), "svg+xml", false);
diff --git a/modules/webxr/doc_classes/WebXRInterface.xml b/modules/webxr/doc_classes/WebXRInterface.xml
index f5964eb4d1..ba1750386f 100644
--- a/modules/webxr/doc_classes/WebXRInterface.xml
+++ b/modules/webxr/doc_classes/WebXRInterface.xml
@@ -18,7 +18,7 @@
func _ready():
# We assume this node has a button as a child.
# This button is for the user to consent to entering immersive VR mode.
- $Button.pressed.connect(self._on_Button_pressed)
+ $Button.pressed.connect(self._on_button_pressed)
webxr_interface = XRServer.find_interface("WebXR")
if webxr_interface:
@@ -38,7 +38,7 @@
if session_mode == 'immersive-vr':
vr_supported = supported
- func _on_Button_pressed():
+ func _on_button_pressed():
if not vr_supported:
OS.alert("Your browser doesn't support VR")
return
diff --git a/platform/android/README.md b/platform/android/README.md
index f6aabab708..01eb9c03a6 100644
--- a/platform/android/README.md
+++ b/platform/android/README.md
@@ -5,7 +5,7 @@ using [Gradle](https://gradle.org/) as a build system.
## Documentation
-- [Compiling for Android](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_android.html)
+- [Compiling for Android](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_android.html)
- Instructions on building this platform port from source.
- [Exporting for Android](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_android.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index 780ad4334e..6b3bdb7fe6 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -466,14 +466,15 @@ Vector<String> DisplayServerAndroid::get_rendering_drivers_func() {
DisplayServer *DisplayServerAndroid::create_func(const String &p_rendering_driver, DisplayServer::WindowMode p_mode, DisplayServer::VSyncMode p_vsync_mode, uint32_t p_flags, const Vector2i *p_position, const Vector2i &p_resolution, int p_screen, Error &r_error) {
DisplayServer *ds = memnew(DisplayServerAndroid(p_rendering_driver, p_mode, p_vsync_mode, p_flags, p_position, p_resolution, p_screen, r_error));
if (r_error != OK) {
- OS::get_singleton()->alert("Your video card driver does not support any of the supported Vulkan versions.", "Unable to initialize Video driver");
if (p_rendering_driver == "vulkan") {
- OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
- "Please try exporting your game using the gl_compatibility renderer.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ "Your device seems not to support the required Vulkan version.\n\n"
+ "Please try exporting your game using the 'gl_compatibility' renderer.",
+ "Unable to initialize Vulkan video driver");
} else {
- OS::get_singleton()->alert("Your video card driver does not support OpenGL ES 3.0.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ "Your device seems not to support the required OpenGL ES 3.0 version.",
+ "Unable to initialize OpenGL video driver");
}
}
return ds;
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index bb1ad3d83b..587caf81bf 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -437,6 +437,14 @@ String EditorExportPlatformAndroid::get_project_name(const String &p_name) const
String EditorExportPlatformAndroid::get_package_name(const String &p_package) const {
String pname = p_package;
+ String name = get_valid_basename();
+ pname = pname.replace("$genname", name);
+ return pname;
+}
+
+// Returns the project name without invalid characters
+// or the "noname" string if all characters are invalid.
+String EditorExportPlatformAndroid::get_valid_basename() const {
String basename = GLOBAL_GET("application/config/name");
basename = basename.to_lower();
@@ -452,13 +460,12 @@ String EditorExportPlatformAndroid::get_package_name(const String &p_package) co
first = false;
}
}
+
if (name.is_empty()) {
name = "noname";
}
- pname = pname.replace("$genname", name);
-
- return pname;
+ return name;
}
String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const {
@@ -466,7 +473,7 @@ String EditorExportPlatformAndroid::get_assets_directory(const Ref<EditorExportP
}
bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package, String *r_error) const {
- String pname = p_package;
+ String pname = get_package_name(p_package);
if (pname.length() == 0) {
if (r_error) {
@@ -525,6 +532,24 @@ bool EditorExportPlatformAndroid::is_package_name_valid(const String &p_package,
return false;
}
+ if (p_package.find("$genname") >= 0 && !is_project_name_valid()) {
+ if (r_error) {
+ *r_error = TTR("The project name does not meet the requirement for the package name format. Please explicitly specify the package name.");
+ }
+ return false;
+ }
+
+ return true;
+}
+
+bool EditorExportPlatformAndroid::is_project_name_valid() const {
+ // Get the original project name and convert to lowercase.
+ String basename = GLOBAL_GET("application/config/name");
+ basename = basename.to_lower();
+ // Check if there are invalid characters.
+ if (basename != get_valid_basename()) {
+ return false;
+ }
return true;
}
@@ -2286,7 +2311,7 @@ bool EditorExportPlatformAndroid::has_valid_project_configuration(const Ref<Edit
String pn = p_preset->get("package/unique_name");
String pn_err;
- if (!is_package_name_valid(get_package_name(pn), &pn_err)) {
+ if (!is_package_name_valid(pn, &pn_err)) {
valid = false;
err += TTR("Invalid package name:") + " " + pn_err + "\n";
}
diff --git a/platform/android/export/export_plugin.h b/platform/android/export/export_plugin.h
index a6dfc9fcb3..bff769fcba 100644
--- a/platform/android/export/export_plugin.h
+++ b/platform/android/export/export_plugin.h
@@ -91,9 +91,12 @@ class EditorExportPlatformAndroid : public EditorExportPlatform {
String get_package_name(const String &p_package) const;
+ String get_valid_basename() const;
+
String get_assets_directory(const Ref<EditorExportPreset> &p_preset, int p_export_format) const;
bool is_package_name_valid(const String &p_package, String *r_error = nullptr) const;
+ bool is_project_name_valid() const;
static bool _should_compress_asset(const String &p_path, const Vector<uint8_t> &p_data);
diff --git a/platform/android/os_android.cpp b/platform/android/os_android.cpp
index 376ed89c16..942bf0a904 100644
--- a/platform/android/os_android.cpp
+++ b/platform/android/os_android.cpp
@@ -355,20 +355,20 @@ void OS_Android::_load_system_font_config() {
if (parser->get_node_type() == XMLParser::NODE_ELEMENT) {
in_font_node = false;
if (parser->get_node_name() == "familyset") {
- int ver = parser->has_attribute("version") ? parser->get_attribute_value("version").to_int() : 0;
+ int ver = parser->has_attribute("version") ? parser->get_named_attribute_value("version").to_int() : 0;
if (ver < 21) {
ERR_PRINT(vformat("Unsupported font config version %s", ver));
break;
}
} else if (parser->get_node_name() == "alias") {
- String name = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String();
- String to = parser->has_attribute("to") ? parser->get_attribute_value("to").strip_edges() : String();
+ String name = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String();
+ String to = parser->has_attribute("to") ? parser->get_named_attribute_value("to").strip_edges() : String();
if (!name.is_empty() && !to.is_empty()) {
font_aliases[name] = to;
}
} else if (parser->get_node_name() == "family") {
- fn = parser->has_attribute("name") ? parser->get_attribute_value("name").strip_edges() : String();
- String lang_code = parser->has_attribute("lang") ? parser->get_attribute_value("lang").strip_edges() : String();
+ fn = parser->has_attribute("name") ? parser->get_named_attribute_value("name").strip_edges() : String();
+ String lang_code = parser->has_attribute("lang") ? parser->get_named_attribute_value("lang").strip_edges() : String();
Vector<String> lang_codes = lang_code.split(",");
for (int i = 0; i < lang_codes.size(); i++) {
Vector<String> lang_code_elements = lang_codes[i].split("-");
@@ -412,9 +412,9 @@ void OS_Android::_load_system_font_config() {
}
} else if (parser->get_node_name() == "font") {
in_font_node = true;
- fb = parser->has_attribute("fallbackFor") ? parser->get_attribute_value("fallbackFor").strip_edges() : String();
- fi.weight = parser->has_attribute("weight") ? parser->get_attribute_value("weight").to_int() : 400;
- fi.italic = parser->has_attribute("style") && parser->get_attribute_value("style").strip_edges() == "italic";
+ fb = parser->has_attribute("fallbackFor") ? parser->get_named_attribute_value("fallbackFor").strip_edges() : String();
+ fi.weight = parser->has_attribute("weight") ? parser->get_named_attribute_value("weight").to_int() : 400;
+ fi.italic = parser->has_attribute("style") && parser->get_named_attribute_value("style").strip_edges() == "italic";
}
}
if (parser->get_node_type() == XMLParser::NODE_TEXT) {
diff --git a/platform/ios/README.md b/platform/ios/README.md
index 82c275ad31..0e1d6802cb 100644
--- a/platform/ios/README.md
+++ b/platform/ios/README.md
@@ -8,7 +8,7 @@ project template used for packaging the iOS export templates.
## Documentation
-- [Compiling for iOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_ios.html)
+- [Compiling for iOS](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_ios.html)
- Instructions on building this platform port from source.
- [Exporting for iOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_ios.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index bea88a7f9b..86ea602a98 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -56,16 +56,9 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
tts = [[TTS_IOS alloc] init];
#if defined(GLES3_ENABLED)
- // FIXME: Add support for both OpenGL and Vulkan when OpenGL is implemented
- // again,
- // Note that we should be checking "opengl3" as the driver, might never enable this seeing OpenGL is deprecated on iOS
- // We are hardcoding the rendering_driver to "vulkan" down below
-
if (rendering_driver == "opengl3") {
bool gl_initialization_error = false;
- // FIXME: Add Vulkan support via MoltenVK. Add fallback code back?
-
if (RasterizerGLES3::is_viable() == OK) {
RasterizerGLES3::register_config();
RasterizerGLES3::make_current();
@@ -74,22 +67,10 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
}
if (gl_initialization_error) {
- OS::get_singleton()->alert("Your device does not support any of the supported OpenGL versions.", "Unable to initialize video driver");
- // return ERR_UNAVAILABLE;
+ OS::get_singleton()->alert(
+ "Your device seems not to support the required OpenGL ES 3.0 version.\n\n",
+ "Unable to initialize OpenGL video driver");
}
-
- // rendering_server = memnew(RenderingServerDefault);
- // // FIXME: Reimplement threaded rendering
- // if (get_render_thread_mode() != RENDER_THREAD_UNSAFE) {
- // rendering_server = memnew(RenderingServerWrapMT(rendering_server,
- // false));
- // }
- // rendering_server->init();
- // rendering_server->cursor_set_visible(false, 0);
-
- // reset this to what it should be, it will have been set to 0 after
- // rendering_server->init() is called
- // RasterizerStorageGLES3system_fbo = gl_view_base_fb;
}
#endif
diff --git a/platform/ios/export/export_plugin.cpp b/platform/ios/export/export_plugin.cpp
index ccd3480d11..87b599bc81 100644
--- a/platform/ios/export/export_plugin.cpp
+++ b/platform/ios/export/export_plugin.cpp
@@ -1572,7 +1572,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
int ret = unzGoToFirstFile(src_pkg_zip);
Vector<uint8_t> project_file_data;
while (ret == UNZ_OK) {
-#if defined(MACOS_ENABLED) || defined(X11_ENABLED)
+#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED)
bool is_execute = false;
#endif
@@ -1605,7 +1605,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
continue; //ignore!
}
found_library = true;
-#if defined(MACOS_ENABLED) || defined(X11_ENABLED)
+#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED)
is_execute = true;
#endif
file = file.replace(library_to_use, binary_name + ".xcframework");
@@ -1648,7 +1648,7 @@ Error EditorExportPlatformIOS::export_project(const Ref<EditorExportPreset> &p_p
f->store_buffer(data.ptr(), data.size());
}
-#if defined(MACOS_ENABLED) || defined(X11_ENABLED)
+#if defined(MACOS_ENABLED) || defined(LINUXBSD_ENABLED)
if (is_execute) {
// we need execute rights on this file
chmod(file.utf8().get_data(), 0755);
diff --git a/platform/linuxbsd/README.md b/platform/linuxbsd/README.md
index efa8682062..c4f287cc6c 100644
--- a/platform/linuxbsd/README.md
+++ b/platform/linuxbsd/README.md
@@ -7,7 +7,7 @@ used by this platform.
## Documentation
-- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_linuxbsd.html)
+- [Compiling for Linux/*BSD](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_linuxbsd.html)
- Instructions on building this platform port from source.
- [Exporting for Linux/*BSD](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_linux.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/linuxbsd/crash_handler_linuxbsd.cpp b/platform/linuxbsd/crash_handler_linuxbsd.cpp
index add69c436f..8d03e3d31c 100644
--- a/platform/linuxbsd/crash_handler_linuxbsd.cpp
+++ b/platform/linuxbsd/crash_handler_linuxbsd.cpp
@@ -44,6 +44,7 @@
#include <cxxabi.h>
#include <dlfcn.h>
#include <execinfo.h>
+#include <link.h>
#include <signal.h>
#include <stdlib.h>
@@ -79,7 +80,27 @@ static void handle_crash(int sig) {
}
print_error(vformat("Dumping the backtrace. %s", msg));
char **strings = backtrace_symbols(bt_buffer, size);
+ // PIE executable relocation, zero for non-PIE executables
+ uintptr_t relocation = _r_debug.r_map->l_addr;
if (strings) {
+ List<String> args;
+ for (size_t i = 0; i < size; i++) {
+ char str[1024];
+ snprintf(str, 1024, "%p", (void *)((uintptr_t)bt_buffer[i] - relocation));
+ args.push_back(str);
+ }
+ args.push_back("-e");
+ args.push_back(_execpath);
+
+ // Try to get the file/line number using addr2line
+ int ret;
+ String output = "";
+ Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret);
+ Vector<String> addr2line_results;
+ if (err == OK) {
+ addr2line_results = output.substr(0, output.length() - 1).split("\n", false);
+ }
+
for (size_t i = 1; i < size; i++) {
char fname[1024];
Dl_info info;
@@ -102,24 +123,7 @@ static void handle_crash(int sig) {
}
}
- List<String> args;
-
- char str[1024];
- snprintf(str, 1024, "%p", bt_buffer[i]);
- args.push_back(str);
- args.push_back("-e");
- args.push_back(_execpath);
-
- String output = "";
-
- // Try to get the file/line number using addr2line
- int ret;
- Error err = OS::get_singleton()->execute(String("addr2line"), args, &output, &ret);
- if (err == OK) {
- output = output.substr(0, output.length() - 1);
- }
-
- print_error(vformat("[%d] %s (%s)", (int64_t)i, fname, output));
+ print_error(vformat("[%d] %s (%s)", (int64_t)i, fname, err == OK ? addr2line_results[i] : ""));
}
free(strings);
diff --git a/platform/linuxbsd/detect.py b/platform/linuxbsd/detect.py
index 747dcbd76c..1830a7b39b 100644
--- a/platform/linuxbsd/detect.py
+++ b/platform/linuxbsd/detect.py
@@ -338,12 +338,17 @@ def configure(env: "Environment"):
env.Prepend(CPPPATH=["#platform/linuxbsd"])
+ env.Append(
+ CPPDEFINES=[
+ "LINUXBSD_ENABLED",
+ "UNIX_ENABLED",
+ ("_FILE_OFFSET_BITS", 64),
+ ]
+ )
+
if env["x11"]:
env.Append(CPPDEFINES=["X11_ENABLED"])
- env.Append(CPPDEFINES=["UNIX_ENABLED"])
- env.Append(CPPDEFINES=[("_FILE_OFFSET_BITS", 64)])
-
if env["vulkan"]:
env.Append(CPPDEFINES=["VULKAN_ENABLED"])
if not env["use_volk"]:
@@ -400,9 +405,9 @@ def configure(env: "Environment"):
# Link those statically for portability
if env["use_static_cpp"]:
env.Append(LINKFLAGS=["-static-libgcc", "-static-libstdc++"])
- if env["use_llvm"]:
+ if env["use_llvm"] and platform.system() != "FreeBSD":
env["LINKCOM"] = env["LINKCOM"] + " -l:libatomic.a"
else:
- if env["use_llvm"]:
+ if env["use_llvm"] and platform.system() != "FreeBSD":
env.Append(LIBS=["atomic"])
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index 10fd9972e3..d4f82cc81e 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -1420,31 +1420,35 @@ void DisplayServerX11::window_set_mouse_passthrough(const Vector<Vector2> &p_reg
_THREAD_SAFE_METHOD_
ERR_FAIL_COND(!windows.has(p_window));
- const WindowData &wd = windows[p_window];
+ windows[p_window].mpath = p_region;
+ _update_window_mouse_passthrough(p_window);
+}
+
+void DisplayServerX11::_update_window_mouse_passthrough(WindowID p_window) {
+ ERR_FAIL_COND(!windows.has(p_window));
+
+ const Vector<Vector2> region_path = windows[p_window].mpath;
int event_base, error_base;
const Bool ext_okay = XShapeQueryExtension(x11_display, &event_base, &error_base);
if (ext_okay) {
- Region region;
- if (p_region.size() == 0) {
- region = XCreateRegion();
- XRectangle rect;
- rect.x = 0;
- rect.y = 0;
- rect.width = window_get_size_with_decorations(p_window).x;
- rect.height = window_get_size_with_decorations(p_window).y;
- XUnionRectWithRegion(&rect, region, region);
+ if (windows[p_window].mpass) {
+ Region region = XCreateRegion();
+ XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet);
+ XDestroyRegion(region);
+ } else if (region_path.size() == 0) {
+ XShapeCombineMask(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, None, ShapeSet);
} else {
- XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * p_region.size());
- for (int i = 0; i < p_region.size(); i++) {
- points[i].x = p_region[i].x;
- points[i].y = p_region[i].y;
+ XPoint *points = (XPoint *)memalloc(sizeof(XPoint) * region_path.size());
+ for (int i = 0; i < region_path.size(); i++) {
+ points[i].x = region_path[i].x;
+ points[i].y = region_path[i].y;
}
- region = XPolygonRegion(points, p_region.size(), EvenOddRule);
+ Region region = XPolygonRegion(points, region_path.size(), EvenOddRule);
memfree(points);
+ XShapeCombineRegion(x11_display, windows[p_window].x11_window, ShapeInput, 0, 0, region, ShapeSet);
+ XDestroyRegion(region);
}
- XShapeCombineRegion(x11_display, wd.x11_window, ShapeInput, 0, 0, region, ShapeSet);
- XDestroyRegion(region);
}
}
@@ -2312,6 +2316,7 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
window_set_size(window_get_size(p_window), p_window);
wd.borderless = p_enabled;
+ _update_window_mouse_passthrough(p_window);
} break;
case WINDOW_FLAG_ALWAYS_ON_TOP: {
ERR_FAIL_COND_MSG(wd.transient_parent != INVALID_WINDOW_ID, "Can't make a window transient if the 'on top' flag is active.");
@@ -2345,6 +2350,10 @@ void DisplayServerX11::window_set_flag(WindowFlags p_flag, bool p_enabled, Windo
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ wd.mpass = p_enabled;
+ _update_window_mouse_passthrough(p_window);
+ } break;
case WINDOW_FLAG_POPUP: {
XWindowAttributes xwa;
XSync(x11_display, False);
@@ -2398,6 +2407,9 @@ bool DisplayServerX11::window_get_flag(WindowFlags p_flag, WindowID p_window) co
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ return wd.mpass;
+ } break;
case WINDOW_FLAG_POPUP: {
return wd.is_popup;
} break;
@@ -4564,18 +4576,20 @@ DisplayServer *DisplayServerX11::create_func(const String &p_rendering_driver, W
if (r_error != OK) {
if (p_rendering_driver == "vulkan") {
String executable_name = OS::get_singleton()->get_executable_path().get_file();
- OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
- "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
- "You can enable the OpenGL 3 driver by starting the engine from the\n"
- "command line with the command:\n'./" +
- executable_name + " --rendering-driver opengl3'.\n "
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ vformat("Your video card drivers seem not to support the required Vulkan version.\n\n"
+ "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'%s --rendering-driver opengl3'\n\n"
+ "If you recently updated your video card drivers, try rebooting.",
+ executable_name),
+ "Unable to initialize Vulkan video driver");
} else {
- OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
- "Please try updating your GPU driver.\n"
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
+ "If possible, consider updating your video card drivers.\n\n"
+ "If you recently updated your video card drivers, try rebooting.",
+ "Unable to initialize OpenGL video driver");
}
}
return ds;
diff --git a/platform/linuxbsd/x11/display_server_x11.h b/platform/linuxbsd/x11/display_server_x11.h
index 43a66f95b2..437766d953 100644
--- a/platform/linuxbsd/x11/display_server_x11.h
+++ b/platform/linuxbsd/x11/display_server_x11.h
@@ -149,6 +149,8 @@ class DisplayServerX11 : public DisplayServer {
Callable input_text_callback;
Callable drop_files_callback;
+ Vector<Vector2> mpath;
+
WindowID transient_parent = INVALID_WINDOW_ID;
HashSet<WindowID> transient_children;
@@ -169,6 +171,7 @@ class DisplayServerX11 : public DisplayServer {
bool maximized = false;
bool is_popup = false;
bool layered_window = false;
+ bool mpass = false;
Rect2i parent_safe_rect;
@@ -245,6 +248,7 @@ class DisplayServerX11 : public DisplayServer {
Atom _process_selection_request_target(Atom p_target, Window p_requestor, Atom p_property, Atom p_selection) const;
void _handle_selection_request_event(XSelectionRequestEvent *p_event) const;
+ void _update_window_mouse_passthrough(WindowID p_window);
String _clipboard_get_impl(Atom p_source, Window x11_window, Atom target) const;
String _clipboard_get(Atom p_source, Window x11_window) const;
diff --git a/platform/macos/README.md b/platform/macos/README.md
index feead80736..205c59e05d 100644
--- a/platform/macos/README.md
+++ b/platform/macos/README.md
@@ -11,7 +11,7 @@ packaging macOS export templates.
## Documentation
-- [Compiling for macOS](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_macos.html)
+- [Compiling for macOS](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_macos.html)
- Instructions on building this platform port from source.
- [Exporting for macOS](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_macos.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 67e4b49b14..14e6e92bfa 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -231,7 +231,6 @@ def configure(env: "Environment"):
if env["opengl3"]:
env.Append(CPPDEFINES=["GLES_ENABLED", "GLES3_ENABLED"])
- env.Append(CCFLAGS=["-Wno-deprecated-declarations"]) # Disable deprecation warnings
env.Append(LINKFLAGS=["-framework", "OpenGL"])
env.Append(LINKFLAGS=["-rpath", "@executable_path/../Frameworks", "-rpath", "@executable_path"])
diff --git a/platform/macos/display_server_macos.h b/platform/macos/display_server_macos.h
index 7f57644a4c..4873db4b64 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -114,6 +114,7 @@ public:
bool resize_disabled = false;
bool no_focus = false;
bool is_popup = false;
+ bool mpass = false;
Rect2i parent_safe_rect;
};
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index 865b8d9711..d992467042 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -2974,6 +2974,9 @@ void DisplayServerMacOS::window_set_flag(WindowFlags p_flag, bool p_enabled, Win
case WINDOW_FLAG_NO_FOCUS: {
wd.no_focus = p_enabled;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ wd.mpass = p_enabled;
+ } break;
case WINDOW_FLAG_POPUP: {
ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
ERR_FAIL_COND_MSG([wd.window_object isVisible] && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
@@ -3013,6 +3016,9 @@ bool DisplayServerMacOS::window_get_flag(WindowFlags p_flag, WindowID p_window)
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ return wd.mpass;
+ } break;
case WINDOW_FLAG_POPUP: {
return wd.is_popup;
} break;
@@ -3487,7 +3493,11 @@ void DisplayServerMacOS::process_events() {
for (KeyValue<WindowID, WindowData> &E : windows) {
WindowData &wd = E.value;
- if (wd.mpath.size() > 0) {
+ if (wd.mpass) {
+ if (![wd.window_object ignoresMouseEvents]) {
+ [wd.window_object setIgnoresMouseEvents:YES];
+ }
+ } else if (wd.mpath.size() > 0) {
update_mouse_pos(wd, [wd.window_object mouseLocationOutsideOfEventStream]);
if (Geometry2D::is_point_in_polygon(wd.mouse_pos, wd.mpath)) {
if ([wd.window_object ignoresMouseEvents]) {
@@ -3597,18 +3607,18 @@ DisplayServer *DisplayServerMacOS::create_func(const String &p_rendering_driver,
} else {
executable_command = vformat("open %s --args --rendering-driver opengl3", OS::get_singleton()->get_bundle_resource_dir().path_join("../..").simplify_path());
}
- OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
- "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
- "You can enable the OpenGL 3 driver by starting the engine from the\n"
- "command line with the command: '" +
- executable_command + "'.\n"
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ vformat("Your video card drivers seem not to support the required Vulkan version.\n\n"
+ "If possible, consider updating your macOS version or using the OpenGL 3 driver.\n\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'%s'",
+ executable_command),
+ "Unable to initialize Vulkan video driver");
} else {
- OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
- "Please try updating your GPU driver.\n"
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
+ "If possible, consider updating your macOS version.",
+ "Unable to initialize OpenGL video driver");
}
}
return ds;
diff --git a/platform/macos/gl_manager_macos_legacy.h b/platform/macos/gl_manager_macos_legacy.h
index 663bc5ea7b..c33b803d81 100644
--- a/platform/macos/gl_manager_macos_legacy.h
+++ b/platform/macos/gl_manager_macos_legacy.h
@@ -33,6 +33,9 @@
#if defined(MACOS_ENABLED) && defined(GLES3_ENABLED)
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // OpenGL is deprecated in macOS 10.14
+
#include "core/error/error_list.h"
#include "core/os/os.h"
#include "core/templates/local_vector.h"
@@ -95,6 +98,8 @@ public:
~GLManager_MacOS();
};
+#pragma clang diagnostic push
+
#endif // MACOS_ENABLED && GLES3_ENABLED
#endif // GL_MANAGER_MACOS_LEGACY_H
diff --git a/platform/macos/gl_manager_macos_legacy.mm b/platform/macos/gl_manager_macos_legacy.mm
index a53b737289..65e978bfe6 100644
--- a/platform/macos/gl_manager_macos_legacy.mm
+++ b/platform/macos/gl_manager_macos_legacy.mm
@@ -33,6 +33,9 @@
#ifdef MACOS_ENABLED
#ifdef GLES3_ENABLED
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // OpenGL is deprecated in macOS 10.14
+
#include <stdio.h>
#include <stdlib.h>
@@ -232,5 +235,7 @@ GLManager_MacOS::~GLManager_MacOS() {
release_current();
}
+#pragma clang diagnostic pop
+
#endif // GLES3_ENABLED
#endif // MACOS_ENABLED
diff --git a/platform/macos/godot_content_view.h b/platform/macos/godot_content_view.h
index ba7f15c32b..e660285e49 100644
--- a/platform/macos/godot_content_view.h
+++ b/platform/macos/godot_content_view.h
@@ -53,6 +53,9 @@
@end
+#pragma clang diagnostic push
+#pragma clang diagnostic ignored "-Wdeprecated-declarations" // OpenGL is deprecated in macOS 10.14
+
@interface GodotContentView : RootView <NSTextInputClient> {
DisplayServer::WindowID window_id;
NSTrackingArea *tracking_area;
@@ -73,4 +76,6 @@
@end
+#pragma clang diagnostic pop
+
#endif // GODOT_CONTENT_VIEW_H
diff --git a/platform/macos/godot_menu_delegate.mm b/platform/macos/godot_menu_delegate.mm
index 02cfca0841..ebfe8b1f6d 100644
--- a/platform/macos/godot_menu_delegate.mm
+++ b/platform/macos/godot_menu_delegate.mm
@@ -41,7 +41,7 @@
- (BOOL)menuHasKeyEquivalent:(NSMenu *)menu forEvent:(NSEvent *)event target:(id *)target action:(SEL *)action {
NSString *ev_key = [[event charactersIgnoringModifiers] lowercaseString];
- NSUInteger ev_modifiers = [event modifierFlags] & NSDeviceIndependentModifierFlagsMask;
+ NSUInteger ev_modifiers = [event modifierFlags] & NSEventModifierFlagDeviceIndependentFlagsMask;
for (int i = 0; i < [menu numberOfItems]; i++) {
const NSMenuItem *menu_item = [menu itemAtIndex:i];
if ([menu_item isEnabled] && [[menu_item keyEquivalent] compare:ev_key] == NSOrderedSame) {
diff --git a/platform/macos/joypad_macos.cpp b/platform/macos/joypad_macos.cpp
index b7b8e0604c..1fcd636a4b 100644
--- a/platform/macos/joypad_macos.cpp
+++ b/platform/macos/joypad_macos.cpp
@@ -316,7 +316,7 @@ bool JoypadMacOS::configure_joypad(IOHIDDeviceRef p_device_ref, joypad *p_joy) {
if (vendor && product_id) {
char uid[128];
- sprintf(uid, "%08x%08x%08x%08x", OSSwapHostToBigInt32(3), OSSwapHostToBigInt32(vendor), OSSwapHostToBigInt32(product_id), OSSwapHostToBigInt32(version));
+ snprintf(uid, 128, "%08x%08x%08x%08x", OSSwapHostToBigInt32(3), OSSwapHostToBigInt32(vendor), OSSwapHostToBigInt32(product_id), OSSwapHostToBigInt32(version));
input->joy_connection_changed(id, true, name, uid);
} else {
// Bluetooth device.
diff --git a/platform/uwp/README.md b/platform/uwp/README.md
index 575f90e3c7..d69a8a8850 100644
--- a/platform/uwp/README.md
+++ b/platform/uwp/README.md
@@ -14,7 +14,7 @@ project template used for packaging the UWP export templates.
## Documentation
-- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_uwp.html)
+- [Compiling for Universal Windows Platform](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_uwp.html)
- Instructions on building this platform port from source.
- [Exporting for Universal Windows Platform](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_uwp.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/web/README.md b/platform/web/README.md
index 1265ca09df..906eb508fe 100644
--- a/platform/web/README.md
+++ b/platform/web/README.md
@@ -10,7 +10,7 @@ this platform such as the html shell (web page).
## Documentation
-- [Compiling for the Web](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_web.html)
+- [Compiling for the Web](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_web.html)
- Instructions on building this platform port from source.
- [Exporting for the Web](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_web.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/web/api/web_tools_editor_plugin.cpp b/platform/web/api/web_tools_editor_plugin.cpp
index 7df9555b50..146a48db81 100644
--- a/platform/web/api/web_tools_editor_plugin.cpp
+++ b/platform/web/api/web_tools_editor_plugin.cpp
@@ -57,7 +57,7 @@ WebToolsEditorPlugin::WebToolsEditorPlugin() {
add_tool_menu_item("Download Project Source", callable_mp(this, &WebToolsEditorPlugin::_download_zip));
}
-void WebToolsEditorPlugin::_download_zip(Variant p_v) {
+void WebToolsEditorPlugin::_download_zip() {
if (!Engine::get_singleton() || !Engine::get_singleton()->is_editor_hint()) {
ERR_PRINT("Downloading the project as a ZIP archive is only available in Editor mode.");
return;
diff --git a/platform/web/api/web_tools_editor_plugin.h b/platform/web/api/web_tools_editor_plugin.h
index 72f4950b36..fc74899a58 100644
--- a/platform/web/api/web_tools_editor_plugin.h
+++ b/platform/web/api/web_tools_editor_plugin.h
@@ -41,7 +41,7 @@ class WebToolsEditorPlugin : public EditorPlugin {
private:
void _zip_file(String p_path, String p_base_path, zipFile p_zip);
void _zip_recursive(String p_path, String p_base_path, zipFile p_zip);
- void _download_zip(Variant p_v);
+ void _download_zip();
public:
static void initialize();
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index 7dd0515d3f..fdb9d107a7 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -787,8 +787,10 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
RasterizerGLES3::make_current();
} else {
- OS::get_singleton()->alert("Your browser does not seem to support WebGL2. Please update your browser version.",
- "Unable to initialize video driver");
+ OS::get_singleton()->alert(
+ "Your browser seems not to support WebGL 2.\n\n"
+ "If possible, consider updating your browser version and video card drivers.",
+ "Unable to initialize WebGL 2 video driver");
RasterizerDummy::make_current();
}
#else
diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp
index e12f62f4ad..964bce01da 100644
--- a/platform/web/os_web.cpp
+++ b/platform/web/os_web.cpp
@@ -30,6 +30,7 @@
#include "os_web.h"
+#include "core/config/project_settings.h"
#include "core/debugger/engine_debugger.h"
#include "drivers/unix/dir_access_unix.h"
#include "drivers/unix/file_access_unix.h"
@@ -157,7 +158,22 @@ void OS_Web::vibrate_handheld(int p_duration_ms) {
}
String OS_Web::get_user_data_dir() const {
- return "/userfs";
+ String userfs = "/userfs";
+ String appname = get_safe_dir_name(GLOBAL_GET("application/config/name"));
+ if (!appname.is_empty()) {
+ bool use_custom_dir = GLOBAL_GET("application/config/use_custom_user_dir");
+ if (use_custom_dir) {
+ String custom_dir = get_safe_dir_name(GLOBAL_GET("application/config/custom_user_dir_name"), true);
+ if (custom_dir.is_empty()) {
+ custom_dir = appname;
+ }
+ return userfs.path_join(custom_dir).replace("\\", "/");
+ } else {
+ return userfs.path_join(get_godot_dir_name()).path_join("app_userdata").path_join(appname).replace("\\", "/");
+ }
+ }
+
+ return userfs.path_join(get_godot_dir_name()).path_join("app_userdata").path_join("[unnamed project]");
}
String OS_Web::get_cache_path() const {
diff --git a/platform/windows/README.md b/platform/windows/README.md
index c04032ae1d..4c775576fe 100644
--- a/platform/windows/README.md
+++ b/platform/windows/README.md
@@ -7,7 +7,7 @@ used by this platform.
## Documentation
-- [Compiling for Windows](https://docs.godotengine.org/en/latest/development/compiling/compiling_for_windows.html)
+- [Compiling for Windows](https://docs.godotengine.org/en/latest/contributing/development/compiling/compiling_for_windows.html)
- Instructions on building this platform port from source.
- [Exporting for Windows](https://docs.godotengine.org/en/latest/tutorials/export/exporting_for_windows.html)
- Instructions on using the compiled export templates to export a project.
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 2d787c84e2..631543763b 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -735,9 +735,23 @@ DisplayServer::WindowID DisplayServerWindows::create_sub_window(WindowMode p_mod
if (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) {
wd.no_focus = true;
}
+ if (p_flags & WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT) {
+ wd.mpass = true;
+ }
if (p_flags & WINDOW_FLAG_POPUP_BIT) {
wd.is_popup = true;
}
+ if (p_flags & WINDOW_FLAG_TRANSPARENT_BIT) {
+ DWM_BLURBEHIND bb;
+ ZeroMemory(&bb, sizeof(bb));
+ HRGN hRgn = CreateRectRgn(0, 0, -1, -1);
+ bb.dwFlags = DWM_BB_ENABLE | DWM_BB_BLURREGION;
+ bb.hRgnBlur = hRgn;
+ bb.fEnable = TRUE;
+ DwmEnableBlurBehindWindow(wd.hWnd, &bb);
+
+ wd.layered_window = true;
+ }
// Inherit icons from MAIN_WINDOW for all sub windows.
HICON mainwindow_icon = (HICON)SendMessage(windows[MAIN_WINDOW_ID].hWnd, WM_GETICON, ICON_SMALL, 0);
@@ -775,6 +789,9 @@ void DisplayServerWindows::show_window(WindowID p_id) {
SetForegroundWindow(wd.hWnd); // Slightly higher priority.
SetFocus(wd.hWnd); // Set keyboard focus.
}
+ if (wd.always_on_top) {
+ SetWindowPos(wd.hWnd, HWND_TOPMOST, 0, 0, 0, 0, SWP_FRAMECHANGED | SWP_NOMOVE | SWP_NOSIZE | ((wd.no_focus || wd.is_popup) ? SWP_NOACTIVATE : 0));
+ }
}
void DisplayServerWindows::delete_sub_window(WindowID p_window) {
@@ -918,7 +935,7 @@ void DisplayServerWindows::window_set_mouse_passthrough(const Vector<Vector2> &p
void DisplayServerWindows::_update_window_mouse_passthrough(WindowID p_window) {
ERR_FAIL_COND(!windows.has(p_window));
- if (windows[p_window].mpath.size() == 0) {
+ if (windows[p_window].mpass || windows[p_window].mpath.size() == 0) {
SetWindowRgn(windows[p_window].hWnd, nullptr, TRUE);
} else {
POINT *points = (POINT *)memalloc(sizeof(POINT) * windows[p_window].mpath.size());
@@ -1499,6 +1516,10 @@ void DisplayServerWindows::window_set_flag(WindowFlags p_flag, bool p_enabled, W
wd.no_focus = p_enabled;
_update_window_style(p_window);
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ wd.mpass = p_enabled;
+ _update_window_mouse_passthrough(p_window);
+ } break;
case WINDOW_FLAG_POPUP: {
ERR_FAIL_COND_MSG(p_window == MAIN_WINDOW_ID, "Main window can't be popup.");
ERR_FAIL_COND_MSG(IsWindowVisible(wd.hWnd) && (wd.is_popup != p_enabled), "Popup flag can't changed while window is opened.");
@@ -1530,6 +1551,9 @@ bool DisplayServerWindows::window_get_flag(WindowFlags p_flag, WindowID p_window
case WINDOW_FLAG_NO_FOCUS: {
return wd.no_focus;
} break;
+ case WINDOW_FLAG_MOUSE_PASSTHROUGH: {
+ return wd.mpass;
+ } break;
case WINDOW_FLAG_POPUP: {
return wd.is_popup;
} break;
@@ -2464,6 +2488,11 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Process window messages.
switch (uMsg) {
+ case WM_NCHITTEST: {
+ if (windows[window_id].mpass) {
+ return HTTRANSPARENT;
+ }
+ } break;
case WM_MOUSEACTIVATE: {
if (windows[window_id].no_focus) {
return MA_NOACTIVATEANDEAT; // Do not activate, and discard mouse messages.
@@ -3656,7 +3685,7 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
DWORD dwExStyle;
DWORD dwStyle;
- _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
+ _get_window_style(window_id_counter == MAIN_WINDOW_ID, (p_mode == WINDOW_MODE_FULLSCREEN || p_mode == WINDOW_MODE_EXCLUSIVE_FULLSCREEN), p_mode != WINDOW_MODE_EXCLUSIVE_FULLSCREEN, p_flags & WINDOW_FLAG_BORDERLESS_BIT, !(p_flags & WINDOW_FLAG_RESIZE_DISABLED_BIT), p_mode == WINDOW_MODE_MAXIMIZED, (p_flags & WINDOW_FLAG_NO_FOCUS_BIT) | (p_flags & WINDOW_FLAG_POPUP), dwStyle, dwExStyle);
RECT WindowRect;
@@ -4130,18 +4159,20 @@ DisplayServer *DisplayServerWindows::create_func(const String &p_rendering_drive
if (r_error != OK) {
if (p_rendering_driver == "vulkan") {
String executable_name = OS::get_singleton()->get_executable_path().get_file();
- OS::get_singleton()->alert("Your video card driver does not support the selected Vulkan version.\n"
- "Please try updating your GPU driver or try using the OpenGL 3 driver.\n"
- "You can enable the OpenGL 3 driver by starting the engine from the\n"
- "command line with the command:\n'./" +
- executable_name + " --rendering-driver opengl3'.\n "
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ vformat("Your video card drivers seem not to support the required Vulkan version.\n\n"
+ "If possible, consider updating your video card drivers or using the OpenGL 3 driver.\n\n"
+ "You can enable the OpenGL 3 driver by starting the engine from the\n"
+ "command line with the command:\n'%s --rendering-driver opengl3'\n\n"
+ "If you have recently updated your video card drivers, try rebooting.",
+ executable_name),
+ "Unable to initialize Vulkan video driver");
} else {
- OS::get_singleton()->alert("Your video card driver does not support the selected OpenGL version.\n"
- "Please try updating your GPU driver.\n"
- "If you have updated your graphics drivers recently, try rebooting.",
- "Unable to initialize Video driver");
+ OS::get_singleton()->alert(
+ "Your video card drivers seem not to support the required OpenGL 3.3 version.\n\n"
+ "If possible, consider updating your video card drivers.\n\n"
+ "If you have recently updated your video card drivers, try rebooting.",
+ "Unable to initialize OpenGL video driver");
}
}
return ds;
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 84f2dee35e..ce4b94af59 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -370,6 +370,7 @@ class DisplayServerWindows : public DisplayServer {
bool window_has_focus = false;
bool exclusive = false;
bool context_created = false;
+ bool mpass = false;
// Used to transfer data between events using timer.
WPARAM saved_wparam;
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index b3831573cf..08299d9b98 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -210,6 +210,8 @@ void OS_Windows::initialize() {
} else if (!dwrite2_init) {
print_verbose("Unable to load IDWriteFactory2, automatic system font fallback is disabled.");
}
+
+ FileAccessWindows::initialize();
}
void OS_Windows::delete_main_loop() {
@@ -252,6 +254,8 @@ void OS_Windows::finalize() {
}
void OS_Windows::finalize_core() {
+ FileAccessWindows::finalize();
+
timeEndPeriod(1);
memdelete(process_map);
@@ -1166,8 +1170,17 @@ String OS_Windows::get_environment(const String &p_var) const {
return "";
}
-bool OS_Windows::set_environment(const String &p_var, const String &p_value) const {
- return (bool)SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), (LPCWSTR)(p_value.utf16().get_data()));
+void OS_Windows::set_environment(const String &p_var, const String &p_value) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ Char16String var = p_var.utf16();
+ Char16String value = p_value.utf16();
+ ERR_FAIL_COND_MSG(var.length() + value.length() + 2 > 32767, vformat("Invalid definition for environment variable '%s', cannot exceed 32767 characters.", p_var));
+ SetEnvironmentVariableW((LPCWSTR)(var.get_data()), (LPCWSTR)(value.get_data()));
+}
+
+void OS_Windows::unset_environment(const String &p_var) const {
+ ERR_FAIL_COND_MSG(p_var.is_empty() || p_var.contains("="), vformat("Invalid environment variable name '%s', cannot be empty or include '='.", p_var));
+ SetEnvironmentVariableW((LPCWSTR)(p_var.utf16().get_data()), nullptr); // Null to delete.
}
String OS_Windows::get_stdin_string() {
diff --git a/platform/windows/os_windows.h b/platform/windows/os_windows.h
index c33e0f6740..05110c2614 100644
--- a/platform/windows/os_windows.h
+++ b/platform/windows/os_windows.h
@@ -186,7 +186,8 @@ public:
virtual bool has_environment(const String &p_var) const override;
virtual String get_environment(const String &p_var) const override;
- virtual bool set_environment(const String &p_var, const String &p_value) const override;
+ virtual void set_environment(const String &p_var, const String &p_value) const override;
+ virtual void unset_environment(const String &p_var) const override;
virtual Vector<String> get_system_fonts() const override;
virtual String get_system_font_path(const String &p_font_name, int p_weight = 400, int p_stretch = 100, bool p_italic = false) const override;
diff --git a/scene/2d/area_2d.cpp b/scene/2d/area_2d.cpp
index 5eb76bdbb5..f80da6e9ab 100644
--- a/scene/2d/area_2d.cpp
+++ b/scene/2d/area_2d.cpp
@@ -175,6 +175,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
return; //does not exist because it was likely removed from the tree
}
+ lock_callback();
locked = true;
if (body_in) {
@@ -224,6 +225,7 @@ void Area2D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
locked = false;
+ unlock_callback();
}
void Area2D::_area_enter_tree(ObjectID p_id) {
@@ -268,6 +270,8 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
if (!area_in && !E) {
return; //likely removed from the tree
}
+
+ lock_callback();
locked = true;
if (area_in) {
@@ -317,6 +321,7 @@ void Area2D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
locked = false;
+ unlock_callback();
}
void Area2D::_clear_monitoring() {
diff --git a/scene/2d/collision_object_2d.cpp b/scene/2d/collision_object_2d.cpp
index b2fee6ad82..caea753d99 100644
--- a/scene/2d/collision_object_2d.cpp
+++ b/scene/2d/collision_object_2d.cpp
@@ -94,10 +94,14 @@ void CollisionObject2D::_notification(int p_what) {
bool disabled = !is_enabled();
if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
- if (area) {
- PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ if (callback_lock > 0) {
+ ERR_PRINT("Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead.");
} else {
- PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ }
}
}
@@ -225,10 +229,14 @@ void CollisionObject2D::_apply_disabled() {
switch (disable_mode) {
case DISABLE_MODE_REMOVE: {
if (is_inside_tree()) {
- if (area) {
- PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ if (callback_lock > 0) {
+ ERR_PRINT("Disabling a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Disable with call_deferred() instead.");
} else {
- PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ if (area) {
+ PhysicsServer2D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer2D::get_singleton()->body_set_space(rid, RID());
+ }
}
}
} break;
diff --git a/scene/2d/collision_object_2d.h b/scene/2d/collision_object_2d.h
index d44e402e96..88429b145d 100644
--- a/scene/2d/collision_object_2d.h
+++ b/scene/2d/collision_object_2d.h
@@ -53,6 +53,7 @@ private:
bool area = false;
RID rid;
+ uint32_t callback_lock = 0;
bool pickable = false;
DisableMode disable_mode = DISABLE_MODE_REMOVE;
@@ -83,6 +84,12 @@ private:
void _apply_enabled();
protected:
+ _FORCE_INLINE_ void lock_callback() { callback_lock++; }
+ _FORCE_INLINE_ void unlock_callback() {
+ ERR_FAIL_COND(callback_lock == 0);
+ callback_lock--;
+ }
+
CollisionObject2D(RID p_rid, bool p_area);
void _notification(int p_what);
diff --git a/scene/2d/path_2d.cpp b/scene/2d/path_2d.cpp
index 09f4406ffe..5036dd30b1 100644
--- a/scene/2d/path_2d.cpp
+++ b/scene/2d/path_2d.cpp
@@ -31,6 +31,7 @@
#include "path_2d.h"
#include "core/math/geometry_2d.h"
+#include "scene/main/timer.h"
#ifdef TOOLS_ENABLED
#include "editor/editor_scale.h"
@@ -171,6 +172,12 @@ void Path2D::_curve_changed() {
}
queue_redraw();
+ for (int i = 0; i < get_child_count(); i++) {
+ PathFollow2D *follow = Object::cast_to<PathFollow2D>(get_child(i));
+ if (follow) {
+ follow->path_changed();
+ }
+ }
}
void Path2D::set_curve(const Ref<Curve2D> &p_curve) {
@@ -200,6 +207,14 @@ void Path2D::_bind_methods() {
/////////////////////////////////////////////////////////////////////////////////
+void PathFollow2D::path_changed() {
+ if (update_timer && !update_timer->is_stopped()) {
+ update_timer->start();
+ } else {
+ _update_transform();
+ }
+}
+
void PathFollow2D::_update_transform() {
if (!path) {
return;
@@ -230,6 +245,16 @@ void PathFollow2D::_update_transform() {
void PathFollow2D::_notification(int p_what) {
switch (p_what) {
+ case NOTIFICATION_READY: {
+ if (Engine::get_singleton()->is_editor_hint()) {
+ update_timer = memnew(Timer);
+ update_timer->set_wait_time(0.2);
+ update_timer->set_one_shot(true);
+ update_timer->connect("timeout", callable_mp(this, &PathFollow2D::_update_transform));
+ add_child(update_timer, false, Node::INTERNAL_MODE_BACK);
+ }
+ } break;
+
case NOTIFICATION_ENTER_TREE: {
path = Object::cast_to<Path2D>(get_parent());
if (path) {
diff --git a/scene/2d/path_2d.h b/scene/2d/path_2d.h
index 884743dd2a..89c77c49eb 100644
--- a/scene/2d/path_2d.h
+++ b/scene/2d/path_2d.h
@@ -34,6 +34,8 @@
#include "scene/2d/node_2d.h"
#include "scene/resources/curve.h"
+class Timer;
+
class Path2D : public Node2D {
GDCLASS(Path2D, Node2D);
@@ -65,6 +67,7 @@ public:
private:
Path2D *path = nullptr;
real_t progress = 0.0;
+ Timer *update_timer = nullptr;
real_t h_offset = 0.0;
real_t v_offset = 0.0;
real_t lookahead = 4.0;
@@ -81,6 +84,8 @@ protected:
static void _bind_methods();
public:
+ void path_changed();
+
void set_progress(real_t p_progress);
real_t get_progress() const;
diff --git a/scene/2d/physics_body_2d.cpp b/scene/2d/physics_body_2d.cpp
index 9fee99c6a7..1721bcde3b 100644
--- a/scene/2d/physics_body_2d.cpp
+++ b/scene/2d/physics_body_2d.cpp
@@ -434,6 +434,8 @@ struct _RigidBody2DInOut {
};
void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
+ lock_callback();
+
set_block_transform_notify(true); // don't want notify (would feedback loop)
if (!freeze || freeze_mode != FREEZE_MODE_KINEMATIC) {
set_global_transform(p_state->get_transform());
@@ -527,6 +529,8 @@ void RigidBody2D::_body_state_changed(PhysicsDirectBodyState2D *p_state) {
contact_monitor->locked = false;
}
+
+ unlock_callback();
}
void RigidBody2D::_apply_body_mode() {
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index ed07d5d11e..4f282dc0ab 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -482,7 +482,11 @@ void TileMap::set_selected_layer(int p_layer_id) {
ERR_FAIL_COND(p_layer_id < -1 || p_layer_id >= (int)layers.size());
selected_layer = p_layer_id;
emit_signal(SNAME("changed"));
- _make_all_quadrants_dirty();
+
+ // Update the layers modulation.
+ for (unsigned int layer = 0; layer < layers.size(); layer++) {
+ _rendering_update_layer(layer);
+ }
}
int TileMap::get_selected_layer() const {
@@ -653,8 +657,7 @@ void TileMap::set_layer_modulate(int p_layer, Color p_modulate) {
}
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].modulate = p_modulate;
- _clear_layer_internals(p_layer);
- _recreate_layer_internals(p_layer);
+ _rendering_update_layer(p_layer);
emit_signal(SNAME("changed"));
}
@@ -703,8 +706,7 @@ void TileMap::set_layer_z_index(int p_layer, int p_z_index) {
}
ERR_FAIL_INDEX(p_layer, (int)layers.size());
layers[p_layer].z_index = p_z_index;
- _clear_layer_internals(p_layer);
- _recreate_layer_internals(p_layer);
+ _rendering_update_layer(p_layer);
emit_signal(SNAME("changed"));
update_configuration_warnings();
@@ -1103,6 +1105,19 @@ void TileMap::_rendering_update_layer(int p_layer) {
rs->canvas_item_set_default_texture_filter(ci, RS::CanvasItemTextureFilter(get_texture_filter_in_tree()));
rs->canvas_item_set_default_texture_repeat(ci, RS::CanvasItemTextureRepeat(get_texture_repeat_in_tree()));
rs->canvas_item_set_light_mask(ci, get_light_mask());
+
+ Color layer_modulate = get_layer_modulate(p_layer);
+ if (selected_layer >= 0 && p_layer != selected_layer) {
+ int z1 = get_layer_z_index(p_layer);
+ int z2 = get_layer_z_index(selected_layer);
+ if (z1 < z2 || (z1 == z2 && p_layer < selected_layer)) {
+ layer_modulate = layer_modulate.darkened(0.5);
+ } else if (z1 > z2 || (z1 == z2 && p_layer > selected_layer)) {
+ layer_modulate = layer_modulate.darkened(0.5);
+ layer_modulate.a *= 0.3;
+ }
+ }
+ rs->canvas_item_set_modulate(ci, layer_modulate);
}
void TileMap::_rendering_cleanup_layer(int p_layer) {
@@ -1145,19 +1160,6 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
int prev_z_index = 0;
RID prev_ci;
- Color tile_modulate = get_self_modulate();
- tile_modulate *= get_layer_modulate(q.layer);
- if (selected_layer >= 0) {
- int z1 = get_layer_z_index(q.layer);
- int z2 = get_layer_z_index(selected_layer);
- if (z1 < z2 || (z1 == z2 && q.layer < selected_layer)) {
- tile_modulate = tile_modulate.darkened(0.5);
- } else if (z1 > z2 || (z1 == z2 && q.layer > selected_layer)) {
- tile_modulate = tile_modulate.darkened(0.5);
- tile_modulate.a *= 0.3;
- }
- }
-
// Iterate over the cells of the quadrant.
for (const KeyValue<Vector2i, Vector2i> &E_cell : q.local_to_map) {
TileMapCell c = get_cell(q.layer, E_cell.value, true);
@@ -1227,7 +1229,7 @@ void TileMap::_rendering_update_dirty_quadrants(SelfList<TileMapQuadrant>::List
}
// Drawing the tile in the canvas item.
- draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, tile_modulate, tile_data);
+ draw_tile(ci, E_cell.key - tile_position, tile_set, c.source_id, c.get_atlas_coords(), c.alternative_tile, -1, get_self_modulate(), tile_data);
// --- Occluders ---
for (int i = 0; i < tile_set->get_occlusion_layers_count(); i++) {
@@ -2839,7 +2841,7 @@ void TileMap::_set_tile_data(int p_layer, const Vector<int> &p_data) {
const int *r = p_data.ptr();
int offset = (format >= FORMAT_2) ? 3 : 2;
- ERR_FAIL_COND_MSG(c % offset != 0, "Corrupted tile data.");
+ ERR_FAIL_COND_MSG(c % offset != 0, vformat("Corrupted tile data. Got size: %s. Expected modulo: %s", offset));
clear_layer(p_layer);
@@ -2979,11 +2981,7 @@ void TileMap::_build_runtime_update_tile_data(SelfList<TileMapQuadrant>::List &r
#ifdef TOOLS_ENABLED
Rect2 TileMap::_edit_get_rect() const {
// Return the visible rect of the tilemap
- if (pending_update) {
- const_cast<TileMap *>(this)->_update_dirty_quadrants();
- } else {
- const_cast<TileMap *>(this)->_recompute_rect_cache();
- }
+ const_cast<TileMap *>(this)->_recompute_rect_cache();
return rect_cache;
}
#endif
@@ -3738,6 +3736,22 @@ TypedArray<Vector2i> TileMap::get_used_cells(int p_layer) const {
return a;
}
+TypedArray<Vector2i> TileMap::get_used_cells_by_id(int p_layer, int p_source_id, const Vector2i p_atlas_coords, int p_alternative_tile) const {
+ ERR_FAIL_INDEX_V(p_layer, (int)layers.size(), TypedArray<Vector2i>());
+
+ // Returns the cells used in the tilemap.
+ TypedArray<Vector2i> a;
+ for (const KeyValue<Vector2i, TileMapCell> &E : layers[p_layer].tile_map) {
+ if ((p_source_id == TileSet::INVALID_SOURCE || p_source_id == E.value.source_id) &&
+ (p_atlas_coords == TileSetSource::INVALID_ATLAS_COORDS || p_atlas_coords == E.value.get_atlas_coords()) &&
+ (p_alternative_tile == TileSetSource::INVALID_TILE_ALTERNATIVE || p_alternative_tile == E.value.alternative_tile)) {
+ a.push_back(E.key);
+ }
+ }
+
+ return a;
+}
+
Rect2i TileMap::get_used_rect() { // Not const because of cache
// Return the rect of the currently used area
if (used_rect_cache_dirty) {
@@ -4030,6 +4044,7 @@ void TileMap::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_surrounding_cells", "coords"), &TileMap::get_surrounding_cells);
ClassDB::bind_method(D_METHOD("get_used_cells", "layer"), &TileMap::get_used_cells);
+ ClassDB::bind_method(D_METHOD("get_used_cells_by_id", "layer", "source_id", "atlas_coords", "alternative_tile"), &TileMap::get_used_cells_by_id, DEFVAL(TileSet::INVALID_SOURCE), DEFVAL(TileSetSource::INVALID_ATLAS_COORDS), DEFVAL(TileSetSource::INVALID_TILE_ALTERNATIVE));
ClassDB::bind_method(D_METHOD("get_used_rect"), &TileMap::get_used_rect);
ClassDB::bind_method(D_METHOD("map_to_local", "map_position"), &TileMap::map_to_local);
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index d187a917b5..7cf2a2eded 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -179,7 +179,7 @@ private:
FORMAT_2,
FORMAT_3
};
- mutable DataFormat format = FORMAT_1; // Assume lowest possible format if none is present;
+ mutable DataFormat format = FORMAT_3;
static constexpr float FP_ADJUST = 0.00001;
@@ -340,7 +340,7 @@ public:
VisibilityMode get_navigation_visibility_mode();
// Cells accessors.
- void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = -1, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
+ void set_cell(int p_layer, const Vector2i &p_coords, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = 0);
void erase_cell(int p_layer, const Vector2i &p_coords);
int get_cell_source_id(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
Vector2i get_cell_atlas_coords(int p_layer, const Vector2i &p_coords, bool p_use_proxies = false) const;
@@ -377,6 +377,7 @@ public:
Vector2i get_neighbor_cell(const Vector2i &p_coords, TileSet::CellNeighbor p_cell_neighbor) const;
TypedArray<Vector2i> get_used_cells(int p_layer) const;
+ TypedArray<Vector2i> get_used_cells_by_id(int p_layer, int p_source_id = TileSet::INVALID_SOURCE, const Vector2i p_atlas_coords = TileSetSource::INVALID_ATLAS_COORDS, int p_alternative_tile = TileSetSource::INVALID_TILE_ALTERNATIVE) const;
Rect2i get_used_rect(); // Not const because of cache
// Override some methods of the CanvasItem class to pass the changes to the quadrants CanvasItems
diff --git a/scene/3d/area_3d.cpp b/scene/3d/area_3d.cpp
index fa61ce5546..72f186c676 100644
--- a/scene/3d/area_3d.cpp
+++ b/scene/3d/area_3d.cpp
@@ -230,6 +230,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
return; //likely removed from the tree
}
+ lock_callback();
locked = true;
if (body_in) {
@@ -279,6 +280,7 @@ void Area3D::_body_inout(int p_status, const RID &p_body, ObjectID p_instance, i
}
locked = false;
+ unlock_callback();
}
void Area3D::_clear_monitoring() {
@@ -417,6 +419,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
return; //likely removed from the tree
}
+ lock_callback();
locked = true;
if (area_in) {
@@ -466,6 +469,7 @@ void Area3D::_area_inout(int p_status, const RID &p_area, ObjectID p_instance, i
}
locked = false;
+ unlock_callback();
}
bool Area3D::is_monitoring() const {
diff --git a/scene/3d/bone_attachment_3d.cpp b/scene/3d/bone_attachment_3d.cpp
index a44e66ce2a..fe7f6837f0 100644
--- a/scene/3d/bone_attachment_3d.cpp
+++ b/scene/3d/bone_attachment_3d.cpp
@@ -61,11 +61,7 @@ void BoneAttachment3D::_validate_property(PropertyInfo &p_property) const {
}
bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) {
- if (p_path == SNAME("override_pose")) {
- set_override_pose(p_value);
- } else if (p_path == SNAME("override_mode")) {
- set_override_mode(p_value);
- } else if (p_path == SNAME("use_external_skeleton")) {
+ if (p_path == SNAME("use_external_skeleton")) {
set_use_external_skeleton(p_value);
} else if (p_path == SNAME("external_skeleton")) {
set_external_skeleton(p_value);
@@ -75,11 +71,7 @@ bool BoneAttachment3D::_set(const StringName &p_path, const Variant &p_value) {
}
bool BoneAttachment3D::_get(const StringName &p_path, Variant &r_ret) const {
- if (p_path == SNAME("override_pose")) {
- r_ret = get_override_pose();
- } else if (p_path == SNAME("override_mode")) {
- r_ret = get_override_mode();
- } else if (p_path == SNAME("use_external_skeleton")) {
+ if (p_path == SNAME("use_external_skeleton")) {
r_ret = get_use_external_skeleton();
} else if (p_path == SNAME("external_skeleton")) {
r_ret = get_external_skeleton();
@@ -208,14 +200,10 @@ void BoneAttachment3D::_transform_changed() {
Transform3D our_trans = get_transform();
if (use_external_skeleton) {
- our_trans = sk->world_transform_to_global_pose(get_global_transform());
+ our_trans = sk->get_global_transform().affine_inverse() * get_global_transform();
}
- if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
- sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true);
- } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
- sk->set_bone_local_pose_override(bone_idx, sk->global_pose_to_local_pose(bone_idx, our_trans), 1.0, true);
- }
+ sk->set_bone_global_pose_override(bone_idx, our_trans, 1.0, true);
}
}
@@ -267,11 +255,7 @@ void BoneAttachment3D::set_override_pose(bool p_override) {
if (!override_pose) {
Skeleton3D *sk = _get_skeleton3d();
if (sk) {
- if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
- sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
- } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
- sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false);
- }
+ sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
}
_transform_changed();
}
@@ -282,27 +266,6 @@ bool BoneAttachment3D::get_override_pose() const {
return override_pose;
}
-void BoneAttachment3D::set_override_mode(int p_mode) {
- if (override_pose) {
- Skeleton3D *sk = _get_skeleton3d();
- if (sk) {
- if (override_mode == OVERRIDE_MODES::MODE_GLOBAL_POSE) {
- sk->set_bone_global_pose_override(bone_idx, Transform3D(), 0.0, false);
- } else if (override_mode == OVERRIDE_MODES::MODE_LOCAL_POSE) {
- sk->set_bone_local_pose_override(bone_idx, Transform3D(), 0.0, false);
- }
- }
- override_mode = p_mode;
- _transform_changed();
- return;
- }
- override_mode = p_mode;
-}
-
-int BoneAttachment3D::get_override_mode() const {
- return override_mode;
-}
-
void BoneAttachment3D::set_use_external_skeleton(bool p_use_external) {
use_external_skeleton = p_use_external;
@@ -361,7 +324,7 @@ void BoneAttachment3D::on_bone_pose_update(int p_bone_index) {
if (sk) {
if (!override_pose) {
if (use_external_skeleton) {
- set_global_transform(sk->global_pose_to_world_transform(sk->get_bone_global_pose(bone_idx)));
+ set_global_transform(sk->get_global_transform() * sk->get_bone_global_pose(bone_idx));
} else {
set_transform(sk->get_bone_global_pose(bone_idx));
}
@@ -407,8 +370,6 @@ void BoneAttachment3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_override_pose", "override_pose"), &BoneAttachment3D::set_override_pose);
ClassDB::bind_method(D_METHOD("get_override_pose"), &BoneAttachment3D::get_override_pose);
- ClassDB::bind_method(D_METHOD("set_override_mode", "override_mode"), &BoneAttachment3D::set_override_mode);
- ClassDB::bind_method(D_METHOD("get_override_mode"), &BoneAttachment3D::get_override_mode);
ClassDB::bind_method(D_METHOD("set_use_external_skeleton", "use_external_skeleton"), &BoneAttachment3D::set_use_external_skeleton);
ClassDB::bind_method(D_METHOD("get_use_external_skeleton"), &BoneAttachment3D::get_use_external_skeleton);
@@ -420,4 +381,5 @@ void BoneAttachment3D::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_idx"), "set_bone_idx", "get_bone_idx");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "override_pose"), "set_override_pose", "get_override_pose");
}
diff --git a/scene/3d/bone_attachment_3d.h b/scene/3d/bone_attachment_3d.h
index 2065271bbe..327cbaa0ab 100644
--- a/scene/3d/bone_attachment_3d.h
+++ b/scene/3d/bone_attachment_3d.h
@@ -44,14 +44,8 @@ class BoneAttachment3D : public Node3D {
int bone_idx = -1;
bool override_pose = false;
- int override_mode = 0;
bool _override_dirty = false;
- enum OVERRIDE_MODES {
- MODE_GLOBAL_POSE,
- MODE_LOCAL_POSE,
- };
-
bool use_external_skeleton = false;
NodePath external_skeleton_node;
ObjectID external_skeleton_node_cache;
@@ -86,8 +80,6 @@ public:
void set_override_pose(bool p_override);
bool get_override_pose() const;
- void set_override_mode(int p_mode);
- int get_override_mode() const;
void set_use_external_skeleton(bool p_external_skeleton);
bool get_use_external_skeleton() const;
diff --git a/scene/3d/collision_object_3d.cpp b/scene/3d/collision_object_3d.cpp
index c408b0714a..26ada1da5a 100644
--- a/scene/3d/collision_object_3d.cpp
+++ b/scene/3d/collision_object_3d.cpp
@@ -100,10 +100,14 @@ void CollisionObject3D::_notification(int p_what) {
bool disabled = !is_enabled();
if (!disabled || (disable_mode != DISABLE_MODE_REMOVE)) {
- if (area) {
- PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ if (callback_lock > 0) {
+ ERR_PRINT("Removing a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Remove with call_deferred() instead.");
} else {
- PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ }
}
}
@@ -223,10 +227,14 @@ void CollisionObject3D::_apply_disabled() {
switch (disable_mode) {
case DISABLE_MODE_REMOVE: {
if (is_inside_tree()) {
- if (area) {
- PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ if (callback_lock > 0) {
+ ERR_PRINT("Disabling a CollisionObject node during a physics callback is not allowed and will cause undesired behavior. Disable with call_deferred() instead.");
} else {
- PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ if (area) {
+ PhysicsServer3D::get_singleton()->area_set_space(rid, RID());
+ } else {
+ PhysicsServer3D::get_singleton()->body_set_space(rid, RID());
+ }
}
}
} break;
diff --git a/scene/3d/collision_object_3d.h b/scene/3d/collision_object_3d.h
index 656b8c9bf1..ebcbb39e0d 100644
--- a/scene/3d/collision_object_3d.h
+++ b/scene/3d/collision_object_3d.h
@@ -52,6 +52,7 @@ private:
bool area = false;
RID rid;
+ uint32_t callback_lock = 0;
DisableMode disable_mode = DISABLE_MODE_REMOVE;
@@ -97,6 +98,12 @@ private:
protected:
CollisionObject3D(RID p_rid, bool p_area);
+ _FORCE_INLINE_ void lock_callback() { callback_lock++; }
+ _FORCE_INLINE_ void unlock_callback() {
+ ERR_FAIL_COND(callback_lock == 0);
+ callback_lock--;
+ }
+
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/3d/decal.cpp b/scene/3d/decal.cpp
index e9cc4e9479..fbcb1c8f2c 100644
--- a/scene/3d/decal.cpp
+++ b/scene/3d/decal.cpp
@@ -156,6 +156,10 @@ void Decal::_validate_property(PropertyInfo &p_property) const {
if (!distance_fade_enabled && (p_property.name == "distance_fade_begin" || p_property.name == "distance_fade_length")) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
}
+
+ if (p_property.name == "sorting_offset") {
+ p_property.usage = PROPERTY_USAGE_DEFAULT;
+ }
}
PackedStringArray Decal::get_configuration_warnings() const {
diff --git a/scene/3d/label_3d.cpp b/scene/3d/label_3d.cpp
index f8c54809da..d0f71768d2 100644
--- a/scene/3d/label_3d.cpp
+++ b/scene/3d/label_3d.cpp
@@ -442,7 +442,7 @@ void Label3D::_shape() {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
- TypedArray<Vector2i> stt;
+ TypedArray<Vector3i> stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
} else {
diff --git a/scene/3d/label_3d.h b/scene/3d/label_3d.h
index 8fc772e4b0..96cc941209 100644
--- a/scene/3d/label_3d.h
+++ b/scene/3d/label_3d.h
@@ -143,7 +143,7 @@ private:
void _generate_glyph_surfaces(const Glyph &p_glyph, Vector2 &r_offset, const Color &p_modulate, int p_priority = 0, int p_outline_size = 0);
protected:
- GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
+ GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
void _notification(int p_what);
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index a6d63619df..6940bad4a6 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -763,7 +763,15 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
MeshesFound &mf = meshes_found.write[m_i];
- Size2i lightmap_size = mf.mesh->get_lightmap_size_hint() * mf.lightmap_scale;
+ Size2i lightmap_size = mf.mesh->get_lightmap_size_hint();
+
+ if (lightmap_size == Size2i(0, 0)) {
+ // TODO we should compute a size if no lightmap hint is set, as we did in 3.x.
+ // For now set to basic size to avoid crash.
+ lightmap_size = Size2i(64, 64);
+ }
+
+ lightmap_size *= mf.lightmap_scale;
TypedArray<RID> overrides;
overrides.resize(mf.overrides.size());
for (int i = 0; i < mf.overrides.size(); i++) {
diff --git a/scene/3d/physics_body_3d.cpp b/scene/3d/physics_body_3d.cpp
index 46956b0a2e..106efbc596 100644
--- a/scene/3d/physics_body_3d.cpp
+++ b/scene/3d/physics_body_3d.cpp
@@ -484,6 +484,8 @@ struct _RigidBodyInOut {
};
void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
+ lock_callback();
+
set_ignore_transform_notification(true);
set_global_transform(p_state->get_transform());
@@ -578,6 +580,8 @@ void RigidBody3D::_body_state_changed(PhysicsDirectBodyState3D *p_state) {
contact_monitor->locked = false;
}
+
+ unlock_callback();
}
void RigidBody3D::_notification(int p_what) {
diff --git a/scene/3d/skeleton_3d.cpp b/scene/3d/skeleton_3d.cpp
index 4eadaa603f..1b46879079 100644
--- a/scene/3d/skeleton_3d.cpp
+++ b/scene/3d/skeleton_3d.cpp
@@ -33,7 +33,6 @@
#include "core/object/message_queue.h"
#include "core/variant/type_info.h"
#include "scene/3d/physics_body_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
#include "scene/resources/surface_tool.h"
#include "scene/scene_string_names.h"
@@ -70,13 +69,6 @@ SkinReference::~SkinReference() {
bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
String path = p_path;
-#ifndef _3D_DISABLED
- if (path.begins_with("modification_stack")) {
- set_modification_stack(p_value);
- return true;
- }
-#endif //_3D_DISABLED
-
if (!path.begins_with("bones/")) {
return false;
}
@@ -113,13 +105,6 @@ bool Skeleton3D::_set(const StringName &p_path, const Variant &p_value) {
bool Skeleton3D::_get(const StringName &p_path, Variant &r_ret) const {
String path = p_path;
-#ifndef _3D_DISABLED
- if (path.begins_with("modification_stack")) {
- r_ret = modification_stack;
- return true;
- }
-#endif //_3D_DISABLED
-
if (!path.begins_with("bones/")) {
return false;
}
@@ -162,14 +147,6 @@ void Skeleton3D::_get_property_list(List<PropertyInfo> *p_list) const {
p_list->push_back(PropertyInfo(Variant::VECTOR3, prep + PNAME("scale"), PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR));
}
-#ifndef _3D_DISABLED
- p_list->push_back(
- PropertyInfo(Variant::OBJECT, "modification_stack",
- PROPERTY_HINT_RESOURCE_TYPE,
- "SkeletonModificationStack3D",
- PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
-#endif //_3D_DISABLED
-
for (PropertyInfo &E : *p_list) {
_validate_property(E);
}
@@ -330,24 +307,10 @@ void Skeleton3D::_notification(int p_what) {
}
}
}
-
- if (modification_stack.is_valid()) {
- execute_modifications(get_physics_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_physics_process);
- }
- } break;
-
- case NOTIFICATION_INTERNAL_PROCESS: {
- if (modification_stack.is_valid()) {
- execute_modifications(get_process_delta_time(), SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_process);
- }
} break;
-
case NOTIFICATION_READY: {
- set_physics_process_internal(true);
- set_process_internal(true);
-
- if (modification_stack.is_valid()) {
- set_modification_stack(modification_stack);
+ if (Engine::get_singleton()->is_editor_hint()) {
+ set_physics_process_internal(true);
}
} break;
#endif // _3D_DISABLED
@@ -395,99 +358,6 @@ Transform3D Skeleton3D::get_bone_global_pose_no_override(int p_bone) const {
return bones[p_bone].pose_global_no_override;
}
-void Skeleton3D::clear_bones_local_pose_override() {
- for (int i = 0; i < bones.size(); i += 1) {
- bones.write[i].local_pose_override_amount = 0;
- }
- _make_dirty();
-}
-
-void Skeleton3D::set_bone_local_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
- bones.write[p_bone].local_pose_override_amount = p_amount;
- bones.write[p_bone].local_pose_override = p_pose;
- bones.write[p_bone].local_pose_override_reset = !p_persistent;
- _make_dirty();
-}
-
-Transform3D Skeleton3D::get_bone_local_pose_override(int p_bone) const {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone, bone_size, Transform3D());
- return bones[p_bone].local_pose_override;
-}
-
-void Skeleton3D::update_bone_rest_forward_vector(int p_bone, bool p_force_update) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
-
- if (bones[p_bone].rest_bone_forward_vector.length_squared() > 0 && p_force_update == false) {
- update_bone_rest_forward_axis(p_bone, p_force_update);
- }
-
- // If it is a child/leaf bone...
- if (get_bone_parent(p_bone) > 0) {
- bones.write[p_bone].rest_bone_forward_vector = bones[p_bone].rest.origin.normalized();
- } else {
- // If it has children...
- Vector<int> child_bones = get_bone_children(p_bone);
- if (child_bones.size() > 0) {
- Vector3 combined_child_dir = Vector3(0, 0, 0);
- for (int i = 0; i < child_bones.size(); i++) {
- combined_child_dir += bones[child_bones[i]].rest.origin.normalized();
- }
- combined_child_dir = combined_child_dir / child_bones.size();
- bones.write[p_bone].rest_bone_forward_vector = combined_child_dir.normalized();
- } else {
- WARN_PRINT_ONCE("Cannot calculate forward direction for bone " + itos(p_bone));
- WARN_PRINT_ONCE("Assuming direction of (0, 1, 0) for bone");
- bones.write[p_bone].rest_bone_forward_vector = Vector3(0, 1, 0);
- }
- }
- update_bone_rest_forward_axis(p_bone, p_force_update);
-}
-
-void Skeleton3D::update_bone_rest_forward_axis(int p_bone, bool p_force_update) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX(p_bone, bone_size);
- if (bones[p_bone].rest_bone_forward_axis > -1 && p_force_update == false) {
- return;
- }
-
- Vector3 forward_axis_absolute = bones[p_bone].rest_bone_forward_vector.abs();
- if (forward_axis_absolute.x > forward_axis_absolute.y && forward_axis_absolute.x > forward_axis_absolute.z) {
- if (bones[p_bone].rest_bone_forward_vector.x > 0) {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_X_FORWARD;
- } else {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_X_FORWARD;
- }
- } else if (forward_axis_absolute.y > forward_axis_absolute.x && forward_axis_absolute.y > forward_axis_absolute.z) {
- if (bones[p_bone].rest_bone_forward_vector.y > 0) {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_Y_FORWARD;
- } else {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_Y_FORWARD;
- }
- } else {
- if (bones[p_bone].rest_bone_forward_vector.z > 0) {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_Z_FORWARD;
- } else {
- bones.write[p_bone].rest_bone_forward_axis = BONE_AXIS_NEGATIVE_Z_FORWARD;
- }
- }
-}
-
-Vector3 Skeleton3D::get_bone_axis_forward_vector(int p_bone) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone, bone_size, Vector3(0, 0, 0));
- return bones[p_bone].rest_bone_forward_vector;
-}
-
-int Skeleton3D::get_bone_axis_forward_enum(int p_bone) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone, bone_size, -1);
- return bones[p_bone].rest_bone_forward_axis;
-}
-
void Skeleton3D::set_motion_scale(float p_motion_scale) {
if (p_motion_scale <= 0) {
motion_scale = 1;
@@ -503,6 +373,10 @@ float Skeleton3D::get_motion_scale() const {
// Skeleton creation api
+uint64_t Skeleton3D::get_version() const {
+ return version;
+}
+
void Skeleton3D::add_bone(const String &p_name) {
ERR_FAIL_COND(p_name.is_empty() || p_name.contains(":") || p_name.contains("/"));
@@ -546,6 +420,7 @@ void Skeleton3D::set_bone_name(int p_bone, const String &p_name) {
}
bones.write[p_bone].name = p_name;
+ version++;
}
bool Skeleton3D::is_bone_parent_of(int p_bone, int p_parent_bone_id) const {
@@ -1068,23 +943,10 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
b.global_rest = b.parent >= 0 ? bonesptr[b.parent].global_rest * b.rest : b.rest;
}
- if (b.local_pose_override_amount >= CMP_EPSILON) {
- Transform3D override_local_pose;
- if (b.parent >= 0) {
- override_local_pose = bonesptr[b.parent].pose_global * b.local_pose_override;
- } else {
- override_local_pose = b.local_pose_override;
- }
- b.pose_global = b.pose_global.interpolate_with(override_local_pose, b.local_pose_override_amount);
- }
-
if (b.global_pose_override_amount >= CMP_EPSILON) {
b.pose_global = b.pose_global.interpolate_with(b.global_pose_override, b.global_pose_override_amount);
}
- if (b.local_pose_override_reset) {
- b.local_pose_override_amount = 0.0;
- }
if (b.global_pose_override_reset) {
b.global_pose_override_amount = 0.0;
}
@@ -1100,100 +962,6 @@ void Skeleton3D::force_update_bone_children_transforms(int p_bone_idx) {
rest_dirty = false;
}
-// Helper functions
-
-Transform3D Skeleton3D::global_pose_to_world_transform(Transform3D p_global_pose) {
- return get_global_transform() * p_global_pose;
-}
-
-Transform3D Skeleton3D::world_transform_to_global_pose(Transform3D p_world_transform) {
- return get_global_transform().affine_inverse() * p_world_transform;
-}
-
-Transform3D Skeleton3D::global_pose_to_local_pose(int p_bone_idx, Transform3D p_global_pose) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D());
- if (bones[p_bone_idx].parent >= 0) {
- int parent_bone_idx = bones[p_bone_idx].parent;
- Transform3D conversion_transform = get_bone_global_pose(parent_bone_idx).affine_inverse();
- return conversion_transform * p_global_pose;
- } else {
- return p_global_pose;
- }
-}
-
-Transform3D Skeleton3D::local_pose_to_global_pose(int p_bone_idx, Transform3D p_local_pose) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Transform3D());
- if (bones[p_bone_idx].parent >= 0) {
- int parent_bone_idx = bones[p_bone_idx].parent;
- return bones[parent_bone_idx].pose_global * p_local_pose;
- } else {
- return p_local_pose;
- }
-}
-
-Basis Skeleton3D::global_pose_z_forward_to_bone_forward(int p_bone_idx, Basis p_basis) {
- const int bone_size = bones.size();
- ERR_FAIL_INDEX_V(p_bone_idx, bone_size, Basis());
- Basis return_basis = p_basis;
-
- if (bones[p_bone_idx].rest_bone_forward_axis < 0) {
- update_bone_rest_forward_vector(p_bone_idx, true);
- }
-
- if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_X_FORWARD) {
- return_basis.rotate_local(Vector3(0, 1, 0), (Math_PI / 2.0));
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_X_FORWARD) {
- return_basis.rotate_local(Vector3(0, 1, 0), -(Math_PI / 2.0));
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_Y_FORWARD) {
- return_basis.rotate_local(Vector3(1, 0, 0), -(Math_PI / 2.0));
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_Y_FORWARD) {
- return_basis.rotate_local(Vector3(1, 0, 0), (Math_PI / 2.0));
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_Z_FORWARD) {
- // Do nothing!
- } else if (bones[p_bone_idx].rest_bone_forward_axis == BONE_AXIS_NEGATIVE_Z_FORWARD) {
- return_basis.rotate_local(Vector3(0, 0, 1), Math_PI);
- }
-
- return return_basis;
-}
-
-// Modifications
-
-#ifndef _3D_DISABLED
-
-void Skeleton3D::set_modification_stack(Ref<SkeletonModificationStack3D> p_stack) {
- if (modification_stack.is_valid()) {
- modification_stack->is_setup = false;
- modification_stack->set_skeleton(nullptr);
- }
-
- modification_stack = p_stack;
- if (modification_stack.is_valid()) {
- modification_stack->set_skeleton(this);
- modification_stack->setup();
- }
-}
-Ref<SkeletonModificationStack3D> Skeleton3D::get_modification_stack() {
- return modification_stack;
-}
-
-void Skeleton3D::execute_modifications(real_t p_delta, int p_execution_mode) {
- if (!modification_stack.is_valid()) {
- return;
- }
-
- // Needed to avoid the issue where the stack looses reference to the skeleton when the scene is saved.
- if (modification_stack->skeleton != this) {
- modification_stack->set_skeleton(this);
- }
-
- modification_stack->execute(p_delta, p_execution_mode);
-}
-
-#endif // _3D_DISABLED
-
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);
@@ -1204,6 +972,7 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_bone_parent", "bone_idx", "parent_idx"), &Skeleton3D::set_bone_parent);
ClassDB::bind_method(D_METHOD("get_bone_count"), &Skeleton3D::get_bone_count);
+ ClassDB::bind_method(D_METHOD("get_version"), &Skeleton3D::get_version);
ClassDB::bind_method(D_METHOD("unparent_bone_and_rest", "bone_idx"), &Skeleton3D::unparent_bone_and_rest);
@@ -1243,23 +1012,12 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_bone_global_pose", "bone_idx"), &Skeleton3D::get_bone_global_pose);
ClassDB::bind_method(D_METHOD("get_bone_global_pose_no_override", "bone_idx"), &Skeleton3D::get_bone_global_pose_no_override);
- ClassDB::bind_method(D_METHOD("clear_bones_local_pose_override"), &Skeleton3D::clear_bones_local_pose_override);
- ClassDB::bind_method(D_METHOD("set_bone_local_pose_override", "bone_idx", "pose", "amount", "persistent"), &Skeleton3D::set_bone_local_pose_override, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_bone_local_pose_override", "bone_idx"), &Skeleton3D::get_bone_local_pose_override);
-
ClassDB::bind_method(D_METHOD("force_update_all_bone_transforms"), &Skeleton3D::force_update_all_bone_transforms);
ClassDB::bind_method(D_METHOD("force_update_bone_child_transform", "bone_idx"), &Skeleton3D::force_update_bone_children_transforms);
ClassDB::bind_method(D_METHOD("set_motion_scale", "motion_scale"), &Skeleton3D::set_motion_scale);
ClassDB::bind_method(D_METHOD("get_motion_scale"), &Skeleton3D::get_motion_scale);
- // Helper functions
- ClassDB::bind_method(D_METHOD("global_pose_to_world_transform", "global_pose"), &Skeleton3D::global_pose_to_world_transform);
- ClassDB::bind_method(D_METHOD("world_transform_to_global_pose", "world_transform"), &Skeleton3D::world_transform_to_global_pose);
- ClassDB::bind_method(D_METHOD("global_pose_to_local_pose", "bone_idx", "global_pose"), &Skeleton3D::global_pose_to_local_pose);
- ClassDB::bind_method(D_METHOD("local_pose_to_global_pose", "bone_idx", "local_pose"), &Skeleton3D::local_pose_to_global_pose);
- ClassDB::bind_method(D_METHOD("global_pose_z_forward_to_bone_forward", "bone_idx", "basis"), &Skeleton3D::global_pose_z_forward_to_bone_forward);
-
ClassDB::bind_method(D_METHOD("set_show_rest_only", "enabled"), &Skeleton3D::set_show_rest_only);
ClassDB::bind_method(D_METHOD("is_show_rest_only"), &Skeleton3D::is_show_rest_only);
@@ -1271,11 +1029,6 @@ void Skeleton3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("physical_bones_add_collision_exception", "exception"), &Skeleton3D::physical_bones_add_collision_exception);
ClassDB::bind_method(D_METHOD("physical_bones_remove_collision_exception", "exception"), &Skeleton3D::physical_bones_remove_collision_exception);
- // Modifications
- ClassDB::bind_method(D_METHOD("set_modification_stack", "modification_stack"), &Skeleton3D::set_modification_stack);
- ClassDB::bind_method(D_METHOD("get_modification_stack"), &Skeleton3D::get_modification_stack);
- ClassDB::bind_method(D_METHOD("execute_modifications", "delta", "execution_mode"), &Skeleton3D::execute_modifications);
-
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "motion_scale", PROPERTY_HINT_RANGE, "0.001,10,0.001,or_greater"), "set_motion_scale", "get_motion_scale");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "show_rest_only"), "set_show_rest_only", "is_show_rest_only");
#ifndef _3D_DISABLED
diff --git a/scene/3d/skeleton_3d.h b/scene/3d/skeleton_3d.h
index f66cc2f9ed..3df909d936 100644
--- a/scene/3d/skeleton_3d.h
+++ b/scene/3d/skeleton_3d.h
@@ -32,7 +32,6 @@
#define SKELETON_3D_H
#include "scene/3d/node_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
#include "scene/resources/skin.h"
typedef int BoneId;
@@ -64,8 +63,6 @@ public:
~SkinReference();
};
-class SkeletonModificationStack3D;
-
class Skeleton3D : public Node3D {
GDCLASS(Skeleton3D, Node3D);
@@ -104,17 +101,8 @@ private:
PhysicalBone3D *physical_bone = nullptr;
PhysicalBone3D *cache_parent_physical_bone = nullptr;
- real_t local_pose_override_amount;
- bool local_pose_override_reset;
- Transform3D local_pose_override;
-
Vector<int> child_bones;
- // The forward direction vector and rest bone forward axis are cached because they do not change
- // 99% of the time, but recalculating them can be expensive on models with many bones.
- Vector3 rest_bone_forward_vector;
- int rest_bone_forward_axis = -1;
-
Bone() {
parent = -1;
enabled = true;
@@ -124,12 +112,7 @@ private:
physical_bone = nullptr;
cache_parent_physical_bone = nullptr;
#endif // _3D_DISABLED
- local_pose_override_amount = 0;
- local_pose_override_reset = false;
child_bones = Vector<int>();
-
- rest_bone_forward_vector = Vector3(0, 0, 0);
- rest_bone_forward_axis = -1;
}
};
@@ -162,25 +145,13 @@ protected:
void _notification(int p_what);
static void _bind_methods();
-#ifndef _3D_DISABLED
- Ref<SkeletonModificationStack3D> modification_stack;
-#endif // _3D_DISABLED
-
public:
- enum Bone_Forward_Axis {
- BONE_AXIS_X_FORWARD = 0,
- BONE_AXIS_Y_FORWARD = 1,
- BONE_AXIS_Z_FORWARD = 2,
- BONE_AXIS_NEGATIVE_X_FORWARD = 3,
- BONE_AXIS_NEGATIVE_Y_FORWARD = 4,
- BONE_AXIS_NEGATIVE_Z_FORWARD = 5,
- };
-
enum {
NOTIFICATION_UPDATE_SKELETON = 50
};
// skeleton creation api
+ uint64_t get_version() const;
void add_bone(const String &p_name);
int find_bone(const String &p_name) const;
String get_bone_name(int p_bone) const;
@@ -233,10 +204,6 @@ public:
Transform3D get_bone_global_pose_override(int p_bone) const;
void set_bone_global_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
- void clear_bones_local_pose_override();
- Transform3D get_bone_local_pose_override(int p_bone) const;
- void set_bone_local_pose_override(int p_bone, const Transform3D &p_pose, real_t p_amount, bool p_persistent = false);
-
void localize_rests(); // used for loaders and tools
Ref<Skin> create_skin_from_rest_transforms();
@@ -247,26 +214,6 @@ public:
void force_update_all_bone_transforms();
void force_update_bone_children_transforms(int bone_idx);
- void update_bone_rest_forward_vector(int p_bone, bool p_force_update = false);
- void update_bone_rest_forward_axis(int p_bone, bool p_force_update = false);
- Vector3 get_bone_axis_forward_vector(int p_bone);
- int get_bone_axis_forward_enum(int p_bone);
-
- // Helper functions
- Transform3D global_pose_to_world_transform(Transform3D p_global_pose);
- Transform3D world_transform_to_global_pose(Transform3D p_transform);
- Transform3D global_pose_to_local_pose(int p_bone_idx, Transform3D p_global_pose);
- Transform3D local_pose_to_global_pose(int p_bone_idx, Transform3D p_local_pose);
-
- Basis global_pose_z_forward_to_bone_forward(int p_bone_idx, Basis p_basis);
-
- // Modifications
-#ifndef _3D_DISABLED
- Ref<SkeletonModificationStack3D> get_modification_stack();
- void set_modification_stack(Ref<SkeletonModificationStack3D> p_stack);
- void execute_modifications(real_t p_delta, int p_execution_mode);
-#endif // _3D_DISABLED
-
// Physical bone API
void set_animate_physical_bones(bool p_enabled);
diff --git a/scene/3d/skeleton_ik_3d.cpp b/scene/3d/skeleton_ik_3d.cpp
index f35cd3fbc5..75f54a925b 100644
--- a/scene/3d/skeleton_ik_3d.cpp
+++ b/scene/3d/skeleton_ik_3d.cpp
@@ -249,6 +249,26 @@ void FabrikInverseKinematic::make_goal(Task *p_task, const Transform3D &p_invers
}
}
+static Vector3 get_bone_axis_forward_vector(Skeleton3D *skeleton, int p_bone) {
+ // If it is a child/leaf bone...
+ if (skeleton->get_bone_parent(p_bone) > 0) {
+ return skeleton->get_bone_rest(p_bone).origin.normalized();
+ }
+ // If it has children...
+ Vector<int> child_bones = skeleton->get_bone_children(p_bone);
+ if (child_bones.size() == 0) {
+ WARN_PRINT_ONCE("Cannot calculate forward direction for bone " + itos(p_bone));
+ WARN_PRINT_ONCE("Assuming direction of (0, 1, 0) for bone");
+ return Vector3(0, 1, 0);
+ }
+ Vector3 combined_child_dir = Vector3(0, 0, 0);
+ for (int i = 0; i < child_bones.size(); i++) {
+ combined_child_dir += skeleton->get_bone_rest(child_bones[i]).origin.normalized();
+ }
+ combined_child_dir = combined_child_dir / child_bones.size();
+ return combined_child_dir.normalized();
+}
+
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
@@ -287,8 +307,7 @@ void FabrikInverseKinematic::solve(Task *p_task, real_t blending_delta, bool ove
new_bone_pose.origin = ci->current_pos;
if (!ci->children.is_empty()) {
- p_task->skeleton->update_bone_rest_forward_vector(ci->bone);
- Vector3 forward_vector = p_task->skeleton->get_bone_axis_forward_vector(ci->bone);
+ Vector3 forward_vector = get_bone_axis_forward_vector(p_task->skeleton, ci->bone);
// Rotate the bone towards the next bone in the chain:
new_bone_pose.basis.rotate_to_align(forward_vector, new_bone_pose.origin.direction_to(ci->children[0].current_pos));
diff --git a/scene/3d/visual_instance_3d.cpp b/scene/3d/visual_instance_3d.cpp
index 64fb0a7657..8026b12c2b 100644
--- a/scene/3d/visual_instance_3d.cpp
+++ b/scene/3d/visual_instance_3d.cpp
@@ -120,6 +120,12 @@ bool VisualInstance3D::is_sorting_use_aabb_center() const {
return sorting_use_aabb_center;
}
+void VisualInstance3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "sorting_offset" || p_property.name == "sorting_use_aabb_center") {
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
+}
+
void VisualInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_base", "base"), &VisualInstance3D::set_base);
ClassDB::bind_method(D_METHOD("get_base"), &VisualInstance3D::get_base);
@@ -437,6 +443,12 @@ PackedStringArray GeometryInstance3D::get_configuration_warnings() const {
return warnings;
}
+void GeometryInstance3D::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "sorting_offset" || p_property.name == "sorting_use_aabb_center") {
+ p_property.usage = PROPERTY_USAGE_DEFAULT;
+ }
+}
+
void GeometryInstance3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_material_override", "material"), &GeometryInstance3D::set_material_override);
ClassDB::bind_method(D_METHOD("get_material_override"), &GeometryInstance3D::get_material_override);
diff --git a/scene/3d/visual_instance_3d.h b/scene/3d/visual_instance_3d.h
index 190ed17753..ef0f7966e2 100644
--- a/scene/3d/visual_instance_3d.h
+++ b/scene/3d/visual_instance_3d.h
@@ -47,6 +47,7 @@ protected:
void _notification(int p_what);
static void _bind_methods();
+ void _validate_property(PropertyInfo &p_property) const;
GDVIRTUAL0RC(AABB, _get_aabb)
public:
@@ -140,6 +141,7 @@ protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
void _get_property_list(List<PropertyInfo> *p_list) const;
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 1ef0774828..a00b1d8ee1 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -229,15 +229,17 @@ AnimationNodeSync::AnimationNodeSync() {
////////////////////////////////////////////////////////
void AnimationNodeOneShot::get_parameter_list(List<PropertyInfo> *r_list) const {
- r_list->push_back(PropertyInfo(Variant::BOOL, active));
- r_list->push_back(PropertyInfo(Variant::BOOL, prev_active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
+ r_list->push_back(PropertyInfo(Variant::BOOL, active, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY));
+ r_list->push_back(PropertyInfo(Variant::INT, request, PROPERTY_HINT_ENUM, ",Fire,Abort"));
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, remaining, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, time_to_restart, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_parameter) const {
- if (p_parameter == active || p_parameter == prev_active) {
+ if (p_parameter == request) {
+ return ONE_SHOT_REQUEST_NONE;
+ } else if (p_parameter == active) {
return false;
} else if (p_parameter == time_to_restart) {
return -1;
@@ -246,6 +248,13 @@ Variant AnimationNodeOneShot::get_parameter_default_value(const StringName &p_pa
}
}
+bool AnimationNodeOneShot::is_parameter_read_only(const StringName &p_parameter) const {
+ if (p_parameter == active) {
+ return true;
+ }
+ return false;
+}
+
void AnimationNodeOneShot::set_fadein_time(double p_time) {
fade_in = p_time;
}
@@ -303,41 +312,42 @@ bool AnimationNodeOneShot::has_filter() const {
}
double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_external_seeking) {
+ OneShotRequest cur_request = static_cast<OneShotRequest>((int)get_parameter(request));
bool cur_active = get_parameter(active);
- bool cur_prev_active = get_parameter(prev_active);
double cur_time = get_parameter(time);
double cur_remaining = get_parameter(remaining);
double cur_time_to_restart = get_parameter(time_to_restart);
- if (!cur_active) {
- //make it as if this node doesn't exist, pass input 0 by.
- if (cur_prev_active) {
- set_parameter(prev_active, false);
- }
+ set_parameter(request, ONE_SHOT_REQUEST_NONE);
+
+ bool do_start = cur_request == ONE_SHOT_REQUEST_FIRE;
+ if (cur_request == ONE_SHOT_REQUEST_ABORT) {
+ set_parameter(active, false);
+ set_parameter(time_to_restart, -1);
+ return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
+ } else if (!do_start && !cur_active) {
if (cur_time_to_restart >= 0.0 && !p_seek) {
cur_time_to_restart -= p_time;
if (cur_time_to_restart < 0) {
- //restart
- set_parameter(active, true);
- cur_active = true;
+ do_start = true; // Restart.
}
set_parameter(time_to_restart, cur_time_to_restart);
}
-
- return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
+ if (!do_start) {
+ return blend_input(0, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, sync);
+ }
}
bool os_seek = p_seek;
-
if (p_seek) {
cur_time = p_time;
}
- bool do_start = !cur_prev_active;
if (do_start) {
cur_time = 0;
os_seek = true;
- set_parameter(prev_active, true);
+ set_parameter(request, ONE_SHOT_REQUEST_NONE);
+ set_parameter(active, true);
}
real_t blend;
@@ -375,7 +385,6 @@ double AnimationNodeOneShot::process(double p_time, bool p_seek, bool p_is_exter
cur_remaining = os_rem;
if (cur_remaining <= 0) {
set_parameter(active, false);
- set_parameter(prev_active, false);
if (autorestart) {
double restart_sec = autorestart_delay + Math::randd() * autorestart_random_delay;
set_parameter(time_to_restart, restart_sec);
@@ -419,6 +428,10 @@ void AnimationNodeOneShot::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_delay", "get_autorestart_delay");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "autorestart_random_delay", PROPERTY_HINT_RANGE, "0,60,0.01,or_greater,suffix:s"), "set_autorestart_random_delay", "get_autorestart_random_delay");
+ BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_NONE);
+ BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_FIRE);
+ BIND_ENUM_CONSTANT(ONE_SHOT_REQUEST_ABORT);
+
BIND_ENUM_CONSTANT(MIX_MODE_BLEND);
BIND_ENUM_CONSTANT(MIX_MODE_ADD);
}
@@ -640,9 +653,10 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con
anims += inputs[i].name;
}
- r_list->push_back(PropertyInfo(Variant::INT, current, PROPERTY_HINT_ENUM, anims));
- r_list->push_back(PropertyInfo(Variant::INT, prev_current, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
- r_list->push_back(PropertyInfo(Variant::INT, prev, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
+ r_list->push_back(PropertyInfo(Variant::STRING, current_state, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_READ_ONLY)); // For interface.
+ r_list->push_back(PropertyInfo(Variant::STRING, transition_request, PROPERTY_HINT_ENUM, anims)); // For transition request. It will be cleared after setting the value immediately.
+ r_list->push_back(PropertyInfo(Variant::INT, current_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_STORAGE | PROPERTY_USAGE_READ_ONLY)); // To avoid finding the index every frame, use this internally.
+ r_list->push_back(PropertyInfo(Variant::INT, prev_index, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, time, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
r_list->push_back(PropertyInfo(Variant::FLOAT, prev_xfading, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NONE));
}
@@ -650,13 +664,22 @@ void AnimationNodeTransition::get_parameter_list(List<PropertyInfo> *r_list) con
Variant AnimationNodeTransition::get_parameter_default_value(const StringName &p_parameter) const {
if (p_parameter == time || p_parameter == prev_xfading) {
return 0.0;
- } else if (p_parameter == prev || p_parameter == prev_current) {
+ } else if (p_parameter == prev_index) {
return -1;
+ } else if (p_parameter == transition_request || p_parameter == current_state) {
+ return String();
} else {
return 0;
}
}
+bool AnimationNodeTransition::is_parameter_read_only(const StringName &p_parameter) const {
+ if (p_parameter == current_state || p_parameter == current_index) {
+ return true;
+ }
+ return false;
+}
+
String AnimationNodeTransition::get_caption() const {
return "Transition";
}
@@ -702,6 +725,17 @@ String AnimationNodeTransition::get_input_caption(int p_input) const {
return inputs[p_input].name;
}
+int AnimationNodeTransition::find_input_caption(const String &p_name) const {
+ int idx = -1;
+ for (int i = 0; i < MAX_INPUTS; i++) {
+ if (inputs[i].name == p_name) {
+ idx = i;
+ break;
+ }
+ }
+ return idx;
+}
+
void AnimationNodeTransition::set_xfade_time(double p_fade) {
xfade_time = p_fade;
}
@@ -718,35 +752,62 @@ Ref<Curve> AnimationNodeTransition::get_xfade_curve() const {
return xfade_curve;
}
-void AnimationNodeTransition::set_from_start(bool p_from_start) {
- from_start = p_from_start;
+void AnimationNodeTransition::set_reset(bool p_reset) {
+ reset = p_reset;
}
-bool AnimationNodeTransition::is_from_start() const {
- return from_start;
+bool AnimationNodeTransition::is_reset() const {
+ return reset;
}
double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_external_seeking) {
- int cur_current = get_parameter(current);
- int cur_prev = get_parameter(prev);
- int cur_prev_current = get_parameter(prev_current);
+ String cur_transition_request = get_parameter(transition_request);
+ int cur_current_index = get_parameter(current_index);
+ int cur_prev_index = get_parameter(prev_index);
double cur_time = get_parameter(time);
double cur_prev_xfading = get_parameter(prev_xfading);
- bool switched = cur_current != cur_prev_current;
+ bool switched = false;
+ bool restart = false;
+
+ if (!cur_transition_request.is_empty()) {
+ int new_idx = find_input_caption(cur_transition_request);
+ if (new_idx >= 0) {
+ if (cur_current_index == new_idx) {
+ // Transition to same state.
+ restart = reset;
+ cur_prev_xfading = 0;
+ set_parameter(prev_xfading, 0);
+ cur_prev_index = -1;
+ set_parameter(prev_index, -1);
+ } else {
+ switched = true;
+ cur_prev_index = cur_current_index;
+ set_parameter(prev_index, cur_current_index);
+ }
+ cur_current_index = new_idx;
+ set_parameter(current_index, cur_current_index);
+ set_parameter(current_state, cur_transition_request);
+ } else {
+ ERR_PRINT("No such input: '" + cur_transition_request + "'");
+ }
+ cur_transition_request = String();
+ set_parameter(transition_request, cur_transition_request);
+ }
- if (switched) {
- set_parameter(prev_current, cur_current);
- set_parameter(prev, cur_prev_current);
+ // Special case for restart.
+ if (restart) {
+ set_parameter(time, 0);
+ return blend_input(cur_current_index, 0, true, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ }
- cur_prev = cur_prev_current;
+ if (switched) {
cur_prev_xfading = xfade_time;
cur_time = 0;
- switched = true;
}
- if (cur_current < 0 || cur_current >= enabled_inputs || cur_prev >= enabled_inputs) {
+ if (cur_current_index < 0 || cur_current_index >= enabled_inputs || cur_prev_index >= enabled_inputs) {
return 0;
}
@@ -754,15 +815,15 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
if (sync) {
for (int i = 0; i < enabled_inputs; i++) {
- if (i != cur_current && i != cur_prev) {
+ if (i != cur_current_index && i != cur_prev_index) {
blend_input(i, p_time, p_seek, p_is_external_seeking, 0, FILTER_IGNORE, true);
}
}
}
- if (cur_prev < 0) { // process current animation, check for transition
+ if (cur_prev_index < 0) { // process current animation, check for transition
- rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
+ rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, 1.0, FILTER_IGNORE, true);
if (p_seek) {
cur_time = p_time;
@@ -770,8 +831,8 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
cur_time += p_time;
}
- if (inputs[cur_current].auto_advance && rem <= xfade_time) {
- set_parameter(current, (cur_current + 1) % enabled_inputs);
+ if (inputs[cur_current_index].auto_advance && rem <= xfade_time) {
+ set_parameter(transition_request, get_input_caption((cur_current_index + 1) % enabled_inputs));
}
} else { // cross-fading from prev to current
@@ -783,21 +844,21 @@ double AnimationNodeTransition::process(double p_time, bool p_seek, bool p_is_ex
// Blend values must be more than CMP_EPSILON to process discrete keys in edge.
real_t blend_inv = 1.0 - blend;
- if (from_start && !p_seek && switched) { //just switched, seek to start of current
- rem = blend_input(cur_current, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
+ if (reset && !p_seek && switched) { //just switched, seek to start of current
+ rem = blend_input(cur_current_index, 0, true, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
} else {
- rem = blend_input(cur_current, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
+ rem = blend_input(cur_current_index, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(blend_inv) ? CMP_EPSILON : blend_inv, FILTER_IGNORE, true);
}
if (p_seek) {
- blend_input(cur_prev, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
+ blend_input(cur_prev_index, p_time, true, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
cur_time = p_time;
} else {
- blend_input(cur_prev, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
+ blend_input(cur_prev_index, p_time, false, p_is_external_seeking, Math::is_zero_approx(blend) ? CMP_EPSILON : blend, FILTER_IGNORE, true);
cur_time += p_time;
cur_prev_xfading -= p_time;
if (cur_prev_xfading < 0) {
- set_parameter(prev, -1);
+ set_parameter(prev_index, -1);
}
}
}
@@ -829,6 +890,7 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_input_caption", "input", "caption"), &AnimationNodeTransition::set_input_caption);
ClassDB::bind_method(D_METHOD("get_input_caption", "input"), &AnimationNodeTransition::get_input_caption);
+ ClassDB::bind_method(D_METHOD("find_input_caption", "caption"), &AnimationNodeTransition::find_input_caption);
ClassDB::bind_method(D_METHOD("set_xfade_time", "time"), &AnimationNodeTransition::set_xfade_time);
ClassDB::bind_method(D_METHOD("get_xfade_time"), &AnimationNodeTransition::get_xfade_time);
@@ -836,13 +898,13 @@ void AnimationNodeTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeTransition::set_xfade_curve);
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeTransition::get_xfade_curve);
- ClassDB::bind_method(D_METHOD("set_from_start", "from_start"), &AnimationNodeTransition::set_from_start);
- ClassDB::bind_method(D_METHOD("is_from_start"), &AnimationNodeTransition::is_from_start);
+ ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeTransition::set_reset);
+ ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeTransition::is_reset);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,64,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "enabled_inputs", PROPERTY_HINT_RANGE, "0,31,1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED), "set_enabled_inputs", "get_enabled_inputs");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,120,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "from_start"), "set_from_start", "is_from_start");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset");
for (int i = 0; i < MAX_INPUTS; i++) {
ADD_PROPERTYI(PropertyInfo(Variant::STRING, "input_" + itos(i) + "/name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_INTERNAL), "set_input_caption", "get_input_caption", i);
diff --git a/scene/animation/animation_blend_tree.h b/scene/animation/animation_blend_tree.h
index e72471202e..a1969bb621 100644
--- a/scene/animation/animation_blend_tree.h
+++ b/scene/animation/animation_blend_tree.h
@@ -96,6 +96,12 @@ class AnimationNodeOneShot : public AnimationNodeSync {
GDCLASS(AnimationNodeOneShot, AnimationNodeSync);
public:
+ enum OneShotRequest {
+ ONE_SHOT_REQUEST_NONE,
+ ONE_SHOT_REQUEST_FIRE,
+ ONE_SHOT_REQUEST_ABORT,
+ };
+
enum MixMode {
MIX_MODE_BLEND,
MIX_MODE_ADD
@@ -110,13 +116,8 @@ private:
double autorestart_random_delay = 0.0;
MixMode mix = MIX_MODE_BLEND;
- /* bool active;
- bool do_start;
- double time;
- double remaining;*/
-
+ StringName request = PNAME("request");
StringName active = PNAME("active");
- StringName prev_active = "prev_active";
StringName time = "time";
StringName remaining = "remaining";
StringName time_to_restart = "time_to_restart";
@@ -127,6 +128,7 @@ protected:
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
+ virtual bool is_parameter_read_only(const StringName &p_parameter) const override;
virtual String get_caption() const override;
@@ -153,6 +155,7 @@ public:
AnimationNodeOneShot();
};
+VARIANT_ENUM_CAST(AnimationNodeOneShot::OneShotRequest)
VARIANT_ENUM_CAST(AnimationNodeOneShot::MixMode)
class AnimationNodeAdd2 : public AnimationNodeSync {
@@ -284,22 +287,19 @@ class AnimationNodeTransition : public AnimationNodeSync {
InputData inputs[MAX_INPUTS];
int enabled_inputs = 0;
- /*
- double prev_xfading;
- int prev;
- double time;
- int current;
- int prev_current; */
-
- StringName prev_xfading = "prev_xfading";
- StringName prev = "prev";
StringName time = "time";
- StringName current = PNAME("current");
- StringName prev_current = "prev_current";
+ StringName prev_xfading = "prev_xfading";
+ StringName prev_index = "prev_index";
+ StringName current_index = PNAME("current_index");
+ StringName current_state = PNAME("current_state");
+ StringName transition_request = PNAME("transition_request");
+
+ StringName prev_frame_current = "pf_current";
+ StringName prev_frame_current_idx = "pf_current_idx";
double xfade_time = 0.0;
Ref<Curve> xfade_curve;
- bool from_start = true;
+ bool reset = true;
void _update_inputs();
@@ -310,6 +310,7 @@ protected:
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const override;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const override;
+ virtual bool is_parameter_read_only(const StringName &p_parameter) const override;
virtual String get_caption() const override;
@@ -321,6 +322,7 @@ public:
void set_input_caption(int p_input, const String &p_name);
String get_input_caption(int p_input) const;
+ int find_input_caption(const String &p_name) const;
void set_xfade_time(double p_fade);
double get_xfade_time() const;
@@ -328,8 +330,8 @@ public:
void set_xfade_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_xfade_curve() const;
- void set_from_start(bool p_from_start);
- bool is_from_start() const;
+ void set_reset(bool p_reset);
+ bool is_reset() const;
double process(double p_time, bool p_seek, bool p_is_external_seeking) override;
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index f5df64dbdd..2c79e5fe06 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -107,6 +107,15 @@ Ref<Curve> AnimationNodeStateMachineTransition::get_xfade_curve() const {
return xfade_curve;
}
+void AnimationNodeStateMachineTransition::set_reset(bool p_reset) {
+ reset = p_reset;
+ emit_changed();
+}
+
+bool AnimationNodeStateMachineTransition::is_reset() const {
+ return reset;
+}
+
void AnimationNodeStateMachineTransition::set_priority(int p_priority) {
priority = p_priority;
emit_changed();
@@ -132,6 +141,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_xfade_curve", "curve"), &AnimationNodeStateMachineTransition::set_xfade_curve);
ClassDB::bind_method(D_METHOD("get_xfade_curve"), &AnimationNodeStateMachineTransition::get_xfade_curve);
+ ClassDB::bind_method(D_METHOD("set_reset", "reset"), &AnimationNodeStateMachineTransition::set_reset);
+ ClassDB::bind_method(D_METHOD("is_reset"), &AnimationNodeStateMachineTransition::is_reset);
+
ClassDB::bind_method(D_METHOD("set_priority", "priority"), &AnimationNodeStateMachineTransition::set_priority);
ClassDB::bind_method(D_METHOD("get_priority"), &AnimationNodeStateMachineTransition::get_priority);
@@ -140,6 +152,9 @@ void AnimationNodeStateMachineTransition::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "xfade_time", PROPERTY_HINT_RANGE, "0,240,0.01,suffix:s"), "set_xfade_time", "get_xfade_time");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "xfade_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_xfade_curve", "get_xfade_curve");
+
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "reset"), "set_reset", "is_reset");
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "priority", PROPERTY_HINT_RANGE, "0,32,1"), "set_priority", "get_priority");
ADD_GROUP("Switch", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "switch_mode", PROPERTY_HINT_ENUM, "Immediate,Sync,At End"), "set_switch_mode", "get_switch_mode");
@@ -164,18 +179,27 @@ AnimationNodeStateMachineTransition::AnimationNodeStateMachineTransition() {
////////////////////////////////////////////////////////
-void AnimationNodeStateMachinePlayback::travel(const StringName &p_state) {
- start_request_travel = true;
- start_request = p_state;
+void AnimationNodeStateMachinePlayback::travel(const StringName &p_state, bool p_reset_on_teleport) {
+ travel_request = p_state;
+ reset_request_on_teleport = p_reset_on_teleport;
stop_request = false;
}
-void AnimationNodeStateMachinePlayback::start(const StringName &p_state) {
- start_request_travel = false;
+void AnimationNodeStateMachinePlayback::start(const StringName &p_state, bool p_reset) {
+ travel_request = StringName();
+ reset_request = p_reset;
+ _start(p_state);
+}
+
+void AnimationNodeStateMachinePlayback::_start(const StringName &p_state) {
start_request = p_state;
stop_request = false;
}
+void AnimationNodeStateMachinePlayback::next() {
+ next_request = true;
+}
+
void AnimationNodeStateMachinePlayback::stop() {
stop_request = true;
}
@@ -212,7 +236,7 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
path.clear(); //a new one will be needed
if (current == p_travel) {
- return true; //nothing to do
+ return false; // Will teleport oneself (restart).
}
Vector2 current_pos = p_state_machine->states[current].position;
@@ -323,6 +347,15 @@ bool AnimationNodeStateMachinePlayback::_travel(AnimationNodeStateMachine *p_sta
}
double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) {
+ double rem = _process(p_state_machine, p_time, p_seek, p_is_external_seeking);
+ start_request = StringName();
+ next_request = false;
+ stop_request = false;
+ reset_request_on_teleport = false;
+ return rem;
+}
+
+double AnimationNodeStateMachinePlayback::_process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking) {
if (p_time == -1) {
Ref<AnimationNodeStateMachine> anodesm = p_state_machine->states[current].node;
if (anodesm.is_valid()) {
@@ -335,14 +368,13 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
//if not playing and it can restart, then restart
if (!playing && start_request == StringName()) {
if (!stop_request && p_state_machine->start_node) {
- start(p_state_machine->start_node);
+ _start(p_state_machine->start_node);
} else {
return 0;
}
}
if (playing && stop_request) {
- stop_request = false;
playing = false;
return 0;
}
@@ -350,42 +382,45 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
bool play_start = false;
if (start_request != StringName()) {
- if (start_request_travel) {
- if (!playing) {
- if (!stop_request && p_state_machine->start_node) {
- // can restart, just postpone traveling
- path.clear();
- current = p_state_machine->start_node;
- playing = true;
- play_start = true;
- } else {
- // stopped, invalid state
- String node_name = start_request;
- start_request = StringName(); //clear start request
- ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?");
- }
- } else {
- if (!_travel(p_state_machine, start_request)) {
- // can't travel, then teleport
- path.clear();
- current = start_request;
- play_start = true;
- }
- start_request = StringName(); //clear start request
- }
+ // teleport to start
+ if (p_state_machine->states.has(start_request)) {
+ path.clear();
+ current = start_request;
+ playing = true;
+ play_start = true;
} else {
- // teleport to start
- if (p_state_machine->states.has(start_request)) {
+ StringName node = start_request;
+ ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
+ }
+ } else if (travel_request != StringName()) {
+ if (!playing) {
+ if (!stop_request && p_state_machine->start_node) {
+ // can restart, just postpone traveling
path.clear();
- current = start_request;
+ current = p_state_machine->start_node;
playing = true;
play_start = true;
- start_request = StringName(); //clear start request
} else {
- StringName node = start_request;
- start_request = StringName(); //clear start request
- ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
+ // stopped, invalid state
+ String node_name = travel_request;
+ travel_request = StringName();
+ ERR_FAIL_V_MSG(0, "Can't travel to '" + node_name + "' if state machine is not playing. Maybe you need to enable Autoplay on Load for one of the nodes in your state machine or call .start() first?");
}
+ } else {
+ if (!_travel(p_state_machine, travel_request)) {
+ // can't travel, then teleport
+ if (p_state_machine->states.has(travel_request)) {
+ path.clear();
+ current = travel_request;
+ play_start = true;
+ reset_request = reset_request_on_teleport;
+ } else {
+ StringName node = travel_request;
+ travel_request = StringName();
+ ERR_FAIL_V_MSG(0, "No such node: '" + node + "'");
+ }
+ }
+ travel_request = StringName();
}
}
@@ -396,8 +431,11 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
current = p_state_machine->start_node;
}
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true);
- pos_current = 0;
+ if (reset_request) {
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, 1.0, AnimationNode::FILTER_IGNORE, true);
+ pos_current = 0;
+ reset_request = false;
+ }
}
if (!p_state_machine->states.has(current)) {
@@ -421,7 +459,8 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
if (current_curve.is_valid()) {
fade_blend = current_curve->sample(fade_blend);
}
- double rem = p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
+
+ double rem = do_start ? len_current : p_state_machine->blend_node(current, p_state_machine->states[current].node, p_time, p_seek, p_is_external_seeking, Math::is_zero_approx(fade_blend) ? CMP_EPSILON : fade_blend, AnimationNode::FILTER_IGNORE, true); // Blend values must be more than CMP_EPSILON to process discrete keys in edge.
if (fading_from != StringName()) {
double fade_blend_inv = 1.0 - fade_blend;
@@ -457,6 +496,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
next_xfade = p_state_machine->transitions[i].transition->get_xfade_time();
current_curve = p_state_machine->transitions[i].transition->get_xfade_curve();
switch_mode = p_state_machine->transitions[i].transition->get_switch_mode();
+ reset_request = p_state_machine->transitions[i].transition->is_reset();
next = path[0];
}
}
@@ -513,6 +553,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
current_curve = p_state_machine->transitions[auto_advance_to].transition->get_xfade_curve();
next_xfade = p_state_machine->transitions[auto_advance_to].transition->get_xfade_time();
switch_mode = p_state_machine->transitions[auto_advance_to].transition->get_switch_mode();
+ reset_request = p_state_machine->transitions[auto_advance_to].transition->is_reset();
}
}
@@ -567,7 +608,7 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
goto_next = fading_from == StringName();
}
- if (goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped
+ if (next_request || goto_next) { //end_loop should be used because fade time may be too small or zero and animation may have looped
if (next_xfade) {
//time to fade, baby
fading_from = current;
@@ -591,7 +632,9 @@ double AnimationNodeStateMachinePlayback::process(AnimationNodeStateMachine *p_s
current = next;
- len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here.
+ if (reset_request) {
+ len_current = p_state_machine->blend_node(current, p_state_machine->states[current].node, 0, true, p_is_external_seeking, CMP_EPSILON, AnimationNode::FILTER_IGNORE, true); // Process next node's first key in here.
+ }
if (switch_mode == AnimationNodeStateMachineTransition::SWITCH_MODE_SYNC) {
pos_current = MIN(pos_current, len_current);
p_state_machine->blend_node(current, p_state_machine->states[current].node, pos_current, true, p_is_external_seeking, 0, AnimationNode::FILTER_IGNORE, true);
@@ -652,8 +695,9 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima
}
void AnimationNodeStateMachinePlayback::_bind_methods() {
- ClassDB::bind_method(D_METHOD("travel", "to_node"), &AnimationNodeStateMachinePlayback::travel);
- ClassDB::bind_method(D_METHOD("start", "node"), &AnimationNodeStateMachinePlayback::start);
+ ClassDB::bind_method(D_METHOD("travel", "to_node", "reset_on_teleport"), &AnimationNodeStateMachinePlayback::travel, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("start", "node", "reset"), &AnimationNodeStateMachinePlayback::start, DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("next"), &AnimationNodeStateMachinePlayback::next);
ClassDB::bind_method(D_METHOD("stop"), &AnimationNodeStateMachinePlayback::stop);
ClassDB::bind_method(D_METHOD("is_playing"), &AnimationNodeStateMachinePlayback::is_playing);
ClassDB::bind_method(D_METHOD("get_current_node"), &AnimationNodeStateMachinePlayback::get_current_node);
diff --git a/scene/animation/animation_node_state_machine.h b/scene/animation/animation_node_state_machine.h
index 116589eb2f..8183d2025a 100644
--- a/scene/animation/animation_node_state_machine.h
+++ b/scene/animation/animation_node_state_machine.h
@@ -57,6 +57,7 @@ private:
StringName advance_condition_name;
float xfade_time = 0.0;
Ref<Curve> xfade_curve;
+ bool reset = true;
int priority = 1;
String advance_expression;
@@ -84,6 +85,9 @@ public:
void set_xfade_time(float p_xfade);
float get_xfade_time() const;
+ void set_reset(bool p_reset);
+ bool is_reset() const;
+
void set_xfade_curve(const Ref<Curve> &p_curve);
Ref<Curve> get_xfade_curve() const;
@@ -131,10 +135,15 @@ class AnimationNodeStateMachinePlayback : public Resource {
bool playing = false;
StringName start_request;
- bool start_request_travel = false;
+ StringName travel_request;
+ bool reset_request = false;
+ bool reset_request_on_teleport = false;
+ bool next_request = false;
bool stop_request = false;
bool _travel(AnimationNodeStateMachine *p_state_machine, const StringName &p_travel);
+ void _start(const StringName &p_state);
+ double _process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking);
double process(AnimationNodeStateMachine *p_state_machine, double p_time, bool p_seek, bool p_is_external_seeking);
@@ -144,8 +153,9 @@ protected:
static void _bind_methods();
public:
- void travel(const StringName &p_state);
- void start(const StringName &p_state);
+ void travel(const StringName &p_state, bool p_reset_on_teleport = true);
+ void start(const StringName &p_state, bool p_reset = true);
+ void next();
void stop();
bool is_playing() const;
StringName get_current_node() const;
diff --git a/scene/animation/animation_player.cpp b/scene/animation/animation_player.cpp
index d0875c2ba6..0febe580db 100644
--- a/scene/animation/animation_player.cpp
+++ b/scene/animation/animation_player.cpp
@@ -1736,11 +1736,11 @@ String AnimationPlayer::get_assigned_animation() const {
}
void AnimationPlayer::pause() {
- _stop_internal(false);
+ _stop_internal(false, false);
}
-void AnimationPlayer::stop() {
- _stop_internal(true);
+void AnimationPlayer::stop(bool p_keep_state) {
+ _stop_internal(true, p_keep_state);
}
void AnimationPlayer::set_speed_scale(float p_speed) {
@@ -1960,14 +1960,18 @@ void AnimationPlayer::_set_process(bool p_process, bool p_force) {
processing = p_process;
}
-void AnimationPlayer::_stop_internal(bool p_reset) {
+void AnimationPlayer::_stop_internal(bool p_reset, bool p_keep_state) {
_stop_playing_caches(p_reset);
Playback &c = playback;
c.blend.clear();
if (p_reset) {
- is_stopping = true;
- seek(0, true);
- is_stopping = false;
+ if (p_keep_state) {
+ c.current.pos = 0;
+ } else {
+ is_stopping = true;
+ seek(0, true);
+ is_stopping = false;
+ }
c.current.from = nullptr;
c.current.speed_scale = 1;
}
@@ -2100,7 +2104,7 @@ Ref<AnimatedValuesBackup> AnimationPlayer::apply_reset(bool p_user_initiated) {
Ref<AnimatedValuesBackup> new_values = aux_player->backup_animated_values();
old_values->restore();
- Ref<EditorUndoRedoManager> &ur = EditorNode::get_undo_redo();
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
ur->create_action(TTR("Animation Apply Reset"));
ur->add_do_method(new_values.ptr(), "restore");
ur->add_undo_method(old_values.ptr(), "restore");
@@ -2139,7 +2143,7 @@ void AnimationPlayer::_bind_methods() {
ClassDB::bind_method(D_METHOD("play", "name", "custom_blend", "custom_speed", "from_end"), &AnimationPlayer::play, DEFVAL(""), DEFVAL(-1), DEFVAL(1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("play_backwards", "name", "custom_blend"), &AnimationPlayer::play_backwards, DEFVAL(""), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("pause"), &AnimationPlayer::pause);
- ClassDB::bind_method(D_METHOD("stop"), &AnimationPlayer::stop);
+ ClassDB::bind_method(D_METHOD("stop", "keep_state"), &AnimationPlayer::stop, DEFVAL(false));
ClassDB::bind_method(D_METHOD("is_playing"), &AnimationPlayer::is_playing);
ClassDB::bind_method(D_METHOD("set_current_animation", "anim"), &AnimationPlayer::set_current_animation);
diff --git a/scene/animation/animation_player.h b/scene/animation/animation_player.h
index 8dfa7aed27..7e7d12f982 100644
--- a/scene/animation/animation_player.h
+++ b/scene/animation/animation_player.h
@@ -295,7 +295,7 @@ private:
void _animation_changed(const StringName &p_name);
void _set_process(bool p_process, bool p_force = false);
- void _stop_internal(bool p_reset);
+ void _stop_internal(bool p_reset, bool p_keep_state);
bool playing = false;
@@ -349,7 +349,7 @@ public:
Vector<String> get_queue();
void clear_queue();
void pause();
- void stop();
+ void stop(bool p_keep_state = false);
bool is_playing() const;
String get_current_animation() const;
void set_current_animation(const String &p_anim);
diff --git a/scene/animation/animation_tree.cpp b/scene/animation/animation_tree.cpp
index ab341797c7..dd00897422 100644
--- a/scene/animation/animation_tree.cpp
+++ b/scene/animation/animation_tree.cpp
@@ -54,13 +54,19 @@ Variant AnimationNode::get_parameter_default_value(const StringName &p_parameter
return ret;
}
+bool AnimationNode::is_parameter_read_only(const StringName &p_parameter) const {
+ bool ret = false;
+ GDVIRTUAL_CALL(_is_parameter_read_only, p_parameter, ret);
+ return ret;
+}
+
void AnimationNode::set_parameter(const StringName &p_name, const Variant &p_value) {
ERR_FAIL_COND(!state);
ERR_FAIL_COND(!state->tree->property_parent_map.has(base_path));
ERR_FAIL_COND(!state->tree->property_parent_map[base_path].has(p_name));
StringName path = state->tree->property_parent_map[base_path][p_name];
- state->tree->property_map[path] = p_value;
+ state->tree->property_map[path].first = p_value;
}
Variant AnimationNode::get_parameter(const StringName &p_name) const {
@@ -69,7 +75,7 @@ Variant AnimationNode::get_parameter(const StringName &p_name) const {
ERR_FAIL_COND_V(!state->tree->property_parent_map[base_path].has(p_name), Variant());
StringName path = state->tree->property_parent_map[base_path][p_name];
- return state->tree->property_map[path];
+ return state->tree->property_map[path].first;
}
void AnimationNode::get_child_nodes(List<ChildNode> *r_child_nodes) {
@@ -427,6 +433,7 @@ void AnimationNode::_bind_methods() {
GDVIRTUAL_BIND(_get_parameter_list);
GDVIRTUAL_BIND(_get_child_by_name, "name");
GDVIRTUAL_BIND(_get_parameter_default_value, "parameter");
+ GDVIRTUAL_BIND(_is_parameter_read_only, "parameter");
GDVIRTUAL_BIND(_process, "time", "seek", "is_external_seeking");
GDVIRTUAL_BIND(_get_caption);
GDVIRTUAL_BIND(_has_filter);
@@ -1889,7 +1896,10 @@ void AnimationTree::_update_properties_for_node(const String &p_base_path, Ref<A
StringName key = pinfo.name;
if (!property_map.has(p_base_path + key)) {
- property_map[p_base_path + key] = node->get_parameter_default_value(key);
+ Pair<Variant, bool> param;
+ param.first = node->get_parameter_default_value(key);
+ param.second = node->is_parameter_read_only(key);
+ property_map[p_base_path + key] = param;
}
property_parent_map[p_base_path][key] = p_base_path + key;
@@ -1931,7 +1941,10 @@ bool AnimationTree::_set(const StringName &p_name, const Variant &p_value) {
}
if (property_map.has(p_name)) {
- property_map[p_name] = p_value;
+ if (is_inside_tree() && property_map[p_name].second) {
+ return false; // Prevent to set property by user.
+ }
+ property_map[p_name].first = p_value;
return true;
}
@@ -1944,7 +1957,7 @@ bool AnimationTree::_get(const StringName &p_name, Variant &r_ret) const {
}
if (property_map.has(p_name)) {
- r_ret = property_map[p_name];
+ r_ret = property_map[p_name].first;
return true;
}
diff --git a/scene/animation/animation_tree.h b/scene/animation/animation_tree.h
index 2c1be6199c..52d3e1bd41 100644
--- a/scene/animation/animation_tree.h
+++ b/scene/animation/animation_tree.h
@@ -117,6 +117,7 @@ protected:
GDVIRTUAL0RC(Array, _get_parameter_list)
GDVIRTUAL1RC(Ref<AnimationNode>, _get_child_by_name, StringName)
GDVIRTUAL1RC(Variant, _get_parameter_default_value, StringName)
+ GDVIRTUAL1RC(bool, _is_parameter_read_only, StringName)
GDVIRTUAL3RC(double, _process, double, bool, bool)
GDVIRTUAL0RC(String, _get_caption)
GDVIRTUAL0RC(bool, _has_filter)
@@ -124,6 +125,7 @@ protected:
public:
virtual void get_parameter_list(List<PropertyInfo> *r_list) const;
virtual Variant get_parameter_default_value(const StringName &p_parameter) const;
+ virtual bool is_parameter_read_only(const StringName &p_parameter) const;
void set_parameter(const StringName &p_name, const Variant &p_value);
Variant get_parameter(const StringName &p_name) const;
@@ -304,7 +306,7 @@ private:
void _update_properties();
List<PropertyInfo> properties;
HashMap<StringName, HashMap<StringName, StringName>> property_parent_map;
- HashMap<StringName, Variant> property_map;
+ HashMap<StringName, Pair<Variant, bool>> property_map; // Property value and read-only flag.
struct Activity {
uint64_t last_pass = 0;
diff --git a/scene/animation/tween.cpp b/scene/animation/tween.cpp
index be8c23844f..39d1793368 100644
--- a/scene/animation/tween.cpp
+++ b/scene/animation/tween.cpp
@@ -280,7 +280,16 @@ bool Tween::step(double p_delta) {
}
if (!started) {
- ERR_FAIL_COND_V_MSG(tweeners.is_empty(), false, "Tween started, but has no Tweeners.");
+ if (tweeners.is_empty()) {
+ String tween_id;
+ Node *node = get_bound_node();
+ if (node) {
+ tween_id = vformat("Tween (bound to %s)", node->is_inside_tree() ? (String)node->get_path() : (String)node->get_name());
+ } else {
+ tween_id = to_string();
+ }
+ ERR_FAIL_V_MSG(false, tween_id + ": started with no Tweeners.");
+ }
current_step = 0;
loops_done = 0;
total_time = 0;
@@ -393,6 +402,15 @@ Variant Tween::interpolate_variant(Variant p_initial_val, Variant p_delta_val, d
return ret;
}
+String Tween::to_string() {
+ String ret = Object::to_string();
+ Node *node = get_bound_node();
+ if (node) {
+ ret += vformat(" (bound to %s)", node->get_name());
+ }
+ return ret;
+}
+
void Tween::_bind_methods() {
ClassDB::bind_method(D_METHOD("tween_property", "object", "property", "final_val", "duration"), &Tween::tween_property);
ClassDB::bind_method(D_METHOD("tween_interval", "time"), &Tween::tween_interval);
diff --git a/scene/animation/tween.h b/scene/animation/tween.h
index 08911d6623..58217db535 100644
--- a/scene/animation/tween.h
+++ b/scene/animation/tween.h
@@ -130,6 +130,8 @@ protected:
static void _bind_methods();
public:
+ virtual String to_string() override;
+
Ref<PropertyTweener> tween_property(Object *p_target, NodePath p_property, Variant p_to, double p_duration);
Ref<IntervalTweener> tween_interval(double p_time);
Ref<CallbackTweener> tween_callback(Callable p_callback);
diff --git a/scene/gui/base_button.cpp b/scene/gui/base_button.cpp
index 9cc25bf743..472299b135 100644
--- a/scene/gui/base_button.cpp
+++ b/scene/gui/base_button.cpp
@@ -30,6 +30,7 @@
#include "base_button.h"
+#include "core/config/project_settings.h"
#include "core/os/keyboard.h"
#include "scene/main/window.h"
#include "scene/scene_string_names.h"
@@ -127,7 +128,6 @@ void BaseButton::_notification(int p_what) {
status.hovering = false;
status.press_attempt = false;
status.pressing_inside = false;
- status.shortcut_press = false;
} break;
}
}
@@ -154,14 +154,10 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
if (status.press_attempt && status.pressing_inside) {
if (toggle_mode) {
bool is_pressed = p_event->is_pressed();
- if (Object::cast_to<InputEventShortcut>(*p_event)) {
- is_pressed = false;
- }
if ((is_pressed && action_mode == ACTION_MODE_BUTTON_PRESS) || (!is_pressed && action_mode == ACTION_MODE_BUTTON_RELEASE)) {
if (action_mode == ACTION_MODE_BUTTON_PRESS) {
status.press_attempt = false;
status.pressing_inside = false;
- status.shortcut_press = false;
}
status.pressed = !status.pressed;
_unpress_group();
@@ -187,7 +183,6 @@ void BaseButton::on_action_event(Ref<InputEvent> p_event) {
}
status.press_attempt = false;
status.pressing_inside = false;
- status.shortcut_press = false;
emit_signal(SNAME("button_up"));
}
@@ -212,7 +207,6 @@ void BaseButton::set_disabled(bool p_disabled) {
}
status.press_attempt = false;
status.pressing_inside = false;
- status.shortcut_press = false;
}
queue_redraw();
}
@@ -267,6 +261,10 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
return DRAW_DISABLED;
}
+ if (in_shortcut_feedback) {
+ return DRAW_HOVER_PRESSED;
+ }
+
if (!status.press_attempt && status.hovering) {
if (status.pressed) {
return DRAW_HOVER_PRESSED;
@@ -285,7 +283,7 @@ BaseButton::DrawMode BaseButton::get_draw_mode() const {
pressing = status.pressed;
}
- if ((shortcut_feedback || !status.shortcut_press) && pressing) {
+ if (pressing) {
return DRAW_PRESSED;
} else {
return DRAW_NORMAL;
@@ -339,6 +337,14 @@ bool BaseButton::is_keep_pressed_outside() const {
return keep_pressed_outside;
}
+void BaseButton::set_shortcut_feedback(bool p_enable) {
+ shortcut_feedback = p_enable;
+}
+
+bool BaseButton::is_shortcut_feedback() const {
+ return shortcut_feedback;
+}
+
void BaseButton::set_shortcut(const Ref<Shortcut> &p_shortcut) {
shortcut = p_shortcut;
set_process_shortcut_input(shortcut.is_valid());
@@ -348,13 +354,46 @@ Ref<Shortcut> BaseButton::get_shortcut() const {
return shortcut;
}
+void BaseButton::_shortcut_feedback_timeout() {
+ in_shortcut_feedback = false;
+ queue_redraw();
+}
+
void BaseButton::shortcut_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
- if (!is_disabled() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) {
- status.shortcut_press = true;
- on_action_event(p_event);
+ if (!is_disabled() && p_event->is_pressed() && is_visible_in_tree() && !p_event->is_echo() && shortcut.is_valid() && shortcut->matches_event(p_event)) {
+ if (toggle_mode) {
+ status.pressed = !status.pressed;
+
+ if (status.pressed) {
+ _unpress_group();
+ if (button_group.is_valid()) {
+ button_group->emit_signal(SNAME("pressed"), this);
+ }
+ }
+
+ _toggled(status.pressed);
+ _pressed();
+
+ } else {
+ _pressed();
+ }
+ queue_redraw();
accept_event();
+
+ if (shortcut_feedback) {
+ if (shortcut_feedback_timer == nullptr) {
+ shortcut_feedback_timer = memnew(Timer);
+ shortcut_feedback_timer->set_one_shot(true);
+ add_child(shortcut_feedback_timer);
+ shortcut_feedback_timer->set_wait_time(GLOBAL_GET("gui/timers/button_shortcut_feedback_highlight_time"));
+ shortcut_feedback_timer->connect("timeout", callable_mp(this, &BaseButton::_shortcut_feedback_timeout));
+ }
+
+ in_shortcut_feedback = true;
+ shortcut_feedback_timer->start();
+ }
}
}
@@ -393,14 +432,6 @@ bool BaseButton::_was_pressed_by_mouse() const {
return was_mouse_pressed;
}
-void BaseButton::set_shortcut_feedback(bool p_feedback) {
- shortcut_feedback = p_feedback;
-}
-
-bool BaseButton::is_shortcut_feedback() const {
- return shortcut_feedback;
-}
-
PackedStringArray BaseButton::get_configuration_warnings() const {
PackedStringArray warnings = Control::get_configuration_warnings();
@@ -429,6 +460,8 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_draw_mode"), &BaseButton::get_draw_mode);
ClassDB::bind_method(D_METHOD("set_keep_pressed_outside", "enabled"), &BaseButton::set_keep_pressed_outside);
ClassDB::bind_method(D_METHOD("is_keep_pressed_outside"), &BaseButton::is_keep_pressed_outside);
+ ClassDB::bind_method(D_METHOD("set_shortcut_feedback", "enabled"), &BaseButton::set_shortcut_feedback);
+ ClassDB::bind_method(D_METHOD("is_shortcut_feedback"), &BaseButton::is_shortcut_feedback);
ClassDB::bind_method(D_METHOD("set_shortcut", "shortcut"), &BaseButton::set_shortcut);
ClassDB::bind_method(D_METHOD("get_shortcut"), &BaseButton::get_shortcut);
@@ -436,9 +469,6 @@ void BaseButton::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_button_group", "button_group"), &BaseButton::set_button_group);
ClassDB::bind_method(D_METHOD("get_button_group"), &BaseButton::get_button_group);
- ClassDB::bind_method(D_METHOD("set_shortcut_feedback", "enabled"), &BaseButton::set_shortcut_feedback);
- ClassDB::bind_method(D_METHOD("is_shortcut_feedback"), &BaseButton::is_shortcut_feedback);
-
GDVIRTUAL_BIND(_pressed);
GDVIRTUAL_BIND(_toggled, "button_pressed");
@@ -466,6 +496,8 @@ void BaseButton::_bind_methods() {
BIND_ENUM_CONSTANT(ACTION_MODE_BUTTON_PRESS);
BIND_ENUM_CONSTANT(ACTION_MODE_BUTTON_RELEASE);
+
+ GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/timers/button_shortcut_feedback_highlight_time", PROPERTY_HINT_RANGE, "0.01,10,0.01,suffix:s"), 0.2);
}
BaseButton::BaseButton() {
diff --git a/scene/gui/base_button.h b/scene/gui/base_button.h
index f7c864c5fb..962a16c453 100644
--- a/scene/gui/base_button.h
+++ b/scene/gui/base_button.h
@@ -51,9 +51,9 @@ private:
bool shortcut_in_tooltip = true;
bool was_mouse_pressed = false;
bool keep_pressed_outside = false;
+ bool shortcut_feedback = true;
Ref<Shortcut> shortcut;
ObjectID shortcut_context;
- bool shortcut_feedback = true;
ActionMode action_mode = ACTION_MODE_BUTTON_RELEASE;
struct Status {
@@ -61,7 +61,6 @@ private:
bool hovering = false;
bool press_attempt = false;
bool pressing_inside = false;
- bool shortcut_press = false;
bool disabled = false;
@@ -75,6 +74,10 @@ private:
void on_action_event(Ref<InputEvent> p_event);
+ Timer *shortcut_feedback_timer = nullptr;
+ bool in_shortcut_feedback = false;
+ void _shortcut_feedback_timeout();
+
protected:
virtual void pressed();
virtual void toggled(bool p_pressed);
@@ -122,6 +125,9 @@ public:
void set_keep_pressed_outside(bool p_on);
bool is_keep_pressed_outside() const;
+ void set_shortcut_feedback(bool p_enable);
+ bool is_shortcut_feedback() const;
+
void set_button_mask(BitField<MouseButtonMask> p_mask);
BitField<MouseButtonMask> get_button_mask() const;
@@ -133,9 +139,6 @@ public:
void set_button_group(const Ref<ButtonGroup> &p_group);
Ref<ButtonGroup> get_button_group() const;
- void set_shortcut_feedback(bool p_feedback);
- bool is_shortcut_feedback() const;
-
PackedStringArray get_configuration_warnings() const override;
BaseButton();
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 7539810feb..c977d9d2fb 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -548,7 +548,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
}
if (k->is_action("ui_text_dedent", true)) {
- do_unindent();
+ unindent_lines();
accept_event();
return;
}
@@ -898,50 +898,6 @@ void CodeEdit::indent_lines() {
end_complex_operation();
}
-void CodeEdit::do_unindent() {
- if (!is_editable()) {
- return;
- }
-
- int cc = get_caret_column();
-
- if (has_selection() || cc <= 0) {
- unindent_lines();
- return;
- }
-
- begin_complex_operation();
- Vector<int> caret_edit_order = get_caret_index_edit_order();
- for (const int &c : caret_edit_order) {
- int cl = get_caret_line(c);
- const String &line = get_line(cl);
-
- if (line[cc - 1] == '\t') {
- remove_text(cl, cc - 1, cl, cc);
- set_caret_column(MAX(0, cc - 1), c == 0, c);
- adjust_carets_after_edit(c, cl, cc, cl, cc - 1);
- continue;
- }
-
- if (line[cc - 1] != ' ') {
- continue;
- }
-
- int spaces_to_remove = _calculate_spaces_till_next_left_indent(cc);
- if (spaces_to_remove > 0) {
- for (int i = 1; i <= spaces_to_remove; i++) {
- if (line[cc - i] != ' ') {
- spaces_to_remove = i - 1;
- break;
- }
- }
- remove_text(cl, cc - spaces_to_remove, cl, cc);
- set_caret_column(MAX(0, cc - spaces_to_remove), c == 0, c);
- }
- }
- end_complex_operation();
-}
-
void CodeEdit::unindent_lines() {
if (!is_editable()) {
return;
@@ -2086,9 +2042,11 @@ void CodeEdit::confirm_code_completion(bool p_replace) {
int post_brace_pair = get_caret_column(i) < get_line(caret_line).length() ? _get_auto_brace_pair_close_at_pos(caret_line, get_caret_column(i)) : -1;
// Strings do not nest like brackets, so ensure we don't add an additional closing pair.
- if (has_string_delimiter(String::chr(last_completion_char)) && post_brace_pair != -1 && last_char_matches) {
- remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
- adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ if (has_string_delimiter(String::chr(last_completion_char))) {
+ if (post_brace_pair != -1 && last_char_matches) {
+ remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ adjust_carets_after_edit(i, caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
+ }
} else {
if (pre_brace_pair != -1 && pre_brace_pair != post_brace_pair && last_char_matches) {
remove_text(caret_line, get_caret_column(i), caret_line, get_caret_column(i) + 1);
@@ -2202,7 +2160,6 @@ void CodeEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_auto_indent_prefixes"), &CodeEdit::get_auto_indent_prefixes);
ClassDB::bind_method(D_METHOD("do_indent"), &CodeEdit::do_indent);
- ClassDB::bind_method(D_METHOD("do_unindent"), &CodeEdit::do_unindent);
ClassDB::bind_method(D_METHOD("indent_lines"), &CodeEdit::indent_lines);
ClassDB::bind_method(D_METHOD("unindent_lines"), &CodeEdit::unindent_lines);
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index c050b2266f..55fc5aa2ae 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -289,7 +289,6 @@ public:
TypedArray<String> get_auto_indent_prefixes() const;
void do_indent();
- void do_unindent();
void indent_lines();
void unindent_lines();
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index b5846cb692..b0261dcf23 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -642,7 +642,7 @@ inline int ColorPicker::_get_preset_size() {
void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
ColorPresetButton *btn_preset_new = memnew(ColorPresetButton(p_color, p_size));
btn_preset_new->set_tooltip_text(vformat(RTR("Color: #%s\nLMB: Apply color\nRMB: Remove preset"), p_color.to_html(p_color.a < 1)));
- btn_preset_new->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCDU(btn_preset_new, ColorPicker);
btn_preset_new->set_button_group(preset_group);
preset_container->add_child(btn_preset_new);
btn_preset_new->set_pressed(true);
@@ -1544,10 +1544,6 @@ void ColorPicker::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_picker_shape", "shape"), &ColorPicker::set_picker_shape);
ClassDB::bind_method(D_METHOD("get_picker_shape"), &ColorPicker::get_picker_shape);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &ColorPicker::_get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &ColorPicker::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &ColorPicker::_drop_data_fw);
-
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::INT, "color_mode", PROPERTY_HINT_ENUM, "RGB,HSV,RAW,OKHSL"), "set_color_mode", "get_color_mode");
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index 4188946494..fead0878fb 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -758,6 +758,7 @@ void Control::set_anchor_and_offset(Side p_side, real_t p_anchor, real_t p_pos,
}
void Control::set_begin(const Size2 &p_point) {
+ ERR_FAIL_COND(!isfinite(p_point.x) || !isfinite(p_point.y));
if (data.offset[0] == p_point.x && data.offset[1] == p_point.y) {
return;
}
@@ -1405,6 +1406,7 @@ void Control::_set_size(const Size2 &p_size) {
}
void Control::set_size(const Size2 &p_size, bool p_keep_offsets) {
+ ERR_FAIL_COND(!isfinite(p_size.x) || !isfinite(p_size.y));
Size2 new_size = p_size;
Size2 min = get_combined_minimum_size();
if (new_size.x < min.x) {
@@ -1580,10 +1582,6 @@ void Control::set_block_minimum_size_adjust(bool p_block) {
data.block_minimum_size_adjust = p_block;
}
-bool Control::is_minimum_size_adjust_blocked() const {
- return data.block_minimum_size_adjust;
-}
-
Size2 Control::get_minimum_size() const {
Vector2 ms;
GDVIRTUAL_CALL(_get_minimum_size, ms);
@@ -1595,7 +1593,7 @@ void Control::set_custom_minimum_size(const Size2 &p_custom) {
return;
}
- if (isnan(p_custom.x) || isnan(p_custom.y)) {
+ if (!isfinite(p_custom.x) || !isfinite(p_custom.y)) {
// Prevent infinite loop.
return;
}
@@ -1821,19 +1819,6 @@ bool Control::is_focus_owner_in_shortcut_context() const {
// Drag and drop handling.
-void Control::set_drag_forwarding_compat(Object *p_base) {
- if (p_base != nullptr) {
- data.forward_drag = Callable(p_base, "_get_drag_data_fw").bind(this);
- data.forward_can_drop = Callable(p_base, "_can_drop_data_fw").bind(this);
- data.forward_drop = Callable(p_base, "_drop_data_fw").bind(this);
-
- } else {
- data.forward_drag = Callable();
- data.forward_can_drop = Callable();
- data.forward_drop = Callable();
- }
-}
-
void Control::set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop) {
data.forward_drag = p_drag;
data.forward_can_drop = p_can_drop;
@@ -2780,9 +2765,9 @@ void Control::end_bulk_theme_override() {
// Internationalization.
-TypedArray<Vector2i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+TypedArray<Vector3i> Control::structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
if (p_parser_type == TextServer::STRUCTURED_TEXT_CUSTOM) {
- TypedArray<Vector2i> ret;
+ TypedArray<Vector3i> ret;
GDVIRTUAL_CALL(_structured_text_parser, p_args, p_text, ret);
return ret;
} else {
diff --git a/scene/gui/control.h b/scene/gui/control.h
index 22a37dd89e..a93a88e5b4 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -145,7 +145,7 @@ public:
TEXT_DIRECTION_AUTO = TextServer::DIRECTION_AUTO,
TEXT_DIRECTION_LTR = TextServer::DIRECTION_LTR,
TEXT_DIRECTION_RTL = TextServer::DIRECTION_RTL,
- TEXT_DIRECTION_INHERITED,
+ TEXT_DIRECTION_INHERITED = TextServer::DIRECTION_INHERITED,
};
private:
@@ -330,7 +330,7 @@ protected:
// Internationalization.
- virtual TypedArray<Vector2i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ virtual TypedArray<Vector3i> structured_text_parser(TextServer::StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
// Base object overrides.
@@ -340,7 +340,7 @@ protected:
// Exposed virtual methods.
GDVIRTUAL1RC(bool, _has_point, Vector2)
- GDVIRTUAL2RC(TypedArray<Vector2i>, _structured_text_parser, Array, String)
+ GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
GDVIRTUAL0RC(Vector2, _get_minimum_size)
GDVIRTUAL1RC(Variant, _get_drag_data, Vector2)
@@ -464,7 +464,6 @@ public:
void update_minimum_size();
void set_block_minimum_size_adjust(bool p_block);
- bool is_minimum_size_adjust_blocked() const;
virtual Size2 get_minimum_size() const;
virtual Size2 get_combined_minimum_size() const;
@@ -503,7 +502,6 @@ public:
// Drag and drop handling.
virtual void set_drag_forwarding(const Callable &p_drag, const Callable &p_can_drop, const Callable &p_drop);
- virtual void set_drag_forwarding_compat(Object *p_base);
virtual Variant get_drag_data(const Point2 &p_point);
virtual bool can_drop_data(const Point2 &p_point, const Variant &p_data) const;
virtual void drop_data(const Point2 &p_point, const Variant &p_data);
@@ -634,4 +632,10 @@ VARIANT_ENUM_CAST(Control::LayoutMode);
VARIANT_ENUM_CAST(Control::LayoutDirection);
VARIANT_ENUM_CAST(Control::TextDirection);
+// G = get_drag_data_fw, C = can_drop_data_fw, D = drop_data_fw, U = underscore
+#define SET_DRAG_FORWARDING_CD(from, to) from->set_drag_forwarding(Callable(), callable_mp(this, &to::can_drop_data_fw).bind(from), callable_mp(this, &to::drop_data_fw).bind(from));
+#define SET_DRAG_FORWARDING_CDU(from, to) from->set_drag_forwarding(Callable(), callable_mp(this, &to::_can_drop_data_fw).bind(from), callable_mp(this, &to::_drop_data_fw).bind(from));
+#define SET_DRAG_FORWARDING_GCD(from, to) from->set_drag_forwarding(callable_mp(this, &to::get_drag_data_fw).bind(from), callable_mp(this, &to::can_drop_data_fw).bind(from), callable_mp(this, &to::drop_data_fw).bind(from));
+#define SET_DRAG_FORWARDING_GCDU(from, to) from->set_drag_forwarding(callable_mp(this, &to::_get_drag_data_fw).bind(from), callable_mp(this, &to::_can_drop_data_fw).bind(from), callable_mp(this, &to::_drop_data_fw).bind(from));
+
#endif // CONTROL_H
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index 2fd6d666e5..6c495ab2c9 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -1496,6 +1496,7 @@ float GraphEdit::get_zoom() const {
void GraphEdit::set_zoom_step(float p_zoom_step) {
p_zoom_step = abs(p_zoom_step);
+ ERR_FAIL_COND(!isfinite(p_zoom_step));
if (zoom_step == p_zoom_step) {
return;
}
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index 372baeadae..25a27d5e1a 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -309,12 +309,6 @@ void ItemList::set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon) {
shape_changed = true;
}
-Ref<Texture2D> ItemList::get_item_tag_icon(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, items.size(), Ref<Texture2D>());
-
- return items[p_idx].tag_icon;
-}
-
void ItemList::set_item_selectable(int p_idx, bool p_selectable) {
if (p_idx < 0) {
p_idx += get_item_count();
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index 848f9a2ba9..934318dbb4 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -191,7 +191,6 @@ public:
Variant get_item_metadata(int p_idx) const;
void set_item_tag_icon(int p_idx, const Ref<Texture2D> &p_tag_icon);
- Ref<Texture2D> get_item_tag_icon(int p_idx) const;
void set_item_tooltip_enabled(int p_idx, const bool p_enabled);
bool is_item_tooltip_enabled(int p_idx) const;
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index cafea83f16..f59702835c 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -222,6 +222,7 @@ void Label::_shape() {
}
}
lines_dirty = false;
+ lines_shaped_last_width = get_size().width;
}
_update_visible();
@@ -596,7 +597,13 @@ void Label::_notification(int p_what) {
} break;
case NOTIFICATION_RESIZED: {
- lines_dirty = true;
+ // It may happen that the reshaping due to this size change triggers a cascade of re-layout
+ // across the hierarchy where this label belongs to in a way that its size changes multiple
+ // times, but ending up with the original size it was already shaped for.
+ // This check prevents the catastrophic, freezing infinite cascade of re-layout.
+ if (lines_shaped_last_width != get_size().width) {
+ lines_dirty = true;
+ }
} break;
}
}
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 2350525236..b80646810b 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -49,6 +49,8 @@ private:
bool uppercase = false;
bool lines_dirty = true;
+ int lines_shaped_last_width = -1;
+
bool dirty = true;
bool font_dirty = true;
RID text_rid;
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index 5ab64b35fd..a7e50a765e 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -4074,8 +4074,8 @@ void RichTextLabel::append_text(const String &p_bbcode) {
st_parser_type = TextServer::STRUCTURED_TEXT_EMAIL;
} else if (subtag_a[1] == "l" || subtag_a[1] == "list") {
st_parser_type = TextServer::STRUCTURED_TEXT_LIST;
- } else if (subtag_a[1] == "n" || subtag_a[1] == "none") {
- st_parser_type = TextServer::STRUCTURED_TEXT_NONE;
+ } else if (subtag_a[1] == "n" || subtag_a[1] == "gdscript") {
+ st_parser_type = TextServer::STRUCTURED_TEXT_GDSCRIPT;
} else if (subtag_a[1] == "c" || subtag_a[1] == "custom") {
st_parser_type = TextServer::STRUCTURED_TEXT_CUSTOM;
}
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 3457cfa94f..208cb29772 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -954,9 +954,6 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("_repaint"), &TabContainer::_repaint);
ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);
- ClassDB::bind_method(D_METHOD("_get_drag_data_fw"), &TabContainer::_get_drag_data_fw);
- ClassDB::bind_method(D_METHOD("_can_drop_data_fw"), &TabContainer::_can_drop_data_fw);
- ClassDB::bind_method(D_METHOD("_drop_data_fw"), &TabContainer::_drop_data_fw);
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("tab_selected", PropertyInfo(Variant::INT, "tab")));
@@ -975,7 +972,7 @@ void TabContainer::_bind_methods() {
TabContainer::TabContainer() {
tab_bar = memnew(TabBar);
- tab_bar->set_drag_forwarding_compat(this);
+ SET_DRAG_FORWARDING_GCDU(tab_bar, TabContainer);
add_child(tab_bar, false, INTERNAL_MODE_FRONT);
tab_bar->set_anchors_and_offsets_preset(Control::PRESET_TOP_WIDE);
tab_bar->connect("tab_changed", callable_mp(this, &TabContainer::_on_tab_changed));
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 108a533a74..8ffaa9e81f 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -1208,7 +1208,15 @@ void TextEdit::_notification(int p_what) {
char_ofs = 0;
}
for (int j = 0; j < gl_size; j++) {
- const Variant *color_data = color_map.getptr(glyphs[j].start);
+ int64_t color_start = -1;
+ for (const Variant *key = color_map.next(nullptr); key; key = color_map.next(key)) {
+ if (int64_t(*key) <= glyphs[j].start) {
+ color_start = *key;
+ } else {
+ break;
+ }
+ }
+ const Variant *color_data = (color_start >= 0) ? color_map.getptr(color_start) : nullptr;
if (color_data != nullptr) {
current_color = (color_data->operator Dictionary()).get("color", font_color);
if (!editable && current_color.a > font_readonly_color.a) {
diff --git a/scene/gui/texture_rect.cpp b/scene/gui/texture_rect.cpp
index 5a3f4af106..20472ab46e 100644
--- a/scene/gui/texture_rect.cpp
+++ b/scene/gui/texture_rect.cpp
@@ -178,6 +178,16 @@ void TextureRect::_bind_methods() {
BIND_ENUM_CONSTANT(STRETCH_KEEP_ASPECT_COVERED);
}
+#ifndef DISABLE_DEPRECATED
+bool TextureRect::_set(const StringName &p_name, const Variant &p_value) {
+ if ((p_name == SNAME("expand") || p_name == SNAME("ignore_texture_size")) && p_value.operator bool()) {
+ expand_mode = EXPAND_IGNORE_SIZE;
+ return true;
+ }
+ return false;
+}
+#endif
+
void TextureRect::_texture_changed() {
if (texture.is_valid()) {
queue_redraw();
diff --git a/scene/gui/texture_rect.h b/scene/gui/texture_rect.h
index 6f17ebd87f..2425c6094b 100644
--- a/scene/gui/texture_rect.h
+++ b/scene/gui/texture_rect.h
@@ -69,6 +69,9 @@ protected:
void _notification(int p_what);
virtual Size2 get_minimum_size() const override;
static void _bind_methods();
+#ifndef DISABLE_DEPRECATED
+ bool _set(const StringName &p_name, const Variant &p_value);
+#endif
public:
void set_texture(const Ref<Texture2D> &p_tex);
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 3458b87b8d..2d985c2324 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -332,7 +332,7 @@ void TreeItem::set_structured_text_bidi_override(int p_column, TextServer::Struc
}
TextServer::StructuredTextParser TreeItem::get_structured_text_bidi_override(int p_column) const {
- ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::STRUCTURED_TEXT_NONE);
+ ERR_FAIL_INDEX_V(p_column, cells.size(), TextServer::STRUCTURED_TEXT_DEFAULT);
return cells[p_column].st_parser;
}
@@ -657,7 +657,7 @@ int TreeItem::get_custom_minimum_height() const {
/* Item manipulation */
-TreeItem *TreeItem::create_child(int p_idx) {
+TreeItem *TreeItem::create_child(int p_index) {
TreeItem *ti = memnew(TreeItem(tree));
if (tree) {
ti->cells.resize(tree->columns.size());
@@ -669,7 +669,7 @@ TreeItem *TreeItem::create_child(int p_idx) {
int idx = 0;
while (c) {
- if (idx++ == p_idx) {
+ if (idx++ == p_index) {
c->prev = ti;
ti->next = c;
break;
@@ -683,7 +683,7 @@ TreeItem *TreeItem::create_child(int p_idx) {
ti->prev = l_prev;
if (!children_cache.is_empty()) {
if (ti->next) {
- children_cache.insert(p_idx, ti);
+ children_cache.insert(p_index, ti);
} else {
children_cache.append(ti);
}
@@ -826,15 +826,15 @@ TreeItem *TreeItem::get_next_visible(bool p_wrap) {
return next_item;
}
-TreeItem *TreeItem::get_child(int p_idx) {
+TreeItem *TreeItem::get_child(int p_index) {
_create_children_cache();
- if (p_idx < 0) {
- p_idx += children_cache.size();
+ if (p_index < 0) {
+ p_index += children_cache.size();
}
- ERR_FAIL_INDEX_V(p_idx, children_cache.size(), nullptr);
+ ERR_FAIL_INDEX_V(p_index, children_cache.size(), nullptr);
- return children_cache.get(p_idx);
+ return children_cache.get(p_index);
}
int TreeItem::get_visible_child_count() {
@@ -1058,28 +1058,28 @@ int TreeItem::get_button_count(int p_column) const {
return cells[p_column].buttons.size();
}
-Ref<Texture2D> TreeItem::get_button(int p_column, int p_idx) const {
+Ref<Texture2D> TreeItem::get_button(int p_column, int p_index) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), Ref<Texture2D>());
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), Ref<Texture2D>());
- return cells[p_column].buttons[p_idx].texture;
+ ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), Ref<Texture2D>());
+ return cells[p_column].buttons[p_index].texture;
}
-String TreeItem::get_button_tooltip_text(int p_column, int p_idx) const {
+String TreeItem::get_button_tooltip_text(int p_column, int p_index) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), String());
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), String());
- return cells[p_column].buttons[p_idx].tooltip;
+ ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), String());
+ return cells[p_column].buttons[p_index].tooltip;
}
-int TreeItem::get_button_id(int p_column, int p_idx) const {
+int TreeItem::get_button_id(int p_column, int p_index) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), -1);
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), -1);
- return cells[p_column].buttons[p_idx].id;
+ ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), -1);
+ return cells[p_column].buttons[p_index].id;
}
-void TreeItem::erase_button(int p_column, int p_idx) {
+void TreeItem::erase_button(int p_column, int p_index) {
ERR_FAIL_INDEX(p_column, cells.size());
- ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
- cells.write[p_column].buttons.remove_at(p_idx);
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
+ cells.write[p_column].buttons.remove_at(p_index);
_changed_notify(p_column);
}
@@ -1094,52 +1094,52 @@ int TreeItem::get_button_by_id(int p_column, int p_id) const {
return -1;
}
-void TreeItem::set_button(int p_column, int p_idx, const Ref<Texture2D> &p_button) {
+void TreeItem::set_button(int p_column, int p_index, const Ref<Texture2D> &p_button) {
ERR_FAIL_COND(p_button.is_null());
ERR_FAIL_INDEX(p_column, cells.size());
- ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
- if (cells[p_column].buttons[p_idx].texture == p_button) {
+ if (cells[p_column].buttons[p_index].texture == p_button) {
return;
}
- cells.write[p_column].buttons.write[p_idx].texture = p_button;
+ cells.write[p_column].buttons.write[p_index].texture = p_button;
cells.write[p_column].cached_minimum_size_dirty = true;
_changed_notify(p_column);
}
-void TreeItem::set_button_color(int p_column, int p_idx, const Color &p_color) {
+void TreeItem::set_button_color(int p_column, int p_index, const Color &p_color) {
ERR_FAIL_INDEX(p_column, cells.size());
- ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
- if (cells[p_column].buttons[p_idx].color == p_color) {
+ if (cells[p_column].buttons[p_index].color == p_color) {
return;
}
- cells.write[p_column].buttons.write[p_idx].color = p_color;
+ cells.write[p_column].buttons.write[p_index].color = p_color;
_changed_notify(p_column);
}
-void TreeItem::set_button_disabled(int p_column, int p_idx, bool p_disabled) {
+void TreeItem::set_button_disabled(int p_column, int p_index, bool p_disabled) {
ERR_FAIL_INDEX(p_column, cells.size());
- ERR_FAIL_INDEX(p_idx, cells[p_column].buttons.size());
+ ERR_FAIL_INDEX(p_index, cells[p_column].buttons.size());
- if (cells[p_column].buttons[p_idx].disabled == p_disabled) {
+ if (cells[p_column].buttons[p_index].disabled == p_disabled) {
return;
}
- cells.write[p_column].buttons.write[p_idx].disabled = p_disabled;
+ cells.write[p_column].buttons.write[p_index].disabled = p_disabled;
cells.write[p_column].cached_minimum_size_dirty = true;
_changed_notify(p_column);
}
-bool TreeItem::is_button_disabled(int p_column, int p_idx) const {
+bool TreeItem::is_button_disabled(int p_column, int p_index) const {
ERR_FAIL_INDEX_V(p_column, cells.size(), false);
- ERR_FAIL_INDEX_V(p_idx, cells[p_column].buttons.size(), false);
+ ERR_FAIL_INDEX_V(p_index, cells[p_column].buttons.size(), false);
- return cells[p_column].buttons[p_idx].disabled;
+ return cells[p_column].buttons[p_index].disabled;
}
void TreeItem::set_editable(int p_column, bool p_editable) {
@@ -1497,15 +1497,15 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("add_button", "column", "button", "id", "disabled", "tooltip_text"), &TreeItem::add_button, DEFVAL(-1), DEFVAL(false), DEFVAL(""));
ClassDB::bind_method(D_METHOD("get_button_count", "column"), &TreeItem::get_button_count);
- ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_idx"), &TreeItem::get_button_tooltip_text);
- ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_idx"), &TreeItem::get_button_id);
+ ClassDB::bind_method(D_METHOD("get_button_tooltip_text", "column", "button_index"), &TreeItem::get_button_tooltip_text);
+ ClassDB::bind_method(D_METHOD("get_button_id", "column", "button_index"), &TreeItem::get_button_id);
ClassDB::bind_method(D_METHOD("get_button_by_id", "column", "id"), &TreeItem::get_button_by_id);
- ClassDB::bind_method(D_METHOD("get_button", "column", "button_idx"), &TreeItem::get_button);
- ClassDB::bind_method(D_METHOD("set_button", "column", "button_idx", "button"), &TreeItem::set_button);
- ClassDB::bind_method(D_METHOD("erase_button", "column", "button_idx"), &TreeItem::erase_button);
- ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_idx", "disabled"), &TreeItem::set_button_disabled);
- ClassDB::bind_method(D_METHOD("set_button_color", "column", "button_idx", "color"), &TreeItem::set_button_color);
- ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_idx"), &TreeItem::is_button_disabled);
+ ClassDB::bind_method(D_METHOD("get_button", "column", "button_index"), &TreeItem::get_button);
+ ClassDB::bind_method(D_METHOD("set_button", "column", "button_index", "button"), &TreeItem::set_button);
+ ClassDB::bind_method(D_METHOD("erase_button", "column", "button_index"), &TreeItem::erase_button);
+ ClassDB::bind_method(D_METHOD("set_button_disabled", "column", "button_index", "disabled"), &TreeItem::set_button_disabled);
+ ClassDB::bind_method(D_METHOD("set_button_color", "column", "button_index", "color"), &TreeItem::set_button_color);
+ ClassDB::bind_method(D_METHOD("is_button_disabled", "column", "button_index"), &TreeItem::is_button_disabled);
ClassDB::bind_method(D_METHOD("set_tooltip_text", "column", "tooltip"), &TreeItem::set_tooltip_text);
ClassDB::bind_method(D_METHOD("get_tooltip_text", "column"), &TreeItem::get_tooltip_text);
@@ -1518,7 +1518,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_disable_folding", "disable"), &TreeItem::set_disable_folding);
ClassDB::bind_method(D_METHOD("is_folding_disabled"), &TreeItem::is_folding_disabled);
- ClassDB::bind_method(D_METHOD("create_child", "idx"), &TreeItem::create_child, DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("create_child", "index"), &TreeItem::create_child, DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_tree"), &TreeItem::get_tree);
ClassDB::bind_method(D_METHOD("get_next"), &TreeItem::get_next);
@@ -1529,7 +1529,7 @@ void TreeItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_next_visible", "wrap"), &TreeItem::get_next_visible, DEFVAL(false));
ClassDB::bind_method(D_METHOD("get_prev_visible", "wrap"), &TreeItem::get_prev_visible, DEFVAL(false));
- ClassDB::bind_method(D_METHOD("get_child", "idx"), &TreeItem::get_child);
+ ClassDB::bind_method(D_METHOD("get_child", "index"), &TreeItem::get_child);
ClassDB::bind_method(D_METHOD("get_child_count"), &TreeItem::get_child_count);
ClassDB::bind_method(D_METHOD("get_children"), &TreeItem::get_children);
ClassDB::bind_method(D_METHOD("get_index"), &TreeItem::get_index);
@@ -4108,14 +4108,14 @@ Size2 Tree::get_minimum_size() const {
}
}
-TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
+TreeItem *Tree::create_item(TreeItem *p_parent, int p_index) {
ERR_FAIL_COND_V(blocked > 0, nullptr);
TreeItem *ti = nullptr;
if (p_parent) {
ERR_FAIL_COND_V_MSG(p_parent->tree != this, nullptr, "A different tree owns the given parent");
- ti = p_parent->create_child(p_idx);
+ ti = p_parent->create_child(p_index);
} else {
if (!root) {
// No root exists, make the given item the new root.
@@ -4126,7 +4126,7 @@ TreeItem *Tree::create_item(TreeItem *p_parent, int p_idx) {
root = ti;
} else {
// Root exists, append or insert to root.
- ti = create_item(root, p_idx);
+ ti = create_item(root, p_index);
}
}
@@ -5162,7 +5162,7 @@ bool Tree::get_allow_reselect() const {
void Tree::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear"), &Tree::clear);
- ClassDB::bind_method(D_METHOD("create_item", "parent", "idx"), &Tree::create_item, DEFVAL(Variant()), DEFVAL(-1));
+ ClassDB::bind_method(D_METHOD("create_item", "parent", "index"), &Tree::create_item, DEFVAL(Variant()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("get_root"), &Tree::get_root);
ClassDB::bind_method(D_METHOD("set_column_custom_minimum_width", "column", "min_width"), &Tree::set_column_custom_minimum_width);
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index e0ed5fdfb5..ec639ce439 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -247,15 +247,15 @@ public:
void add_button(int p_column, const Ref<Texture2D> &p_button, int p_id = -1, bool p_disabled = false, const String &p_tooltip = "");
int get_button_count(int p_column) const;
- String get_button_tooltip_text(int p_column, int p_idx) const;
- Ref<Texture2D> get_button(int p_column, int p_idx) const;
- int get_button_id(int p_column, int p_idx) const;
- void erase_button(int p_column, int p_idx);
+ String get_button_tooltip_text(int p_column, int p_index) const;
+ Ref<Texture2D> get_button(int p_column, int p_index) const;
+ int get_button_id(int p_column, int p_index) const;
+ void erase_button(int p_column, int p_index);
int get_button_by_id(int p_column, int p_id) const;
- void set_button(int p_column, int p_idx, const Ref<Texture2D> &p_button);
- void set_button_color(int p_column, int p_idx, const Color &p_color);
- void set_button_disabled(int p_column, int p_idx, bool p_disabled);
- bool is_button_disabled(int p_column, int p_idx) const;
+ void set_button(int p_column, int p_index, const Ref<Texture2D> &p_button);
+ void set_button_color(int p_column, int p_index, const Color &p_color);
+ void set_button_disabled(int p_column, int p_index, bool p_disabled);
+ bool is_button_disabled(int p_column, int p_index) const;
/* range works for mode number or mode combo */
@@ -329,7 +329,7 @@ public:
/* Item manipulation */
- TreeItem *create_child(int p_idx = -1);
+ TreeItem *create_child(int p_index = -1);
Tree *get_tree() const;
@@ -341,7 +341,7 @@ public:
TreeItem *get_prev_visible(bool p_wrap = false);
TreeItem *get_next_visible(bool p_wrap = false);
- TreeItem *get_child(int p_idx);
+ TreeItem *get_child(int p_index);
int get_visible_child_count();
int get_child_count();
TypedArray<TreeItem> get_children();
@@ -647,7 +647,7 @@ public:
void clear();
- TreeItem *create_item(TreeItem *p_parent = nullptr, int p_idx = -1);
+ TreeItem *create_item(TreeItem *p_parent = nullptr, int p_index = -1);
TreeItem *get_root() const;
TreeItem *get_last_item() const;
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 05caad78a0..bf0a8f7b6c 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -531,10 +531,13 @@ void CanvasItem::draw_polyline_colors(const Vector<Point2> &p_points, const Vect
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 real_t delta_angle = p_end_angle - p_start_angle;
+ Point2 *points_ptr = points.ptrw();
+
+ // Clamp angle difference to full circle so arc won't overlap itself.
+ const real_t delta_angle = CLAMP(p_end_angle - p_start_angle, -Math_TAU, Math_TAU);
for (int i = 0; i < p_point_count; i++) {
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);
+ points_ptr[i] = p_center + Vector2(Math::cos(theta), Math::sin(theta)) * p_radius;
}
draw_polyline(points, p_color, p_width, p_antialiased);
@@ -557,44 +560,47 @@ void CanvasItem::draw_multiline_colors(const Vector<Point2> &p_points, const Vec
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.");
+ Rect2 rect = p_rect.abs();
+
if (p_filled) {
- if (p_width != 1.0) {
+ if (p_width != -1.0) {
WARN_PRINT("The draw_rect() \"width\" argument has no effect when \"filled\" is \"true\".");
}
- RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, p_rect, p_color);
+ RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, rect, p_color);
+ } else if (p_width >= rect.size.width || p_width >= rect.size.height) {
+ RenderingServer::get_singleton()->canvas_item_add_rect(canvas_item, rect.grow(0.5f * p_width), p_color);
} 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
- real_t offset;
- if (p_width >= 2) {
- offset = p_width / 2.0;
- } else {
- offset = 0.0;
- }
+ // Thin lines are drawn without offset. The result may not be perfect.
+ real_t offset = (p_width >= 0) ? 0.5f * p_width : 0.0f;
+ // Top line.
RenderingServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Size2(-offset, 0),
- p_rect.position + Size2(p_rect.size.width + offset, 0),
+ rect.position + Size2(-offset, 0),
+ rect.position + Size2(-offset + rect.size.width, 0),
p_color,
p_width);
+ // Right line.
RenderingServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Size2(p_rect.size.width, offset),
- p_rect.position + Size2(p_rect.size.width, p_rect.size.height - offset),
+ rect.position + Size2(rect.size.width, -offset),
+ rect.position + Size2(rect.size.width, -offset + rect.size.height),
p_color,
p_width);
+ // Bottom line.
RenderingServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Size2(p_rect.size.width + offset, p_rect.size.height),
- p_rect.position + Size2(-offset, p_rect.size.height),
+ rect.position + Size2(offset + rect.size.width, rect.size.height),
+ rect.position + Size2(offset, rect.size.height),
p_color,
p_width);
+ // Left line.
RenderingServer::get_singleton()->canvas_item_add_line(
canvas_item,
- p_rect.position + Size2(0, p_rect.size.height - offset),
- p_rect.position + Size2(0, offset),
+ rect.position + Size2(0, offset + rect.size.height),
+ rect.position + Size2(0, offset),
p_color,
p_width);
}
@@ -647,11 +653,11 @@ 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, real_t 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) {
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);
+ RenderingServer::get_singleton()->canvas_item_add_primitive(canvas_item, p_points, p_colors, p_uvs, rid);
}
void CanvasItem::draw_set_transform(const Point2 &p_offset, real_t p_rot, const Size2 &p_scale) {
@@ -968,14 +974,14 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_draw_behind_parent", "enable"), &CanvasItem::set_draw_behind_parent);
ClassDB::bind_method(D_METHOD("is_draw_behind_parent_enabled"), &CanvasItem::is_draw_behind_parent_enabled);
- ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash", "aligned"), &CanvasItem::draw_dashed_line, DEFVAL(1.0), DEFVAL(2.0), DEFVAL(true));
- ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(1.0));
- ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_line", "from", "to", "color", "width", "antialiased"), &CanvasItem::draw_line, DEFVAL(-1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_dashed_line", "from", "to", "color", "width", "dash", "aligned"), &CanvasItem::draw_dashed_line, DEFVAL(-1.0), DEFVAL(2.0), DEFVAL(true));
+ ClassDB::bind_method(D_METHOD("draw_polyline", "points", "color", "width", "antialiased"), &CanvasItem::draw_polyline, DEFVAL(-1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_polyline_colors", "points", "colors", "width", "antialiased"), &CanvasItem::draw_polyline_colors, DEFVAL(-1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_arc", "center", "radius", "start_angle", "end_angle", "point_count", "color", "width", "antialiased"), &CanvasItem::draw_arc, DEFVAL(-1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("draw_multiline", "points", "color", "width"), &CanvasItem::draw_multiline, DEFVAL(-1.0));
+ ClassDB::bind_method(D_METHOD("draw_multiline_colors", "points", "colors", "width"), &CanvasItem::draw_multiline_colors, DEFVAL(-1.0));
+ ClassDB::bind_method(D_METHOD("draw_rect", "rect", "color", "filled", "width"), &CanvasItem::draw_rect, DEFVAL(true), DEFVAL(-1.0));
ClassDB::bind_method(D_METHOD("draw_circle", "position", "radius", "color"), &CanvasItem::draw_circle);
ClassDB::bind_method(D_METHOD("draw_texture", "texture", "position", "modulate"), &CanvasItem::draw_texture, DEFVAL(Color(1, 1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_texture_rect", "texture", "rect", "tile", "modulate", "transpose"), &CanvasItem::draw_texture_rect, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(false));
@@ -983,7 +989,7 @@ void CanvasItem::_bind_methods() {
ClassDB::bind_method(D_METHOD("draw_msdf_texture_rect_region", "texture", "rect", "src_rect", "modulate", "outline", "pixel_range", "scale"), &CanvasItem::draw_msdf_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)), DEFVAL(0.0), DEFVAL(4.0), DEFVAL(1.0));
ClassDB::bind_method(D_METHOD("draw_lcd_texture_rect_region", "texture", "rect", "src_rect", "modulate"), &CanvasItem::draw_lcd_texture_rect_region, DEFVAL(Color(1, 1, 1, 1)));
ClassDB::bind_method(D_METHOD("draw_style_box", "style_box", "rect"), &CanvasItem::draw_style_box);
- ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture", "width"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()), DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("draw_primitive", "points", "colors", "uvs", "texture"), &CanvasItem::draw_primitive, DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("draw_polygon", "points", "colors", "uvs", "texture"), &CanvasItem::draw_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("draw_colored_polygon", "points", "color", "uvs", "texture"), &CanvasItem::draw_colored_polygon, DEFVAL(PackedVector2Array()), DEFVAL(Ref<Texture2D>()));
ClassDB::bind_method(D_METHOD("draw_string", "font", "pos", "text", "alignment", "width", "font_size", "modulate", "jst_flags", "direction", "orientation"), &CanvasItem::draw_string, DEFVAL(HORIZONTAL_ALIGNMENT_LEFT), DEFVAL(-1), DEFVAL(Font::DEFAULT_FONT_SIZE), DEFVAL(Color(1.0, 1.0, 1.0)), DEFVAL(TextServer::JUSTIFICATION_KASHIDA | TextServer::JUSTIFICATION_WORD_BOUND), DEFVAL(TextServer::DIRECTION_AUTO), DEFVAL(TextServer::ORIENTATION_HORIZONTAL));
diff --git a/scene/main/canvas_item.h b/scene/main/canvas_item.h
index 62357a1834..a7e9fc3c79 100644
--- a/scene/main/canvas_item.h
+++ b/scene/main/canvas_item.h
@@ -247,14 +247,14 @@ public:
/* DRAWING API */
- void draw_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, real_t p_dash = 2.0, bool p_aligned = true);
- void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = 1.0, bool p_antialiased = false);
- 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_dashed_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, real_t p_dash = 2.0, bool p_aligned = true);
+ void draw_line(const Point2 &p_from, const Point2 &p_to, const Color &p_color, real_t p_width = -1.0, bool p_antialiased = false);
+ 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);
@@ -262,7 +262,7 @@ public:
void draw_msdf_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), double p_outline = 0.0, double p_pixel_range = 4.0, double p_scale = 1.0);
void draw_lcd_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));
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>(), real_t 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>());
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>());
diff --git a/scene/main/node.cpp b/scene/main/node.cpp
index eb57ccfef1..def91c424c 100644
--- a/scene/main/node.cpp
+++ b/scene/main/node.cpp
@@ -279,7 +279,10 @@ void Node::_propagate_exit_tree() {
//block while removing children
#ifdef DEBUG_ENABLED
- SceneDebugger::remove_from_cache(data.scene_file_path, this);
+ if (!data.scene_file_path.is_empty()) {
+ // Only remove if file path is set (optimization).
+ SceneDebugger::remove_from_cache(data.scene_file_path, this);
+ }
#endif
data.blocked++;
@@ -305,7 +308,6 @@ void Node::_propagate_exit_tree() {
}
// exit groups
-
for (KeyValue<StringName, GroupData> &E : data.grouped) {
data.tree->remove_from_group(E.key, this);
E.value.group = nullptr;
@@ -1166,7 +1168,7 @@ void Node::add_sibling(Node *p_sibling, bool p_force_readable_name) {
void Node::remove_child(Node *p_child) {
ERR_FAIL_NULL(p_child);
- ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy setting up children, `remove_child()` failed. Consider using `remove_child.call_deferred(child)` instead.");
+ ERR_FAIL_COND_MSG(data.blocked > 0, "Parent node is busy adding/removing children, `remove_child()` can't be called at this time. Consider using `remove_child.call_deferred(child)` instead.");
int child_count = data.children.size();
Node **children = data.children.ptrw();
@@ -1197,11 +1199,13 @@ void Node::remove_child(Node *p_child) {
data.internal_children_back--;
}
+ data.blocked++;
p_child->_set_tree(nullptr);
//}
remove_child_notify(p_child);
p_child->notification(NOTIFICATION_UNPARENTED);
+ data.blocked--;
data.children.remove_at(idx);
diff --git a/scene/main/scene_tree.cpp b/scene/main/scene_tree.cpp
index b5c587c0aa..fbe11c94d1 100644
--- a/scene/main/scene_tree.cpp
+++ b/scene/main/scene_tree.cpp
@@ -1134,7 +1134,6 @@ Error SceneTree::change_scene_to_packed(const Ref<PackedScene> &p_scene) {
ERR_FAIL_COND_V_MSG(p_scene.is_null(), ERR_INVALID_PARAMETER, "Can't change to a null scene. Use unload_current_scene() if you wish to unload it.");
Node *new_scene = p_scene->instantiate();
- new_scene = p_scene->instantiate();
ERR_FAIL_COND_V(!new_scene, ERR_CANT_CREATE);
call_deferred(SNAME("_change_scene"), new_scene);
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 7ca1f9d3ec..07bcf45899 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -1256,6 +1256,7 @@ void Viewport::_gui_show_tooltip() {
panel->set_transient(true);
panel->set_flag(Window::FLAG_NO_FOCUS, true);
panel->set_flag(Window::FLAG_POPUP, false);
+ panel->set_flag(Window::FLAG_MOUSE_PASSTHROUGH, true);
panel->set_wrap_controls(true);
panel->add_child(base_tooltip);
panel->gui_parent = this;
@@ -1401,7 +1402,7 @@ Control *Viewport::gui_find_control(const Point2 &p_global) {
xform = sw->get_canvas_transform();
}
- Control *ret = _gui_find_control_at_pos(sw, p_global, xform, gui.focus_inv_xform);
+ Control *ret = _gui_find_control_at_pos(sw, p_global, xform);
if (ret) {
return ret;
}
@@ -1410,7 +1411,7 @@ Control *Viewport::gui_find_control(const Point2 &p_global) {
return nullptr;
}
-Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform) {
+Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform) {
if (!p_node->is_visible()) {
return nullptr; // Canvas item hidden, discard.
}
@@ -1430,7 +1431,7 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
continue;
}
- Control *ret = _gui_find_control_at_pos(ci, p_global, matrix, r_inv_xform);
+ Control *ret = _gui_find_control_at_pos(ci, p_global, matrix);
if (ret) {
return ret;
}
@@ -1448,7 +1449,6 @@ Control *Viewport::_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_
Control *drag_preview = _gui_get_drag_preview();
if (!drag_preview || (c != drag_preview && !drag_preview->is_ancestor_of(c))) {
- r_inv_xform = matrix;
return c;
}
@@ -1495,12 +1495,11 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Point2 mpos = mb->get_position();
if (mb->is_pressed()) {
- Size2 pos = mpos;
if (!gui.mouse_focus_mask.is_empty()) {
// Do not steal mouse focus and stuff while a focus mask exists.
gui.mouse_focus_mask.set_flag(mouse_button_to_mask(mb->get_button_index()));
} else {
- gui.mouse_focus = gui_find_control(pos);
+ gui.mouse_focus = gui_find_control(mpos);
gui.last_mouse_focus = gui.mouse_focus;
if (!gui.mouse_focus) {
@@ -1519,10 +1518,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
mb = mb->xformed_by(Transform2D()); // Make a copy of the event.
- mb->set_global_position(pos);
-
- pos = gui.focus_inv_xform.xform(pos);
-
+ Point2 pos = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(mpos);
mb->set_position(pos);
#ifdef DEBUG_ENABLED
@@ -1586,11 +1582,8 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
return;
}
- Size2 pos = mpos;
-
mb = mb->xformed_by(Transform2D()); // Make a copy.
- mb->set_global_position(pos);
- pos = gui.focus_inv_xform.xform(pos);
+ Point2 pos = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(mpos);
mb->set_position(pos);
Control *mouse_focus = gui.mouse_focus;
@@ -1893,11 +1886,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool stopped = false;
if (over->can_process()) {
touch_event = touch_event->xformed_by(Transform2D()); // Make a copy.
- if (over == gui.mouse_focus) {
- pos = gui.focus_inv_xform.xform(pos);
- } else {
- pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
- }
+ pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
touch_event->set_position(pos);
stopped = _gui_call_input(over, touch_event);
}
@@ -1912,11 +1901,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Control *over = control_id.is_valid() ? Object::cast_to<Control>(ObjectDB::get_instance(control_id)) : nullptr;
if (over && over->can_process()) {
touch_event = touch_event->xformed_by(Transform2D()); // Make a copy.
- if (over == gui.last_mouse_focus) {
- pos = gui.focus_inv_xform.xform(pos);
- } else {
- pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
- }
+ pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
touch_event->set_position(pos);
stopped = _gui_call_input(over, touch_event);
@@ -1942,11 +1927,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
bool stopped = false;
if (over->can_process()) {
gesture_event = gesture_event->xformed_by(Transform2D()); // Make a copy.
- if (over == gui.mouse_focus) {
- pos = gui.focus_inv_xform.xform(pos);
- } else {
- pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
- }
+ pos = over->get_global_transform_with_canvas().affine_inverse().xform(pos);
gesture_event->set_position(pos);
stopped = _gui_call_input(over, gesture_event);
}
@@ -2393,7 +2374,6 @@ void Viewport::_post_gui_grab_click_focus() {
}
gui.mouse_focus = focus_grabber;
- gui.focus_inv_xform = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse();
click = gui.mouse_focus->get_global_transform_with_canvas().affine_inverse().xform(gui.last_mouse_pos);
for (int i = 0; i < 3; i++) {
@@ -3936,7 +3916,7 @@ void Viewport::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_debanding"), "set_use_debanding", "is_using_debanding");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_occlusion_culling"), "set_use_occlusion_culling", "is_using_occlusion_culling");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mesh_lod_threshold", PROPERTY_HINT_RANGE, "0,1024,0.1"), "set_mesh_lod_threshold", "get_mesh_lod_threshold");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "debug_draw", PROPERTY_HINT_ENUM, "Disabled,Unshaded,Lighting,Overdraw,Wireframe"), "set_debug_draw", "get_debug_draw");
#ifndef _3D_DISABLED
ADD_GROUP("Scaling 3D", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "scaling_3d_mode", PROPERTY_HINT_ENUM, "Bilinear (Fastest),FSR 1.0 (Fast)"), "set_scaling_3d_mode", "get_scaling_3d_mode");
diff --git a/scene/main/viewport.h b/scene/main/viewport.h
index 9f182682d7..603e92b071 100644
--- a/scene/main/viewport.h
+++ b/scene/main/viewport.h
@@ -374,7 +374,6 @@ private:
ObjectID drag_preview_id;
Ref<SceneTreeTimer> tooltip_timer;
double tooltip_delay = 0.0;
- Transform2D focus_inv_xform;
bool roots_order_dirty = false;
List<Control *> roots;
int canvas_sort_index = 0; //for sorting items with canvas as root
@@ -403,7 +402,7 @@ private:
void _gui_call_notification(Control *p_control, int p_what);
void _gui_sort_roots();
- Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform, Transform2D &r_inv_xform);
+ Control *_gui_find_control_at_pos(CanvasItem *p_node, const Point2 &p_global, const Transform2D &p_xform);
void _gui_input_event(Ref<InputEvent> p_event);
void _perform_drop(Control *p_control = nullptr, Point2 p_pos = Point2());
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index c5dbfffd7b..4baedc8c14 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -489,6 +489,7 @@ void Window::_make_window() {
ERR_FAIL_COND(window_id == DisplayServer::INVALID_WINDOW_ID);
DisplayServer::get_singleton()->window_set_max_size(Size2i(), window_id);
DisplayServer::get_singleton()->window_set_min_size(Size2i(), window_id);
+ DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id);
String tr_title = atr(title);
#ifdef DEBUG_ENABLED
if (window_id == DisplayServer::MAIN_WINDOW_ID) {
@@ -1235,6 +1236,18 @@ DisplayServer::WindowID Window::get_window_id() const {
return window_id;
}
+void Window::set_mouse_passthrough_polygon(const Vector<Vector2> &p_region) {
+ mpath = p_region;
+ if (window_id == DisplayServer::INVALID_WINDOW_ID) {
+ return;
+ }
+ DisplayServer::get_singleton()->window_set_mouse_passthrough(mpath, window_id);
+}
+
+Vector<Vector2> Window::get_mouse_passthrough_polygon() const {
+ return mpath;
+}
+
void Window::set_wrap_controls(bool p_enable) {
wrap_controls = p_enable;
if (wrap_controls) {
@@ -2163,6 +2176,9 @@ void Window::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_font_oversampling", "enable"), &Window::set_use_font_oversampling);
ClassDB::bind_method(D_METHOD("is_using_font_oversampling"), &Window::is_using_font_oversampling);
+ ClassDB::bind_method(D_METHOD("set_mouse_passthrough_polygon", "polygon"), &Window::set_mouse_passthrough_polygon);
+ ClassDB::bind_method(D_METHOD("get_mouse_passthrough_polygon"), &Window::get_mouse_passthrough_polygon);
+
ClassDB::bind_method(D_METHOD("set_wrap_controls", "enable"), &Window::set_wrap_controls);
ClassDB::bind_method(D_METHOD("is_wrapping_controls"), &Window::is_wrapping_controls);
ClassDB::bind_method(D_METHOD("child_controls_changed"), &Window::child_controls_changed);
@@ -2243,6 +2259,8 @@ void Window::_bind_methods() {
}
ADD_PROPERTY(PropertyInfo(Variant::INT, "current_screen", PROPERTY_HINT_ENUM, screen_hints), "set_current_screen", "get_current_screen");
+ ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "mouse_passthrough_polygon"), "set_mouse_passthrough_polygon", "get_mouse_passthrough_polygon");
+
ADD_GROUP("Flags", "");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "visible"), "set_visible", "is_visible");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "wrap_controls"), "set_wrap_controls", "is_wrapping_controls");
@@ -2255,6 +2273,7 @@ void Window::_bind_methods() {
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "unfocusable"), "set_flag", "get_flag", FLAG_NO_FOCUS);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "popup_window"), "set_flag", "get_flag", FLAG_POPUP);
ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "extend_to_title"), "set_flag", "get_flag", FLAG_EXTEND_TO_TITLE);
+ ADD_PROPERTYI(PropertyInfo(Variant::BOOL, "mouse_passthrough"), "set_flag", "get_flag", FLAG_MOUSE_PASSTHROUGH);
ADD_GROUP("Limits", "");
ADD_PROPERTY(PropertyInfo(Variant::VECTOR2I, "min_size", PROPERTY_HINT_NONE, "suffix:px"), "set_min_size", "get_min_size");
@@ -2302,6 +2321,7 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(FLAG_NO_FOCUS);
BIND_ENUM_CONSTANT(FLAG_POPUP);
BIND_ENUM_CONSTANT(FLAG_EXTEND_TO_TITLE);
+ BIND_ENUM_CONSTANT(FLAG_MOUSE_PASSTHROUGH);
BIND_ENUM_CONSTANT(FLAG_MAX);
BIND_ENUM_CONSTANT(CONTENT_SCALE_MODE_DISABLED);
diff --git a/scene/main/window.h b/scene/main/window.h
index b4887437a1..d819ca7c60 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -59,6 +59,7 @@ public:
FLAG_NO_FOCUS = DisplayServer::WINDOW_FLAG_NO_FOCUS,
FLAG_POPUP = DisplayServer::WINDOW_FLAG_POPUP,
FLAG_EXTEND_TO_TITLE = DisplayServer::WINDOW_FLAG_EXTEND_TO_TITLE,
+ FLAG_MOUSE_PASSTHROUGH = DisplayServer::WINDOW_FLAG_MOUSE_PASSTHROUGH,
FLAG_MAX = DisplayServer::WINDOW_FLAG_MAX,
};
@@ -101,6 +102,7 @@ private:
mutable Size2i size = Size2i(DEFAULT_WINDOW_SIZE, DEFAULT_WINDOW_SIZE);
mutable Size2i min_size;
mutable Size2i max_size;
+ mutable Vector<Vector2> mpath;
mutable Mode mode = MODE_WINDOWED;
mutable bool flags[FLAG_MAX] = {};
bool visible = true;
@@ -281,6 +283,9 @@ public:
void set_use_font_oversampling(bool p_oversampling);
bool is_using_font_oversampling() const;
+ void set_mouse_passthrough_polygon(const Vector<Vector2> &p_region);
+ Vector<Vector2> get_mouse_passthrough_polygon() const;
+
void set_wrap_controls(bool p_enable);
bool is_wrapping_controls() const;
void child_controls_changed();
diff --git a/scene/register_scene_types.cpp b/scene/register_scene_types.cpp
index 00c538976f..d56b94b6fe 100644
--- a/scene/register_scene_types.cpp
+++ b/scene/register_scene_types.cpp
@@ -184,15 +184,7 @@
#include "scene/resources/skeleton_modification_2d_physicalbones.h"
#include "scene/resources/skeleton_modification_2d_stackholder.h"
#include "scene/resources/skeleton_modification_2d_twoboneik.h"
-#include "scene/resources/skeleton_modification_3d.h"
-#include "scene/resources/skeleton_modification_3d_ccdik.h"
-#include "scene/resources/skeleton_modification_3d_fabrik.h"
-#include "scene/resources/skeleton_modification_3d_jiggle.h"
-#include "scene/resources/skeleton_modification_3d_lookat.h"
-#include "scene/resources/skeleton_modification_3d_stackholder.h"
-#include "scene/resources/skeleton_modification_3d_twoboneik.h"
#include "scene/resources/skeleton_modification_stack_2d.h"
-#include "scene/resources/skeleton_modification_stack_3d.h"
#include "scene/resources/skeleton_profile.h"
#include "scene/resources/sky.h"
#include "scene/resources/sky_material.h"
@@ -833,15 +825,6 @@ void register_scene_types() {
GDREGISTER_CLASS(ConvexPolygonShape3D);
GDREGISTER_CLASS(ConcavePolygonShape3D);
- GDREGISTER_CLASS(SkeletonModificationStack3D);
- GDREGISTER_CLASS(SkeletonModification3D);
- GDREGISTER_CLASS(SkeletonModification3DLookAt);
- GDREGISTER_CLASS(SkeletonModification3DCCDIK);
- GDREGISTER_CLASS(SkeletonModification3DFABRIK);
- GDREGISTER_CLASS(SkeletonModification3DJiggle);
- GDREGISTER_CLASS(SkeletonModification3DTwoBoneIK);
- GDREGISTER_CLASS(SkeletonModification3DStackHolder);
-
OS::get_singleton()->yield(); // may take time to init
#endif // _3D_DISABLED
diff --git a/scene/resources/convex_polygon_shape_2d.cpp b/scene/resources/convex_polygon_shape_2d.cpp
index d92d4fa4a4..e51b48a4b1 100644
--- a/scene/resources/convex_polygon_shape_2d.cpp
+++ b/scene/resources/convex_polygon_shape_2d.cpp
@@ -82,7 +82,7 @@ void ConvexPolygonShape2D::draw(const RID &p_to_rid, const Color &p_color) {
if (is_collision_outline_enabled()) {
RenderingServer::get_singleton()->canvas_item_add_polyline(p_to_rid, points, col);
// Draw the last segment as it's not drawn by `canvas_item_add_polyline()`.
- RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0, true);
+ RenderingServer::get_singleton()->canvas_item_add_line(p_to_rid, points[points.size() - 1], points[0], p_color, 1.0);
}
}
diff --git a/scene/resources/environment.cpp b/scene/resources/environment.cpp
index 746f2f8f9b..8b4656414d 100644
--- a/scene/resources/environment.cpp
+++ b/scene/resources/environment.cpp
@@ -1043,6 +1043,18 @@ void Environment::_validate_property(PropertyInfo &p_property) const {
}
}
+ if (p_property.name == "ambient_light_color" || p_property.name == "ambient_light_energy") {
+ if (ambient_source == AMBIENT_SOURCE_DISABLED) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+ }
+
+ if (p_property.name == "ambient_light_sky_contribution") {
+ if (ambient_source == AMBIENT_SOURCE_DISABLED || ambient_source == AMBIENT_SOURCE_COLOR) {
+ p_property.usage = PROPERTY_USAGE_NO_EDITOR;
+ }
+ }
+
if (p_property.name == "fog_aerial_perspective") {
if (bg_mode != BG_SKY) {
p_property.usage = PROPERTY_USAGE_NO_EDITOR;
diff --git a/scene/resources/immediate_mesh.cpp b/scene/resources/immediate_mesh.cpp
index 247927163b..f4a0db3930 100644
--- a/scene/resources/immediate_mesh.cpp
+++ b/scene/resources/immediate_mesh.cpp
@@ -194,25 +194,20 @@ void ImmediateMesh::surface_end() {
if (uses_normals) {
uint32_t *normal = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + normal_offset];
- Vector3 n = normals[i] * Vector3(0.5, 0.5, 0.5) + Vector3(0.5, 0.5, 0.5);
+ Vector2 n = normals[i].octahedron_encode();
uint32_t value = 0;
- value |= CLAMP(int(n.x * 1023.0), 0, 1023);
- value |= CLAMP(int(n.y * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int(n.z * 1023.0), 0, 1023) << 20;
+ value |= (uint16_t)CLAMP(n.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(n.y * 65535, 0, 65535) << 16;
*normal = value;
}
if (uses_tangents) {
uint32_t *tangent = (uint32_t *)&surface_vertex_ptr[i * vertex_stride + tangent_offset];
- Plane t = tangents[i];
+ Vector2 t = tangents[i].normal.octahedron_tangent_encode(tangents[i].d);
uint32_t value = 0;
- value |= CLAMP(int((t.normal.x * 0.5 + 0.5) * 1023.0), 0, 1023);
- value |= CLAMP(int((t.normal.y * 0.5 + 0.5) * 1023.0), 0, 1023) << 10;
- value |= CLAMP(int((t.normal.z * 0.5 + 0.5) * 1023.0), 0, 1023) << 20;
- if (t.d > 0) {
- value |= 3UL << 30;
- }
+ value |= (uint16_t)CLAMP(t.x * 65535, 0, 65535);
+ value |= (uint16_t)CLAMP(t.y * 65535, 0, 65535) << 16;
*tangent = value;
}
diff --git a/scene/resources/material.cpp b/scene/resources/material.cpp
index d5c3f7730b..3e2a952ea7 100644
--- a/scene/resources/material.cpp
+++ b/scene/resources/material.cpp
@@ -791,6 +791,14 @@ void BaseMaterial3D::_update_shader() {
code += "uniform vec4 refraction_texture_channel;\n";
}
+ if (features[FEATURE_REFRACTION]) {
+ code += "uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_linear_mipmap;";
+ }
+
+ if (proximity_fade_enabled) {
+ code += "uniform sampler2D depth_texture : hint_depth_texture, repeat_disable, filter_nearest;";
+ }
+
if (features[FEATURE_NORMAL_MAPPING]) {
code += "uniform sampler2D texture_normal : hint_roughness_normal," + texfilter_str + ";\n";
code += "uniform float normal_scale : hint_range(-16,16);\n";
@@ -1228,7 +1236,7 @@ void BaseMaterial3D::_update_shader() {
code += " vec2 ref_ofs = SCREEN_UV - ref_normal.xy * dot(texture(texture_refraction,base_uv),refraction_texture_channel) * refraction;\n";
}
code += " float ref_amount = 1.0 - albedo.a * albedo_tex.a;\n";
- code += " EMISSION += textureLod(SCREEN_TEXTURE,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n";
+ code += " EMISSION += textureLod(screen_texture,ref_ofs,ROUGHNESS * 8.0).rgb * ref_amount;\n";
code += " ALBEDO *= 1.0 - ref_amount;\n";
code += " ALPHA = 1.0;\n";
@@ -1246,7 +1254,7 @@ void BaseMaterial3D::_update_shader() {
}
if (proximity_fade_enabled) {
- code += " float depth_tex = textureLod(DEPTH_TEXTURE,SCREEN_UV,0.0).r;\n";
+ code += " float depth_tex = textureLod(depth_texture,SCREEN_UV,0.0).r;\n";
code += " vec4 world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV*2.0-1.0,depth_tex,1.0);\n";
code += " world_pos.xyz/=world_pos.w;\n";
code += " ALPHA*=clamp(1.0-smoothstep(world_pos.z+proximity_fade_distance,world_pos.z,VERTEX.z),0.0,1.0);\n";
diff --git a/scene/resources/mesh.cpp b/scene/resources/mesh.cpp
index 5e18b5df37..cedf4319f8 100644
--- a/scene/resources/mesh.cpp
+++ b/scene/resources/mesh.cpp
@@ -687,6 +687,7 @@ void Mesh::_bind_methods() {
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_2D_VERTICES);
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS);
+ BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY);
BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_NORMALIZED);
BIND_ENUM_CONSTANT(BLEND_SHAPE_MODE_RELATIVE);
@@ -1555,6 +1556,7 @@ void ArrayMesh::_recompute_aabb() {
// TODO: Need to add binding to add_surface using future MeshSurfaceData object.
void ArrayMesh::add_surface(BitField<ArrayFormat> p_format, PrimitiveType p_primitive, const Vector<uint8_t> &p_array, const Vector<uint8_t> &p_attribute_array, const Vector<uint8_t> &p_skin_array, int p_vertex_count, const Vector<uint8_t> &p_index_array, int p_index_count, const AABB &p_aabb, const Vector<uint8_t> &p_blend_shape_data, const Vector<AABB> &p_bone_aabbs, const Vector<RS::SurfaceData::LOD> &p_lods) {
+ ERR_FAIL_COND(surfaces.size() == RS::MAX_MESH_SURFACES);
_create_if_empty();
Surface s;
@@ -1590,6 +1592,7 @@ void ArrayMesh::add_surface(BitField<ArrayFormat> p_format, PrimitiveType p_prim
}
void ArrayMesh::add_surface_from_arrays(PrimitiveType p_primitive, const Array &p_arrays, const TypedArray<Array> &p_blend_shapes, const Dictionary &p_lods, BitField<ArrayFormat> p_flags) {
+ ERR_FAIL_COND(p_blend_shapes.size() != blend_shapes.size());
ERR_FAIL_COND(p_arrays.size() != ARRAY_MAX);
RS::SurfaceData surface;
@@ -2058,7 +2061,7 @@ void ArrayMesh::_bind_methods() {
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);
- ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "compress_flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0));
+ ClassDB::bind_method(D_METHOD("add_surface_from_arrays", "primitive", "arrays", "blend_shapes", "lods", "flags"), &ArrayMesh::add_surface_from_arrays, DEFVAL(Array()), DEFVAL(Dictionary()), DEFVAL(0));
ClassDB::bind_method(D_METHOD("clear_surfaces"), &ArrayMesh::clear_surfaces);
ClassDB::bind_method(D_METHOD("surface_update_vertex_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_vertex_region);
ClassDB::bind_method(D_METHOD("surface_update_attribute_region", "surf_idx", "offset", "data"), &ArrayMesh::surface_update_attribute_region);
diff --git a/scene/resources/primitive_meshes.cpp b/scene/resources/primitive_meshes.cpp
index 5ef66a22b6..86ed0001dd 100644
--- a/scene/resources/primitive_meshes.cpp
+++ b/scene/resources/primitive_meshes.cpp
@@ -2901,7 +2901,7 @@ void TextMesh::_create_mesh_array(Array &p_arr) const {
TS->shaped_text_set_spacing(text_rid, TextServer::SpacingType(i), font->get_spacing(TextServer::SpacingType(i)));
}
- Array stt;
+ TypedArray<Vector3i> stt;
if (st_parser == TextServer::STRUCTURED_TEXT_CUSTOM) {
GDVIRTUAL_CALL(_structured_text_parser, st_args, txt, stt);
} else {
diff --git a/scene/resources/primitive_meshes.h b/scene/resources/primitive_meshes.h
index 22cd12b004..e62f26b17c 100644
--- a/scene/resources/primitive_meshes.h
+++ b/scene/resources/primitive_meshes.h
@@ -622,7 +622,7 @@ protected:
virtual void _create_mesh_array(Array &p_arr) const override;
public:
- GDVIRTUAL2RC(Array, _structured_text_parser, Array, String)
+ GDVIRTUAL2RC(TypedArray<Vector3i>, _structured_text_parser, Array, String)
TextMesh();
~TextMesh();
diff --git a/scene/resources/resource_format_text.cpp b/scene/resources/resource_format_text.cpp
index 80b9ff3f38..2e8b4f93be 100644
--- a/scene/resources/resource_format_text.cpp
+++ b/scene/resources/resource_format_text.cpp
@@ -49,10 +49,6 @@
///
-void ResourceLoaderText::set_local_path(const String &p_local_path) {
- res_path = p_local_path;
-}
-
Ref<Resource> ResourceLoaderText::get_resource() {
return resource;
}
@@ -1846,6 +1842,9 @@ void ResourceFormatSaverTextInstance::_find_resources(const Variant &p_variant,
List<Variant> keys;
d.get_key_list(&keys);
for (const Variant &E : keys) {
+ // Of course keys should also be cached, after all we can't prevent users from using resources as keys, right?
+ // See also ResourceFormatSaverBinaryInstance::_find_resources (when p_variant is of type Variant::DICTIONARY)
+ _find_resources(E);
Variant v = d[E];
_find_resources(v);
}
diff --git a/scene/resources/resource_format_text.h b/scene/resources/resource_format_text.h
index 0f95e2fbfd..0cced3d20c 100644
--- a/scene/resources/resource_format_text.h
+++ b/scene/resources/resource_format_text.h
@@ -115,7 +115,6 @@ class ResourceLoaderText {
Ref<PackedScene> _parse_node_tag(VariantParser::ResourceParser &parser);
public:
- void set_local_path(const String &p_local_path);
Ref<Resource> get_resource();
Error load();
Error set_uid(Ref<FileAccess> p_f, ResourceUID::ID p_uid);
diff --git a/scene/resources/skeleton_modification_3d.cpp b/scene/resources/skeleton_modification_3d.cpp
deleted file mode 100644
index 92fb4bfd78..0000000000
--- a/scene/resources/skeleton_modification_3d.cpp
+++ /dev/null
@@ -1,151 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 "skeleton_modification_3d.h"
-#include "scene/3d/skeleton_3d.h"
-
-void SkeletonModification3D::_execute(real_t p_delta) {
- GDVIRTUAL_CALL(_execute, p_delta);
-
- if (!enabled) {
- return;
- }
-}
-
-void SkeletonModification3D::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
- if (stack) {
- is_setup = true;
- } else {
- WARN_PRINT("Could not setup modification with name " + this->get_name());
- }
-
- GDVIRTUAL_CALL(_setup_modification, Ref<SkeletonModificationStack3D>(p_stack));
-}
-
-void SkeletonModification3D::set_enabled(bool p_enabled) {
- enabled = p_enabled;
-}
-
-bool SkeletonModification3D::get_enabled() {
- return enabled;
-}
-
-// Helper function. Needed for CCDIK.
-real_t SkeletonModification3D::clamp_angle(real_t p_angle, real_t p_min_bound, real_t p_max_bound, bool p_invert) {
- // Map to the 0 to 360 range (in radians though) instead of the -180 to 180 range.
- if (p_angle < 0) {
- p_angle = Math_TAU + p_angle;
- }
-
- // Make min and max in the range of 0 to 360 (in radians), and make sure they are in the right order
- if (p_min_bound < 0) {
- p_min_bound = Math_TAU + p_min_bound;
- }
- if (p_max_bound < 0) {
- p_max_bound = Math_TAU + p_max_bound;
- }
- if (p_min_bound > p_max_bound) {
- SWAP(p_min_bound, p_max_bound);
- }
-
- bool is_beyond_bounds = (p_angle < p_min_bound || p_angle > p_max_bound);
- bool is_within_bounds = (p_angle > p_min_bound && p_angle < p_max_bound);
-
- // Note: May not be the most optimal way to clamp, but it always constraints to the nearest angle.
- if ((!p_invert && is_beyond_bounds) || (p_invert && is_within_bounds)) {
- Vector2 min_bound_vec = Vector2(Math::cos(p_min_bound), Math::sin(p_min_bound));
- Vector2 max_bound_vec = Vector2(Math::cos(p_max_bound), Math::sin(p_max_bound));
- Vector2 angle_vec = Vector2(Math::cos(p_angle), Math::sin(p_angle));
-
- if (angle_vec.distance_squared_to(min_bound_vec) <= angle_vec.distance_squared_to(max_bound_vec)) {
- p_angle = p_min_bound;
- } else {
- p_angle = p_max_bound;
- }
- }
-
- return p_angle;
-}
-
-bool SkeletonModification3D::_print_execution_error(bool p_condition, String p_message) {
- // If the modification is not setup, don't bother printing the error
- if (!is_setup) {
- return p_condition;
- }
-
- if (p_condition && !execution_error_found) {
- ERR_PRINT(p_message);
- execution_error_found = true;
- }
- return p_condition;
-}
-
-Ref<SkeletonModificationStack3D> SkeletonModification3D::get_modification_stack() {
- return stack;
-}
-
-void SkeletonModification3D::set_is_setup(bool p_is_setup) {
- is_setup = p_is_setup;
-}
-
-bool SkeletonModification3D::get_is_setup() const {
- return is_setup;
-}
-
-void SkeletonModification3D::set_execution_mode(int p_mode) {
- execution_mode = p_mode;
-}
-
-int SkeletonModification3D::get_execution_mode() const {
- return execution_mode;
-}
-
-void SkeletonModification3D::_bind_methods() {
- GDVIRTUAL_BIND(_execute, "delta");
- GDVIRTUAL_BIND(_setup_modification, "modification_stack")
-
- ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModification3D::set_enabled);
- ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModification3D::get_enabled);
- ClassDB::bind_method(D_METHOD("get_modification_stack"), &SkeletonModification3D::get_modification_stack);
- ClassDB::bind_method(D_METHOD("set_is_setup", "is_setup"), &SkeletonModification3D::set_is_setup);
- ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModification3D::get_is_setup);
- ClassDB::bind_method(D_METHOD("set_execution_mode", "execution_mode"), &SkeletonModification3D::set_execution_mode);
- ClassDB::bind_method(D_METHOD("get_execution_mode"), &SkeletonModification3D::get_execution_mode);
- ClassDB::bind_method(D_METHOD("clamp_angle", "angle", "min", "max", "invert"), &SkeletonModification3D::clamp_angle);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "execution_mode", PROPERTY_HINT_ENUM, "process,physics_process"), "set_execution_mode", "get_execution_mode");
-}
-
-SkeletonModification3D::SkeletonModification3D() {
- stack = nullptr;
- is_setup = false;
-}
diff --git a/scene/resources/skeleton_modification_3d.h b/scene/resources/skeleton_modification_3d.h
deleted file mode 100644
index 367adbd977..0000000000
--- a/scene/resources/skeleton_modification_3d.h
+++ /dev/null
@@ -1,79 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 SKELETON_MODIFICATION_3D_H
-#define SKELETON_MODIFICATION_3D_H
-
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_stack_3d.h"
-
-class SkeletonModificationStack3D;
-
-class SkeletonModification3D : public Resource {
- GDCLASS(SkeletonModification3D, Resource);
- friend class Skeleton3D;
- friend class SkeletonModificationStack3D;
-
-protected:
- static void _bind_methods();
-
- SkeletonModificationStack3D *stack = nullptr;
- int execution_mode = 0; // 0 = process
-
- bool enabled = true;
- bool is_setup = false;
- bool execution_error_found = false;
-
- bool _print_execution_error(bool p_condition, String p_message);
-
- GDVIRTUAL1(_execute, double)
- GDVIRTUAL1(_setup_modification, Ref<SkeletonModificationStack3D>)
-
-public:
- virtual void _execute(real_t p_delta);
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack);
-
- real_t clamp_angle(real_t p_angle, real_t p_min_bound, real_t p_max_bound, bool p_invert);
-
- void set_enabled(bool p_enabled);
- bool get_enabled();
-
- void set_execution_mode(int p_mode);
- int get_execution_mode() const;
-
- Ref<SkeletonModificationStack3D> get_modification_stack();
-
- void set_is_setup(bool p_setup);
- bool get_is_setup() const;
-
- SkeletonModification3D();
-};
-
-#endif // SKELETON_MODIFICATION_3D_H
diff --git a/scene/resources/skeleton_modification_3d_ccdik.cpp b/scene/resources/skeleton_modification_3d_ccdik.cpp
deleted file mode 100644
index b5c930f970..0000000000
--- a/scene/resources/skeleton_modification_3d_ccdik.cpp
+++ /dev/null
@@ -1,474 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_ccdik.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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/resources/skeleton_modification_3d_ccdik.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DCCDIK::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- int ccdik_data_size = ccdik_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, ccdik_data_size, false);
-
- if (what == "bone_name") {
- set_ccdik_joint_bone_name(which, p_value);
- } else if (what == "bone_index") {
- set_ccdik_joint_bone_index(which, p_value);
- } else if (what == "ccdik_axis") {
- set_ccdik_joint_ccdik_axis(which, p_value);
- } else if (what == "enable_joint_constraint") {
- set_ccdik_joint_enable_constraint(which, p_value);
- } else if (what == "joint_constraint_angle_min") {
- set_ccdik_joint_constraint_angle_min(which, Math::deg_to_rad(real_t(p_value)));
- } else if (what == "joint_constraint_angle_max") {
- set_ccdik_joint_constraint_angle_max(which, Math::deg_to_rad(real_t(p_value)));
- } else if (what == "joint_constraint_angles_invert") {
- set_ccdik_joint_constraint_invert(which, p_value);
- }
- return true;
- }
- return true;
-}
-
-bool SkeletonModification3DCCDIK::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- const int ccdik_data_size = ccdik_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, ccdik_data_size, false);
-
- if (what == "bone_name") {
- r_ret = get_ccdik_joint_bone_name(which);
- } else if (what == "bone_index") {
- r_ret = get_ccdik_joint_bone_index(which);
- } else if (what == "ccdik_axis") {
- r_ret = get_ccdik_joint_ccdik_axis(which);
- } else if (what == "enable_joint_constraint") {
- r_ret = get_ccdik_joint_enable_constraint(which);
- } else if (what == "joint_constraint_angle_min") {
- r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_min(which));
- } else if (what == "joint_constraint_angle_max") {
- r_ret = Math::rad_to_deg(get_ccdik_joint_constraint_angle_max(which));
- } else if (what == "joint_constraint_angles_invert") {
- r_ret = get_ccdik_joint_constraint_invert(which);
- }
- return true;
- }
- return true;
-}
-
-void SkeletonModification3DCCDIK::_get_property_list(List<PropertyInfo> *p_list) const {
- for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) {
- String base_string = "joint_data/" + itos(i) + "/";
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
-
- p_list->push_back(PropertyInfo(Variant::INT, base_string + "ccdik_axis",
- PROPERTY_HINT_ENUM, "X Axis,Y Axis,Z Axis", PROPERTY_USAGE_DEFAULT));
-
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "enable_joint_constraint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (ccdik_data_chain[i].enable_constraint) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "joint_constraint_angle_min", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "joint_constraint_angle_max", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "joint_constraint_angles_invert", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- }
- }
-}
-
-void SkeletonModification3DCCDIK::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
- if (!enabled) {
- return;
- }
-
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update");
- update_target_cache();
- return;
- }
- if (tip_node_cache.is_null()) {
- _print_execution_error(true, "Tip cache is out of date. Attempting to update");
- update_tip_cache();
- return;
- }
-
- // Reset the local bone overrides for CCDIK affected nodes
- for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) {
- stack->skeleton->set_bone_local_pose_override(ccdik_data_chain[i].bone_idx,
- stack->skeleton->get_bone_local_pose_override(ccdik_data_chain[i].bone_idx),
- 0.0, false);
- }
-
- Node3D *node_target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- Node3D *node_tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache));
-
- if (_print_execution_error(!node_target || !node_target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- if (_print_execution_error(!node_tip || !node_tip->is_inside_tree(), "Tip node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
-
- if (use_high_quality_solve) {
- for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) {
- for (uint32_t j = i; j < ccdik_data_chain.size(); j++) {
- _execute_ccdik_joint(j, node_target, node_tip);
- }
- }
- } else {
- for (uint32_t i = 0; i < ccdik_data_chain.size(); i++) {
- _execute_ccdik_joint(i, node_target, node_tip);
- }
- }
-
- execution_error_found = false;
-}
-
-void SkeletonModification3DCCDIK::_execute_ccdik_joint(int p_joint_idx, Node3D *p_target, Node3D *p_tip) {
- CCDIK_Joint_Data ccdik_data = ccdik_data_chain[p_joint_idx];
-
- if (_print_execution_error(ccdik_data.bone_idx < 0 || ccdik_data.bone_idx > stack->skeleton->get_bone_count(),
- "CCDIK joint: bone index for joint" + itos(p_joint_idx) + " not found. Cannot execute modification!")) {
- return;
- }
-
- Transform3D bone_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->get_bone_global_pose(ccdik_data.bone_idx));
- Transform3D tip_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->world_transform_to_global_pose(p_tip->get_global_transform()));
- Transform3D target_trans = stack->skeleton->global_pose_to_local_pose(ccdik_data.bone_idx, stack->skeleton->world_transform_to_global_pose(p_target->get_global_transform()));
-
- if (tip_trans.origin.distance_to(target_trans.origin) <= 0.01) {
- return;
- }
-
- // Inspired (and very loosely based on) by the CCDIK algorithm made by Zalo on GitHub (https://github.com/zalo/MathUtilities)
- // Convert the 3D position to a 2D position so we can use Atan2 (via the angle function)
- // to know how much rotation we need on the given axis to place the tip at the target.
- Vector2 tip_pos_2d;
- Vector2 target_pos_2d;
- if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_X) {
- tip_pos_2d = Vector2(tip_trans.origin.y, tip_trans.origin.z);
- target_pos_2d = Vector2(target_trans.origin.y, target_trans.origin.z);
- bone_trans.basis.rotate_local(Vector3(1, 0, 0), target_pos_2d.angle() - tip_pos_2d.angle());
- } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Y) {
- tip_pos_2d = Vector2(tip_trans.origin.z, tip_trans.origin.x);
- target_pos_2d = Vector2(target_trans.origin.z, target_trans.origin.x);
- bone_trans.basis.rotate_local(Vector3(0, 1, 0), target_pos_2d.angle() - tip_pos_2d.angle());
- } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Z) {
- tip_pos_2d = Vector2(tip_trans.origin.x, tip_trans.origin.y);
- target_pos_2d = Vector2(target_trans.origin.x, target_trans.origin.y);
- bone_trans.basis.rotate_local(Vector3(0, 0, 1), target_pos_2d.angle() - tip_pos_2d.angle());
- } else {
- // Should never happen, but...
- ERR_FAIL_MSG("CCDIK joint: Unknown axis vector passed for joint" + itos(p_joint_idx) + ". Cannot execute modification!");
- }
-
- if (ccdik_data.enable_constraint) {
- Vector3 rotation_axis;
- real_t rotation_angle;
- bone_trans.basis.get_axis_angle(rotation_axis, rotation_angle);
-
- // Note: When the axis has a negative direction, the angle is OVER 180 degrees and therefore we need to account for this
- // when constraining.
- if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_X) {
- if (rotation_axis.x < 0) {
- rotation_angle += Math_PI;
- rotation_axis = Vector3(1, 0, 0);
- }
- } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Y) {
- if (rotation_axis.y < 0) {
- rotation_angle += Math_PI;
- rotation_axis = Vector3(0, 1, 0);
- }
- } else if (ccdik_data.ccdik_axis == CCDIK_Axes::AXIS_Z) {
- if (rotation_axis.z < 0) {
- rotation_angle += Math_PI;
- rotation_axis = Vector3(0, 0, 1);
- }
- } else {
- // Should never happen, but...
- ERR_FAIL_MSG("CCDIK joint: Unknown axis vector passed for joint" + itos(p_joint_idx) + ". Cannot execute modification!");
- }
- rotation_angle = clamp_angle(rotation_angle, ccdik_data.constraint_angle_min, ccdik_data.constraint_angle_max, ccdik_data.constraint_angles_invert);
-
- bone_trans.basis.set_axis_angle(rotation_axis, rotation_angle);
- }
-
- stack->skeleton->set_bone_local_pose_override(ccdik_data.bone_idx, bone_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(ccdik_data.bone_idx);
-}
-
-void SkeletonModification3DCCDIK::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
- if (stack != nullptr) {
- is_setup = true;
- execution_error_found = false;
- update_target_cache();
- update_tip_cache();
- }
-}
-
-void SkeletonModification3DCCDIK::update_target_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
-
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: node is not in scene tree!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DCCDIK::update_tip_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!");
- return;
- }
-
- tip_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(tip_node)) {
- Node *node = stack->skeleton->get_node(tip_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update tip cache: node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update tip cache: node is not in scene tree!");
- tip_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DCCDIK::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_target_cache();
-}
-
-NodePath SkeletonModification3DCCDIK::get_target_node() const {
- return target_node;
-}
-
-void SkeletonModification3DCCDIK::set_tip_node(const NodePath &p_tip_node) {
- tip_node = p_tip_node;
- update_tip_cache();
-}
-
-NodePath SkeletonModification3DCCDIK::get_tip_node() const {
- return tip_node;
-}
-
-void SkeletonModification3DCCDIK::set_use_high_quality_solve(bool p_high_quality) {
- use_high_quality_solve = p_high_quality;
-}
-
-bool SkeletonModification3DCCDIK::get_use_high_quality_solve() const {
- return use_high_quality_solve;
-}
-
-// CCDIK joint data functions
-String SkeletonModification3DCCDIK::get_ccdik_joint_bone_name(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, String());
- return ccdik_data_chain[p_joint_idx].bone_name;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_bone_name(int p_joint_idx, String p_bone_name) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].bone_name = p_bone_name;
-
- if (stack) {
- if (stack->skeleton) {
- ccdik_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_bone_name);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DCCDIK::get_ccdik_joint_bone_index(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return ccdik_data_chain[p_joint_idx].bone_idx;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
- ccdik_data_chain[p_joint_idx].bone_idx = p_bone_idx;
-
- if (stack) {
- if (stack->skeleton) {
- ccdik_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DCCDIK::get_ccdik_joint_ccdik_axis(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return ccdik_data_chain[p_joint_idx].ccdik_axis;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_ccdik_axis(int p_joint_idx, int p_axis) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_axis < 0, "CCDIK axis is out of range: The axis mode is too low!");
- ccdik_data_chain[p_joint_idx].ccdik_axis = p_axis;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DCCDIK::get_ccdik_joint_enable_constraint(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return ccdik_data_chain[p_joint_idx].enable_constraint;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_enable) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].enable_constraint = p_enable;
- notify_property_list_changed();
-}
-
-real_t SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_min(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return ccdik_data_chain[p_joint_idx].constraint_angle_min;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_min(int p_joint_idx, real_t p_angle_min) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].constraint_angle_min = p_angle_min;
-}
-
-real_t SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_max(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return ccdik_data_chain[p_joint_idx].constraint_angle_max;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_max(int p_joint_idx, real_t p_angle_max) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].constraint_angle_max = p_angle_max;
-}
-
-bool SkeletonModification3DCCDIK::get_ccdik_joint_constraint_invert(int p_joint_idx) const {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return ccdik_data_chain[p_joint_idx].constraint_angles_invert;
-}
-
-void SkeletonModification3DCCDIK::set_ccdik_joint_constraint_invert(int p_joint_idx, bool p_invert) {
- const int bone_chain_size = ccdik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ccdik_data_chain[p_joint_idx].constraint_angles_invert = p_invert;
-}
-
-int SkeletonModification3DCCDIK::get_ccdik_data_chain_length() {
- return ccdik_data_chain.size();
-}
-void SkeletonModification3DCCDIK::set_ccdik_data_chain_length(int p_length) {
- ERR_FAIL_COND(p_length < 0);
- ccdik_data_chain.resize(p_length);
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-void SkeletonModification3DCCDIK::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DCCDIK::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DCCDIK::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_tip_node", "tip_nodepath"), &SkeletonModification3DCCDIK::set_tip_node);
- ClassDB::bind_method(D_METHOD("get_tip_node"), &SkeletonModification3DCCDIK::get_tip_node);
-
- ClassDB::bind_method(D_METHOD("set_use_high_quality_solve", "high_quality_solve"), &SkeletonModification3DCCDIK::set_use_high_quality_solve);
- ClassDB::bind_method(D_METHOD("get_use_high_quality_solve"), &SkeletonModification3DCCDIK::get_use_high_quality_solve);
-
- // CCDIK joint data functions
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone_name", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_bone_name);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone_name", "joint_idx", "bone_name"), &SkeletonModification3DCCDIK::set_ccdik_joint_bone_name);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_bone_index", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_bone_index);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_bone_index", "joint_idx", "bone_index"), &SkeletonModification3DCCDIK::set_ccdik_joint_bone_index);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_ccdik_axis", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_ccdik_axis);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_ccdik_axis", "joint_idx", "axis"), &SkeletonModification3DCCDIK::set_ccdik_joint_ccdik_axis);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_enable_joint_constraint", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_enable_constraint);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_enable_joint_constraint", "joint_idx", "enable"), &SkeletonModification3DCCDIK::set_ccdik_joint_enable_constraint);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_min", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_min);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_min", "joint_idx", "min_angle"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_min);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_angle_max", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_angle_max);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_angle_max", "joint_idx", "max_angle"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_angle_max);
- ClassDB::bind_method(D_METHOD("get_ccdik_joint_constraint_invert", "joint_idx"), &SkeletonModification3DCCDIK::get_ccdik_joint_constraint_invert);
- ClassDB::bind_method(D_METHOD("set_ccdik_joint_constraint_invert", "joint_idx", "invert"), &SkeletonModification3DCCDIK::set_ccdik_joint_constraint_invert);
-
- ClassDB::bind_method(D_METHOD("set_ccdik_data_chain_length", "length"), &SkeletonModification3DCCDIK::set_ccdik_data_chain_length);
- ClassDB::bind_method(D_METHOD("get_ccdik_data_chain_length"), &SkeletonModification3DCCDIK::get_ccdik_data_chain_length);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "tip_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_tip_node", "get_tip_node");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "high_quality_solve", PROPERTY_HINT_NONE, ""), "set_use_high_quality_solve", "get_use_high_quality_solve");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "ccdik_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_ccdik_data_chain_length", "get_ccdik_data_chain_length");
-}
-
-SkeletonModification3DCCDIK::SkeletonModification3DCCDIK() {
- stack = nullptr;
- is_setup = false;
- enabled = true;
-}
-
-SkeletonModification3DCCDIK::~SkeletonModification3DCCDIK() {
-}
diff --git a/scene/resources/skeleton_modification_3d_ccdik.h b/scene/resources/skeleton_modification_3d_ccdik.h
deleted file mode 100644
index 30c29bb3aa..0000000000
--- a/scene/resources/skeleton_modification_3d_ccdik.h
+++ /dev/null
@@ -1,114 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_ccdik.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 SKELETON_MODIFICATION_3D_CCDIK_H
-#define SKELETON_MODIFICATION_3D_CCDIK_H
-
-#include "core/templates/local_vector.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DCCDIK : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DCCDIK, SkeletonModification3D);
-
-private:
- enum CCDIK_Axes {
- AXIS_X,
- AXIS_Y,
- AXIS_Z
- };
-
- struct CCDIK_Joint_Data {
- String bone_name = "";
- int bone_idx = -1;
- int ccdik_axis = 0;
-
- bool enable_constraint = false;
- real_t constraint_angle_min = 0;
- real_t constraint_angle_max = (2.0 * Math_PI);
- bool constraint_angles_invert = false;
- };
-
- LocalVector<CCDIK_Joint_Data> ccdik_data_chain;
- NodePath target_node;
- ObjectID target_node_cache;
-
- NodePath tip_node;
- ObjectID tip_node_cache;
-
- bool use_high_quality_solve = true;
-
- void update_target_cache();
- void update_tip_cache();
-
- void _execute_ccdik_joint(int p_joint_idx, Node3D *p_target, Node3D *p_tip);
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- void set_tip_node(const NodePath &p_tip_node);
- NodePath get_tip_node() const;
-
- void set_use_high_quality_solve(bool p_solve);
- bool get_use_high_quality_solve() const;
-
- String get_ccdik_joint_bone_name(int p_joint_idx) const;
- void set_ccdik_joint_bone_name(int p_joint_idx, String p_bone_name);
- int get_ccdik_joint_bone_index(int p_joint_idx) const;
- void set_ccdik_joint_bone_index(int p_joint_idx, int p_bone_idx);
- int get_ccdik_joint_ccdik_axis(int p_joint_idx) const;
- void set_ccdik_joint_ccdik_axis(int p_joint_idx, int p_axis);
- bool get_ccdik_joint_enable_constraint(int p_joint_idx) const;
- void set_ccdik_joint_enable_constraint(int p_joint_idx, bool p_enable);
- real_t get_ccdik_joint_constraint_angle_min(int p_joint_idx) const;
- void set_ccdik_joint_constraint_angle_min(int p_joint_idx, real_t p_angle_min);
- real_t get_ccdik_joint_constraint_angle_max(int p_joint_idx) const;
- void set_ccdik_joint_constraint_angle_max(int p_joint_idx, real_t p_angle_max);
- bool get_ccdik_joint_constraint_invert(int p_joint_idx) const;
- void set_ccdik_joint_constraint_invert(int p_joint_idx, bool p_invert);
-
- int get_ccdik_data_chain_length();
- void set_ccdik_data_chain_length(int p_new_length);
-
- SkeletonModification3DCCDIK();
- ~SkeletonModification3DCCDIK();
-};
-
-#endif // SKELETON_MODIFICATION_3D_CCDIK_H
diff --git a/scene/resources/skeleton_modification_3d_fabrik.cpp b/scene/resources/skeleton_modification_3d_fabrik.cpp
deleted file mode 100644
index 9fb7ade155..0000000000
--- a/scene/resources/skeleton_modification_3d_fabrik.cpp
+++ /dev/null
@@ -1,628 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_fabrik.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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/resources/skeleton_modification_3d_fabrik.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DFABRIK::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- int fabrik_data_size = fabrik_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, fabrik_data_size, false);
-
- if (what == "bone_name") {
- set_fabrik_joint_bone_name(which, p_value);
- } else if (what == "bone_index") {
- set_fabrik_joint_bone_index(which, p_value);
- } else if (what == "length") {
- set_fabrik_joint_length(which, p_value);
- } else if (what == "magnet_position") {
- set_fabrik_joint_magnet(which, p_value);
- } else if (what == "auto_calculate_length") {
- set_fabrik_joint_auto_calculate_length(which, p_value);
- } else if (what == "use_tip_node") {
- set_fabrik_joint_use_tip_node(which, p_value);
- } else if (what == "tip_node") {
- set_fabrik_joint_tip_node(which, p_value);
- } else if (what == "use_target_basis") {
- set_fabrik_joint_use_target_basis(which, p_value);
- } else if (what == "roll") {
- set_fabrik_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
- }
- return true;
- }
- return true;
-}
-
-bool SkeletonModification3DFABRIK::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- const int fabrik_data_size = fabrik_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, fabrik_data_size, false);
-
- if (what == "bone_name") {
- r_ret = get_fabrik_joint_bone_name(which);
- } else if (what == "bone_index") {
- r_ret = get_fabrik_joint_bone_index(which);
- } else if (what == "length") {
- r_ret = get_fabrik_joint_length(which);
- } else if (what == "magnet_position") {
- r_ret = get_fabrik_joint_magnet(which);
- } else if (what == "auto_calculate_length") {
- r_ret = get_fabrik_joint_auto_calculate_length(which);
- } else if (what == "use_tip_node") {
- r_ret = get_fabrik_joint_use_tip_node(which);
- } else if (what == "tip_node") {
- r_ret = get_fabrik_joint_tip_node(which);
- } else if (what == "use_target_basis") {
- r_ret = get_fabrik_joint_use_target_basis(which);
- } else if (what == "roll") {
- r_ret = Math::rad_to_deg(get_fabrik_joint_roll(which));
- }
- return true;
- }
- return true;
-}
-
-void SkeletonModification3DFABRIK::_get_property_list(List<PropertyInfo> *p_list) const {
- for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
- String base_string = "joint_data/" + itos(i) + "/";
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "roll", PROPERTY_HINT_RANGE, "-360,360,0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "auto_calculate_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
-
- if (!fabrik_data_chain[i].auto_calculate_length) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- } else {
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_tip_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (fabrik_data_chain[i].use_tip_node) {
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, base_string + "tip_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT));
- }
- }
-
- // Cannot apply magnet to the origin of the chain, as it will not do anything.
- if (i > 0) {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, base_string + "magnet_position", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- }
- // Only give the override basis option on the last bone in the chain, so only include it for the last bone.
- if (i == fabrik_data_chain.size() - 1) {
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_target_basis", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- }
- }
-}
-
-void SkeletonModification3DFABRIK::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
- if (!enabled) {
- return;
- }
-
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update...");
- update_target_cache();
- return;
- }
-
- if (_print_execution_error(fabrik_data_chain.size() <= 1, "FABRIK requires at least two joints to operate. Cannot execute modification!")) {
- return;
- }
-
- Node3D *node_target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- if (_print_execution_error(!node_target || !node_target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
-
- // Make sure the transform cache is the correct size
- if (fabrik_transforms.size() != fabrik_data_chain.size()) {
- fabrik_transforms.resize(fabrik_data_chain.size());
- }
-
- // Verify that all joints have a valid bone ID, and that all bone lengths are zero or more
- // Also, while we are here, apply magnet positions.
- for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
- if (_print_execution_error(fabrik_data_chain[i].bone_idx < 0, "FABRIK Joint " + itos(i) + " has an invalid bone ID. Cannot execute!")) {
- return;
- }
-
- if (fabrik_data_chain[i].length < 0 && fabrik_data_chain[i].auto_calculate_length) {
- fabrik_joint_auto_calculate_length(i);
- }
- if (_print_execution_error(fabrik_data_chain[i].length < 0, "FABRIK Joint " + itos(i) + " has an invalid joint length. Cannot execute!")) {
- return;
- }
- fabrik_transforms[i] = stack->skeleton->get_bone_global_pose(fabrik_data_chain[i].bone_idx);
-
- // Apply magnet positions:
- if (stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx) >= 0) {
- int parent_bone_idx = stack->skeleton->get_bone_parent(fabrik_data_chain[i].bone_idx);
- Transform3D conversion_transform = (stack->skeleton->get_bone_global_pose(parent_bone_idx));
- fabrik_transforms[i].origin += conversion_transform.basis.xform_inv(fabrik_data_chain[i].magnet_position);
- } else {
- fabrik_transforms[i].origin += fabrik_data_chain[i].magnet_position;
- }
- }
- Transform3D origin_global_pose_trans = stack->skeleton->get_bone_global_pose_no_override(fabrik_data_chain[0].bone_idx);
-
- target_global_pose = stack->skeleton->world_transform_to_global_pose(node_target->get_global_transform());
- origin_global_pose = origin_global_pose_trans;
-
- final_joint_idx = fabrik_data_chain.size() - 1;
- real_t target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin);
- chain_iterations = 0;
-
- while (target_distance > chain_tolerance) {
- chain_backwards();
- chain_forwards();
-
- // update the target distance
- target_distance = fabrik_transforms[final_joint_idx].origin.distance_to(target_global_pose.origin);
-
- // update chain iterations
- chain_iterations += 1;
- if (chain_iterations >= chain_max_iterations) {
- break;
- }
- }
- chain_apply();
-
- execution_error_found = false;
-}
-
-void SkeletonModification3DFABRIK::chain_backwards() {
- int final_bone_idx = fabrik_data_chain[final_joint_idx].bone_idx;
- Transform3D final_joint_trans = fabrik_transforms[final_joint_idx];
-
- // Get the direction the final bone is facing in.
- stack->skeleton->update_bone_rest_forward_vector(final_bone_idx);
- Transform3D final_bone_direction_trans = final_joint_trans.looking_at(target_global_pose.origin, Vector3(0, 1, 0));
- final_bone_direction_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(final_bone_idx, final_bone_direction_trans.basis);
- Vector3 direction = final_bone_direction_trans.basis.xform(stack->skeleton->get_bone_axis_forward_vector(final_bone_idx)).normalized();
-
- // If set to override, then use the target's Basis rather than the bone's
- if (fabrik_data_chain[final_joint_idx].use_target_basis) {
- direction = target_global_pose.basis.xform(stack->skeleton->get_bone_axis_forward_vector(final_bone_idx)).normalized();
- }
-
- // set the position of the final joint to the target position
- final_joint_trans.origin = target_global_pose.origin - (direction * fabrik_data_chain[final_joint_idx].length);
- fabrik_transforms[final_joint_idx] = final_joint_trans;
-
- // for all other joints, move them towards the target
- int i = final_joint_idx;
- while (i >= 1) {
- Transform3D next_bone_trans = fabrik_transforms[i];
- i -= 1;
- Transform3D current_trans = fabrik_transforms[i];
-
- real_t length = fabrik_data_chain[i].length / (current_trans.origin.distance_to(next_bone_trans.origin));
- current_trans.origin = next_bone_trans.origin.lerp(current_trans.origin, length);
-
- // Save the result
- fabrik_transforms[i] = current_trans;
- }
-}
-
-void SkeletonModification3DFABRIK::chain_forwards() {
- // Set root at the initial position.
- Transform3D root_transform = fabrik_transforms[0];
-
- root_transform.origin = origin_global_pose.origin;
- fabrik_transforms[0] = origin_global_pose;
-
- for (uint32_t i = 0; i < fabrik_data_chain.size() - 1; i++) {
- Transform3D current_trans = fabrik_transforms[i];
- Transform3D next_bone_trans = fabrik_transforms[i + 1];
-
- real_t length = fabrik_data_chain[i].length / (next_bone_trans.origin.distance_to(current_trans.origin));
- next_bone_trans.origin = current_trans.origin.lerp(next_bone_trans.origin, length);
-
- // Save the result
- fabrik_transforms[i + 1] = next_bone_trans;
- }
-}
-
-void SkeletonModification3DFABRIK::chain_apply() {
- for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
- int current_bone_idx = fabrik_data_chain[i].bone_idx;
- Transform3D current_trans = fabrik_transforms[i];
-
- // If this is the last bone in the chain...
- if (i == fabrik_data_chain.size() - 1) {
- if (fabrik_data_chain[i].use_target_basis == false) { // Point to target...
- // Get the forward direction that the basis is facing in right now.
- stack->skeleton->update_bone_rest_forward_vector(current_bone_idx);
- Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(current_bone_idx);
- // Rotate the bone towards the target:
- current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(target_global_pose.origin));
- current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll);
- } else { // Use the target's Basis...
- current_trans.basis = target_global_pose.basis.orthonormalized().scaled(current_trans.basis.get_scale());
- }
- } else { // every other bone in the chain...
- Transform3D next_trans = fabrik_transforms[i + 1];
-
- // Get the forward direction that the basis is facing in right now.
- stack->skeleton->update_bone_rest_forward_vector(current_bone_idx);
- Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(current_bone_idx);
- // Rotate the bone towards the next bone in the chain:
- current_trans.basis.rotate_to_align(forward_vector, current_trans.origin.direction_to(next_trans.origin));
- current_trans.basis.rotate_local(forward_vector, fabrik_data_chain[i].roll);
- }
- stack->skeleton->set_bone_local_pose_override(current_bone_idx, stack->skeleton->global_pose_to_local_pose(current_bone_idx, current_trans), stack->strength, true);
- }
-
- // Update all the bones so the next modification has up-to-date data.
- stack->skeleton->force_update_all_bone_transforms();
-}
-
-void SkeletonModification3DFABRIK::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
- if (stack != nullptr) {
- is_setup = true;
- execution_error_found = false;
- update_target_cache();
-
- for (uint32_t i = 0; i < fabrik_data_chain.size(); i++) {
- update_joint_tip_cache(i);
- }
- }
-}
-
-void SkeletonModification3DFABRIK::update_target_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree() && target_node.is_empty() == false) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: node is not in the scene tree!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DFABRIK::update_joint_tip_cache(int p_joint_idx) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_MSG(p_joint_idx, bone_chain_size, "FABRIK joint not found");
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!");
- return;
- }
- fabrik_data_chain[p_joint_idx].tip_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree() && fabrik_data_chain[p_joint_idx].tip_node.is_empty() == false) {
- if (stack->skeleton->has_node(fabrik_data_chain[p_joint_idx].tip_node)) {
- Node *node = stack->skeleton->get_node(fabrik_data_chain[p_joint_idx].tip_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update tip cache for joint " + itos(p_joint_idx) + ": node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update tip cache for joint " + itos(p_joint_idx) + ": node is not in scene tree!");
- fabrik_data_chain[p_joint_idx].tip_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DFABRIK::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_target_cache();
-}
-
-NodePath SkeletonModification3DFABRIK::get_target_node() const {
- return target_node;
-}
-
-int SkeletonModification3DFABRIK::get_fabrik_data_chain_length() {
- return fabrik_data_chain.size();
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_data_chain_length(int p_length) {
- ERR_FAIL_COND(p_length < 0);
- fabrik_data_chain.resize(p_length);
- fabrik_transforms.resize(p_length);
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-real_t SkeletonModification3DFABRIK::get_chain_tolerance() {
- return chain_tolerance;
-}
-
-void SkeletonModification3DFABRIK::set_chain_tolerance(real_t p_tolerance) {
- ERR_FAIL_COND_MSG(p_tolerance <= 0, "FABRIK chain tolerance must be more than zero!");
- chain_tolerance = p_tolerance;
-}
-
-int SkeletonModification3DFABRIK::get_chain_max_iterations() {
- return chain_max_iterations;
-}
-void SkeletonModification3DFABRIK::set_chain_max_iterations(int p_iterations) {
- ERR_FAIL_COND_MSG(p_iterations <= 0, "FABRIK chain iterations must be at least one. Set enabled to false to disable the FABRIK chain.");
- chain_max_iterations = p_iterations;
-}
-
-// FABRIK joint data functions
-String SkeletonModification3DFABRIK::get_fabrik_joint_bone_name(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, String());
- return fabrik_data_chain[p_joint_idx].bone_name;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_bone_name(int p_joint_idx, String p_bone_name) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].bone_name = p_bone_name;
-
- if (stack) {
- if (stack->skeleton) {
- fabrik_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_bone_name);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DFABRIK::get_fabrik_joint_bone_index(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return fabrik_data_chain[p_joint_idx].bone_idx;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
- fabrik_data_chain[p_joint_idx].bone_idx = p_bone_idx;
-
- if (stack) {
- if (stack->skeleton) {
- fabrik_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-real_t SkeletonModification3DFABRIK::get_fabrik_joint_length(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return fabrik_data_chain[p_joint_idx].length;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_length(int p_joint_idx, real_t p_bone_length) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_bone_length < 0, "FABRIK joint length cannot be less than zero!");
-
- if (!is_setup) {
- fabrik_data_chain[p_joint_idx].length = p_bone_length;
- return;
- }
-
- if (fabrik_data_chain[p_joint_idx].auto_calculate_length) {
- WARN_PRINT("FABRIK Length not set: auto calculate length is enabled for this joint!");
- fabrik_joint_auto_calculate_length(p_joint_idx);
- } else {
- fabrik_data_chain[p_joint_idx].length = p_bone_length;
- }
-
- execution_error_found = false;
-}
-
-Vector3 SkeletonModification3DFABRIK::get_fabrik_joint_magnet(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, Vector3());
- return fabrik_data_chain[p_joint_idx].magnet_position;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_magnet(int p_joint_idx, Vector3 p_magnet) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].magnet_position = p_magnet;
-}
-
-bool SkeletonModification3DFABRIK::get_fabrik_joint_auto_calculate_length(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return fabrik_data_chain[p_joint_idx].auto_calculate_length;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_auto_calculate_length(int p_joint_idx, bool p_auto_calculate) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].auto_calculate_length = p_auto_calculate;
- fabrik_joint_auto_calculate_length(p_joint_idx);
- notify_property_list_changed();
-}
-
-void SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length(int p_joint_idx) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- if (!fabrik_data_chain[p_joint_idx].auto_calculate_length) {
- return;
- }
-
- if (!stack || !stack->skeleton || !is_setup) {
- _print_execution_error(true, "Cannot auto calculate joint length: modification is not properly setup!");
- return;
- }
- ERR_FAIL_INDEX_MSG(fabrik_data_chain[p_joint_idx].bone_idx, stack->skeleton->get_bone_count(),
- "Bone for joint " + itos(p_joint_idx) + " is not set or points to an unknown bone!");
-
- if (fabrik_data_chain[p_joint_idx].use_tip_node) { // Use the tip node to update joint length.
-
- update_joint_tip_cache(p_joint_idx);
-
- Node3D *tip_node = Object::cast_to<Node3D>(ObjectDB::get_instance(fabrik_data_chain[p_joint_idx].tip_node_cache));
- ERR_FAIL_COND_MSG(!tip_node, "Tip node for joint " + itos(p_joint_idx) + "is not a Node3D-based node. Cannot calculate length...");
- ERR_FAIL_COND_MSG(!tip_node->is_inside_tree(), "Tip node for joint " + itos(p_joint_idx) + "is not in the scene tree. Cannot calculate length...");
-
- Transform3D node_trans = tip_node->get_global_transform();
- node_trans = stack->skeleton->world_transform_to_global_pose(node_trans);
- //node_trans = stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, node_trans);
- //fabrik_data_chain[p_joint_idx].length = node_trans.origin.length();
-
- fabrik_data_chain[p_joint_idx].length = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx).origin.distance_to(node_trans.origin);
-
- } else { // Use child bone(s) to update joint length, if possible
- Vector<int> bone_children = stack->skeleton->get_bone_children(fabrik_data_chain[p_joint_idx].bone_idx);
- if (bone_children.size() <= 0) {
- ERR_FAIL_MSG("Cannot calculate length for joint " + itos(p_joint_idx) + "joint uses leaf bone. \nPlease manually set the bone length or use a tip node!");
- return;
- }
-
- Transform3D bone_trans = stack->skeleton->get_bone_global_pose(fabrik_data_chain[p_joint_idx].bone_idx);
-
- real_t final_length = 0;
- for (int i = 0; i < bone_children.size(); i++) {
- Transform3D child_transform = stack->skeleton->get_bone_global_pose(bone_children[i]);
- final_length += bone_trans.origin.distance_to(child_transform.origin);
- //final_length += stack->skeleton->global_pose_to_local_pose(fabrik_data_chain[p_joint_idx].bone_idx, child_transform).origin.length();
- }
- fabrik_data_chain[p_joint_idx].length = final_length / bone_children.size();
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DFABRIK::get_fabrik_joint_use_tip_node(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return fabrik_data_chain[p_joint_idx].use_tip_node;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_use_tip_node(int p_joint_idx, bool p_use_tip_node) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].use_tip_node = p_use_tip_node;
- notify_property_list_changed();
-}
-
-NodePath SkeletonModification3DFABRIK::get_fabrik_joint_tip_node(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, NodePath());
- return fabrik_data_chain[p_joint_idx].tip_node;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_tip_node(int p_joint_idx, NodePath p_tip_node) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].tip_node = p_tip_node;
- update_joint_tip_cache(p_joint_idx);
-}
-
-bool SkeletonModification3DFABRIK::get_fabrik_joint_use_target_basis(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return fabrik_data_chain[p_joint_idx].use_target_basis;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_use_target_basis(int p_joint_idx, bool p_use_target_basis) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].use_target_basis = p_use_target_basis;
-}
-
-real_t SkeletonModification3DFABRIK::get_fabrik_joint_roll(int p_joint_idx) const {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, 0.0);
- return fabrik_data_chain[p_joint_idx].roll;
-}
-
-void SkeletonModification3DFABRIK::set_fabrik_joint_roll(int p_joint_idx, real_t p_roll) {
- const int bone_chain_size = fabrik_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- fabrik_data_chain[p_joint_idx].roll = p_roll;
-}
-
-void SkeletonModification3DFABRIK::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DFABRIK::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DFABRIK::get_target_node);
- ClassDB::bind_method(D_METHOD("set_fabrik_data_chain_length", "length"), &SkeletonModification3DFABRIK::set_fabrik_data_chain_length);
- ClassDB::bind_method(D_METHOD("get_fabrik_data_chain_length"), &SkeletonModification3DFABRIK::get_fabrik_data_chain_length);
- ClassDB::bind_method(D_METHOD("set_chain_tolerance", "tolerance"), &SkeletonModification3DFABRIK::set_chain_tolerance);
- ClassDB::bind_method(D_METHOD("get_chain_tolerance"), &SkeletonModification3DFABRIK::get_chain_tolerance);
- ClassDB::bind_method(D_METHOD("set_chain_max_iterations", "max_iterations"), &SkeletonModification3DFABRIK::set_chain_max_iterations);
- ClassDB::bind_method(D_METHOD("get_chain_max_iterations"), &SkeletonModification3DFABRIK::get_chain_max_iterations);
-
- // FABRIK joint data functions
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_name", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_bone_name);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_name", "joint_idx", "bone_name"), &SkeletonModification3DFABRIK::set_fabrik_joint_bone_name);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_bone_index", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_bone_index);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_bone_index", "joint_idx", "bone_index"), &SkeletonModification3DFABRIK::set_fabrik_joint_bone_index);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_length", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_length);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_length", "joint_idx", "length"), &SkeletonModification3DFABRIK::set_fabrik_joint_length);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_magnet", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_magnet);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_magnet", "joint_idx", "magnet_position"), &SkeletonModification3DFABRIK::set_fabrik_joint_magnet);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_auto_calculate_length", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_auto_calculate_length);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_auto_calculate_length", "joint_idx", "auto_calculate_length"), &SkeletonModification3DFABRIK::set_fabrik_joint_auto_calculate_length);
- ClassDB::bind_method(D_METHOD("fabrik_joint_auto_calculate_length", "joint_idx"), &SkeletonModification3DFABRIK::fabrik_joint_auto_calculate_length);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_tip_node", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_use_tip_node);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_tip_node", "joint_idx", "use_tip_node"), &SkeletonModification3DFABRIK::set_fabrik_joint_use_tip_node);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_tip_node", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_tip_node);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_tip_node", "joint_idx", "tip_node"), &SkeletonModification3DFABRIK::set_fabrik_joint_tip_node);
- ClassDB::bind_method(D_METHOD("get_fabrik_joint_use_target_basis", "joint_idx"), &SkeletonModification3DFABRIK::get_fabrik_joint_use_target_basis);
- ClassDB::bind_method(D_METHOD("set_fabrik_joint_use_target_basis", "joint_idx", "use_target_basis"), &SkeletonModification3DFABRIK::set_fabrik_joint_use_target_basis);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "fabrik_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_fabrik_data_chain_length", "get_fabrik_data_chain_length");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "chain_tolerance", PROPERTY_HINT_RANGE, "0,100,0.001"), "set_chain_tolerance", "get_chain_tolerance");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "chain_max_iterations", PROPERTY_HINT_RANGE, "1,50,1"), "set_chain_max_iterations", "get_chain_max_iterations");
-}
-
-SkeletonModification3DFABRIK::SkeletonModification3DFABRIK() {
- stack = nullptr;
- is_setup = false;
- enabled = true;
-}
-
-SkeletonModification3DFABRIK::~SkeletonModification3DFABRIK() {
-}
diff --git a/scene/resources/skeleton_modification_3d_fabrik.h b/scene/resources/skeleton_modification_3d_fabrik.h
deleted file mode 100644
index c834658093..0000000000
--- a/scene/resources/skeleton_modification_3d_fabrik.h
+++ /dev/null
@@ -1,124 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_fabrik.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 SKELETON_MODIFICATION_3D_FABRIK_H
-#define SKELETON_MODIFICATION_3D_FABRIK_H
-
-#include "core/templates/local_vector.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DFABRIK : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DFABRIK, SkeletonModification3D);
-
-private:
- struct FABRIK_Joint_Data {
- String bone_name = "";
- int bone_idx = -1;
- real_t length = -1;
- Vector3 magnet_position = Vector3(0, 0, 0);
-
- bool auto_calculate_length = true;
- bool use_tip_node = false;
- NodePath tip_node;
- ObjectID tip_node_cache;
-
- bool use_target_basis = false;
- real_t roll = 0;
- };
-
- LocalVector<FABRIK_Joint_Data> fabrik_data_chain;
- LocalVector<Transform3D> fabrik_transforms;
-
- NodePath target_node;
- ObjectID target_node_cache;
-
- real_t chain_tolerance = 0.01;
- int chain_max_iterations = 10;
- int chain_iterations = 0;
-
- void update_target_cache();
- void update_joint_tip_cache(int p_joint_idx);
-
- int final_joint_idx = 0;
- Transform3D target_global_pose;
- Transform3D origin_global_pose;
-
- void chain_backwards();
- void chain_forwards();
- void chain_apply();
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- int get_fabrik_data_chain_length();
- void set_fabrik_data_chain_length(int p_new_length);
-
- real_t get_chain_tolerance();
- void set_chain_tolerance(real_t p_tolerance);
-
- int get_chain_max_iterations();
- void set_chain_max_iterations(int p_iterations);
-
- String get_fabrik_joint_bone_name(int p_joint_idx) const;
- void set_fabrik_joint_bone_name(int p_joint_idx, String p_bone_name);
- int get_fabrik_joint_bone_index(int p_joint_idx) const;
- void set_fabrik_joint_bone_index(int p_joint_idx, int p_bone_idx);
- real_t get_fabrik_joint_length(int p_joint_idx) const;
- void set_fabrik_joint_length(int p_joint_idx, real_t p_bone_length);
- Vector3 get_fabrik_joint_magnet(int p_joint_idx) const;
- void set_fabrik_joint_magnet(int p_joint_idx, Vector3 p_magnet);
- bool get_fabrik_joint_auto_calculate_length(int p_joint_idx) const;
- void set_fabrik_joint_auto_calculate_length(int p_joint_idx, bool p_auto_calculate);
- void fabrik_joint_auto_calculate_length(int p_joint_idx);
- bool get_fabrik_joint_use_tip_node(int p_joint_idx) const;
- void set_fabrik_joint_use_tip_node(int p_joint_idx, bool p_use_tip_node);
- NodePath get_fabrik_joint_tip_node(int p_joint_idx) const;
- void set_fabrik_joint_tip_node(int p_joint_idx, NodePath p_tip_node);
- bool get_fabrik_joint_use_target_basis(int p_joint_idx) const;
- void set_fabrik_joint_use_target_basis(int p_joint_idx, bool p_use_basis);
- real_t get_fabrik_joint_roll(int p_joint_idx) const;
- void set_fabrik_joint_roll(int p_joint_idx, real_t p_roll);
-
- SkeletonModification3DFABRIK();
- ~SkeletonModification3DFABRIK();
-};
-
-#endif // SKELETON_MODIFICATION_3D_FABRIK_H
diff --git a/scene/resources/skeleton_modification_3d_jiggle.cpp b/scene/resources/skeleton_modification_3d_jiggle.cpp
deleted file mode 100644
index 2cfc7fb10f..0000000000
--- a/scene/resources/skeleton_modification_3d_jiggle.cpp
+++ /dev/null
@@ -1,582 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_jiggle.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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/resources/skeleton_modification_3d_jiggle.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DJiggle::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- const int jiggle_size = jiggle_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, jiggle_size, false);
-
- if (what == "bone_name") {
- set_jiggle_joint_bone_name(which, p_value);
- } else if (what == "bone_index") {
- set_jiggle_joint_bone_index(which, p_value);
- } else if (what == "override_defaults") {
- set_jiggle_joint_override(which, p_value);
- } else if (what == "stiffness") {
- set_jiggle_joint_stiffness(which, p_value);
- } else if (what == "mass") {
- set_jiggle_joint_mass(which, p_value);
- } else if (what == "damping") {
- set_jiggle_joint_damping(which, p_value);
- } else if (what == "use_gravity") {
- set_jiggle_joint_use_gravity(which, p_value);
- } else if (what == "gravity") {
- set_jiggle_joint_gravity(which, p_value);
- } else if (what == "roll") {
- set_jiggle_joint_roll(which, Math::deg_to_rad(real_t(p_value)));
- }
- return true;
- } else {
- if (path == "use_colliders") {
- set_use_colliders(p_value);
- } else if (path == "collision_mask") {
- set_collision_mask(p_value);
- }
- return true;
- }
- return true;
-}
-
-bool SkeletonModification3DJiggle::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path.begins_with("joint_data/")) {
- const int jiggle_size = jiggle_data_chain.size();
- int which = path.get_slicec('/', 1).to_int();
- String what = path.get_slicec('/', 2);
- ERR_FAIL_INDEX_V(which, jiggle_size, false);
-
- if (what == "bone_name") {
- r_ret = get_jiggle_joint_bone_name(which);
- } else if (what == "bone_index") {
- r_ret = get_jiggle_joint_bone_index(which);
- } else if (what == "override_defaults") {
- r_ret = get_jiggle_joint_override(which);
- } else if (what == "stiffness") {
- r_ret = get_jiggle_joint_stiffness(which);
- } else if (what == "mass") {
- r_ret = get_jiggle_joint_mass(which);
- } else if (what == "damping") {
- r_ret = get_jiggle_joint_damping(which);
- } else if (what == "use_gravity") {
- r_ret = get_jiggle_joint_use_gravity(which);
- } else if (what == "gravity") {
- r_ret = get_jiggle_joint_gravity(which);
- } else if (what == "roll") {
- r_ret = Math::rad_to_deg(get_jiggle_joint_roll(which));
- }
- return true;
- } else {
- if (path == "use_colliders") {
- r_ret = get_use_colliders();
- } else if (path == "collision_mask") {
- r_ret = get_collision_mask();
- }
- return true;
- }
- return true;
-}
-
-void SkeletonModification3DJiggle::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "use_colliders", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (use_colliders) {
- p_list->push_back(PropertyInfo(Variant::INT, "collision_mask", PROPERTY_HINT_LAYERS_3D_PHYSICS, "", PROPERTY_USAGE_DEFAULT));
- }
-
- for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) {
- String base_string = "joint_data/" + itos(i) + "/";
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, base_string + "bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, base_string + "bone_index", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "roll", PROPERTY_HINT_RANGE, "-360,360,0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "override_defaults", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
-
- if (jiggle_data_chain[i].override_defaults) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "stiffness", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "mass", PROPERTY_HINT_RANGE, "0, 1000, 0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, base_string + "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::BOOL, base_string + "use_gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (jiggle_data_chain[i].use_gravity) {
- p_list->push_back(PropertyInfo(Variant::VECTOR3, base_string + "gravity", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- }
- }
- }
-}
-
-void SkeletonModification3DJiggle::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
- if (!enabled) {
- return;
- }
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update...");
- update_cache();
- return;
- }
- Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- _print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!");
-
- for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) {
- _execute_jiggle_joint(i, target, p_delta);
- }
-
- execution_error_found = false;
-}
-
-void SkeletonModification3DJiggle::_execute_jiggle_joint(int p_joint_idx, Node3D *p_target, real_t p_delta) {
- // Adopted from: https://wiki.unity3d.com/index.php/JiggleBone
- // With modifications by TwistedTwigleg.
-
- if (jiggle_data_chain[p_joint_idx].bone_idx <= -2) {
- jiggle_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(jiggle_data_chain[p_joint_idx].bone_name);
- }
- if (_print_execution_error(
- jiggle_data_chain[p_joint_idx].bone_idx < 0 || jiggle_data_chain[p_joint_idx].bone_idx > stack->skeleton->get_bone_count(),
- "Jiggle joint " + itos(p_joint_idx) + " bone index is invalid. Cannot execute modification!")) {
- return;
- }
-
- Transform3D bone_local_pos = stack->skeleton->get_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx);
- if (bone_local_pos == Transform3D()) {
- bone_local_pos = stack->skeleton->get_bone_pose(jiggle_data_chain[p_joint_idx].bone_idx);
- }
-
- Transform3D new_bone_trans = stack->skeleton->local_pose_to_global_pose(jiggle_data_chain[p_joint_idx].bone_idx, bone_local_pos);
- Vector3 target_position = stack->skeleton->world_transform_to_global_pose(p_target->get_global_transform()).origin;
-
- jiggle_data_chain[p_joint_idx].force = (target_position - jiggle_data_chain[p_joint_idx].dynamic_position) * jiggle_data_chain[p_joint_idx].stiffness * p_delta;
-
- if (jiggle_data_chain[p_joint_idx].use_gravity) {
- Vector3 gravity_to_apply = new_bone_trans.basis.inverse().xform(jiggle_data_chain[p_joint_idx].gravity);
- jiggle_data_chain[p_joint_idx].force += gravity_to_apply * p_delta;
- }
-
- jiggle_data_chain[p_joint_idx].acceleration = jiggle_data_chain[p_joint_idx].force / jiggle_data_chain[p_joint_idx].mass;
- jiggle_data_chain[p_joint_idx].velocity += jiggle_data_chain[p_joint_idx].acceleration * (1 - jiggle_data_chain[p_joint_idx].damping);
-
- jiggle_data_chain[p_joint_idx].dynamic_position += jiggle_data_chain[p_joint_idx].velocity + jiggle_data_chain[p_joint_idx].force;
- jiggle_data_chain[p_joint_idx].dynamic_position += new_bone_trans.origin - jiggle_data_chain[p_joint_idx].last_position;
- jiggle_data_chain[p_joint_idx].last_position = new_bone_trans.origin;
-
- // Collision detection/response
- if (use_colliders) {
- if (execution_mode == SkeletonModificationStack3D::EXECUTION_MODE::execution_mode_physics_process) {
- Ref<World3D> world_3d = stack->skeleton->get_world_3d();
- ERR_FAIL_COND(world_3d.is_null());
- PhysicsDirectSpaceState3D *space_state = PhysicsServer3D::get_singleton()->space_get_direct_state(world_3d->get_space());
- PhysicsDirectSpaceState3D::RayResult ray_result;
-
- // Convert to world transforms, which is what the physics server needs
- Transform3D new_bone_trans_world = stack->skeleton->global_pose_to_world_transform(new_bone_trans);
- Transform3D dynamic_position_world = stack->skeleton->global_pose_to_world_transform(Transform3D(Basis(), jiggle_data_chain[p_joint_idx].dynamic_position));
-
- PhysicsDirectSpaceState3D::RayParameters ray_params;
- ray_params.from = new_bone_trans_world.origin;
- ray_params.to = dynamic_position_world.get_origin();
- ray_params.collision_mask = collision_mask;
-
- bool ray_hit = space_state->intersect_ray(ray_params, ray_result);
-
- if (ray_hit) {
- jiggle_data_chain[p_joint_idx].dynamic_position = jiggle_data_chain[p_joint_idx].last_noncollision_position;
- jiggle_data_chain[p_joint_idx].acceleration = Vector3(0, 0, 0);
- jiggle_data_chain[p_joint_idx].velocity = Vector3(0, 0, 0);
- } else {
- jiggle_data_chain[p_joint_idx].last_noncollision_position = jiggle_data_chain[p_joint_idx].dynamic_position;
- }
-
- } else {
- WARN_PRINT_ONCE("Jiggle modifier: You cannot detect colliders without the stack mode being set to _physics_process!");
- }
- }
-
- // Get the forward direction that the basis is facing in right now.
- stack->skeleton->update_bone_rest_forward_vector(jiggle_data_chain[p_joint_idx].bone_idx);
- Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(jiggle_data_chain[p_joint_idx].bone_idx);
-
- // Rotate the bone using the dynamic position!
- new_bone_trans.basis.rotate_to_align(forward_vector, new_bone_trans.origin.direction_to(jiggle_data_chain[p_joint_idx].dynamic_position));
-
- // Roll
- new_bone_trans.basis.rotate_local(forward_vector, jiggle_data_chain[p_joint_idx].roll);
-
- new_bone_trans = stack->skeleton->global_pose_to_local_pose(jiggle_data_chain[p_joint_idx].bone_idx, new_bone_trans);
- stack->skeleton->set_bone_local_pose_override(jiggle_data_chain[p_joint_idx].bone_idx, new_bone_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(jiggle_data_chain[p_joint_idx].bone_idx);
-}
-
-void SkeletonModification3DJiggle::_update_jiggle_joint_data() {
- for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) {
- if (!jiggle_data_chain[i].override_defaults) {
- set_jiggle_joint_stiffness(i, stiffness);
- set_jiggle_joint_mass(i, mass);
- set_jiggle_joint_damping(i, damping);
- set_jiggle_joint_use_gravity(i, use_gravity);
- set_jiggle_joint_gravity(i, gravity);
- }
- }
-}
-
-void SkeletonModification3DJiggle::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
-
- if (stack) {
- is_setup = true;
- execution_error_found = false;
-
- if (stack->skeleton) {
- for (uint32_t i = 0; i < jiggle_data_chain.size(); i++) {
- int bone_idx = jiggle_data_chain[i].bone_idx;
- if (bone_idx > 0 && bone_idx < stack->skeleton->get_bone_count()) {
- jiggle_data_chain[i].dynamic_position = stack->skeleton->local_pose_to_global_pose(bone_idx, stack->skeleton->get_bone_local_pose_override(bone_idx)).origin;
- }
- }
- }
-
- update_cache();
- }
-}
-
-void SkeletonModification3DJiggle::update_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
-
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: node is not in the scene tree!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DJiggle::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_cache();
-}
-
-NodePath SkeletonModification3DJiggle::get_target_node() const {
- return target_node;
-}
-
-void SkeletonModification3DJiggle::set_stiffness(real_t p_stiffness) {
- ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!");
- stiffness = p_stiffness;
- _update_jiggle_joint_data();
-}
-
-real_t SkeletonModification3DJiggle::get_stiffness() const {
- return stiffness;
-}
-
-void SkeletonModification3DJiggle::set_mass(real_t p_mass) {
- ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!");
- mass = p_mass;
- _update_jiggle_joint_data();
-}
-
-real_t SkeletonModification3DJiggle::get_mass() const {
- return mass;
-}
-
-void SkeletonModification3DJiggle::set_damping(real_t p_damping) {
- ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!");
- ERR_FAIL_COND_MSG(p_damping > 1, "Damping cannot be more than one!");
- damping = p_damping;
- _update_jiggle_joint_data();
-}
-
-real_t SkeletonModification3DJiggle::get_damping() const {
- return damping;
-}
-
-void SkeletonModification3DJiggle::set_use_gravity(bool p_use_gravity) {
- use_gravity = p_use_gravity;
- _update_jiggle_joint_data();
-}
-
-bool SkeletonModification3DJiggle::get_use_gravity() const {
- return use_gravity;
-}
-
-void SkeletonModification3DJiggle::set_gravity(Vector3 p_gravity) {
- gravity = p_gravity;
- _update_jiggle_joint_data();
-}
-
-Vector3 SkeletonModification3DJiggle::get_gravity() const {
- return gravity;
-}
-
-void SkeletonModification3DJiggle::set_use_colliders(bool p_use_collider) {
- use_colliders = p_use_collider;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DJiggle::get_use_colliders() const {
- return use_colliders;
-}
-
-void SkeletonModification3DJiggle::set_collision_mask(int p_mask) {
- collision_mask = p_mask;
-}
-
-int SkeletonModification3DJiggle::get_collision_mask() const {
- return collision_mask;
-}
-
-// Jiggle joint data functions
-int SkeletonModification3DJiggle::get_jiggle_data_chain_length() {
- return jiggle_data_chain.size();
-}
-
-void SkeletonModification3DJiggle::set_jiggle_data_chain_length(int p_length) {
- ERR_FAIL_COND(p_length < 0);
- jiggle_data_chain.resize(p_length);
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_bone_name(int p_joint_idx, String p_name) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
-
- jiggle_data_chain[p_joint_idx].bone_name = p_name;
- if (stack && stack->skeleton) {
- jiggle_data_chain[p_joint_idx].bone_idx = stack->skeleton->find_bone(p_name);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-String SkeletonModification3DJiggle::get_jiggle_joint_bone_name(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, "");
- return jiggle_data_chain[p_joint_idx].bone_name;
-}
-
-int SkeletonModification3DJiggle::get_jiggle_joint_bone_index(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return jiggle_data_chain[p_joint_idx].bone_idx;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_bone_index(int p_joint_idx, int p_bone_idx) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
- jiggle_data_chain[p_joint_idx].bone_idx = p_bone_idx;
-
- if (stack) {
- if (stack->skeleton) {
- jiggle_data_chain[p_joint_idx].bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_override(int p_joint_idx, bool p_override) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].override_defaults = p_override;
- _update_jiggle_joint_data();
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DJiggle::get_jiggle_joint_override(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return jiggle_data_chain[p_joint_idx].override_defaults;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_stiffness(int p_joint_idx, real_t p_stiffness) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_COND_MSG(p_stiffness < 0, "Stiffness cannot be set to a negative value!");
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].stiffness = p_stiffness;
-}
-
-real_t SkeletonModification3DJiggle::get_jiggle_joint_stiffness(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return jiggle_data_chain[p_joint_idx].stiffness;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_mass(int p_joint_idx, real_t p_mass) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_COND_MSG(p_mass < 0, "Mass cannot be set to a negative value!");
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].mass = p_mass;
-}
-
-real_t SkeletonModification3DJiggle::get_jiggle_joint_mass(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return jiggle_data_chain[p_joint_idx].mass;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_damping(int p_joint_idx, real_t p_damping) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_COND_MSG(p_damping < 0, "Damping cannot be set to a negative value!");
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].damping = p_damping;
-}
-
-real_t SkeletonModification3DJiggle::get_jiggle_joint_damping(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, -1);
- return jiggle_data_chain[p_joint_idx].damping;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].use_gravity = p_use_gravity;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DJiggle::get_jiggle_joint_use_gravity(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, false);
- return jiggle_data_chain[p_joint_idx].use_gravity;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_gravity(int p_joint_idx, Vector3 p_gravity) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].gravity = p_gravity;
-}
-
-Vector3 SkeletonModification3DJiggle::get_jiggle_joint_gravity(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, Vector3(0, 0, 0));
- return jiggle_data_chain[p_joint_idx].gravity;
-}
-
-void SkeletonModification3DJiggle::set_jiggle_joint_roll(int p_joint_idx, real_t p_roll) {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX(p_joint_idx, bone_chain_size);
- jiggle_data_chain[p_joint_idx].roll = p_roll;
-}
-
-real_t SkeletonModification3DJiggle::get_jiggle_joint_roll(int p_joint_idx) const {
- const int bone_chain_size = jiggle_data_chain.size();
- ERR_FAIL_INDEX_V(p_joint_idx, bone_chain_size, 0.0);
- return jiggle_data_chain[p_joint_idx].roll;
-}
-
-void SkeletonModification3DJiggle::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DJiggle::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DJiggle::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_jiggle_data_chain_length", "length"), &SkeletonModification3DJiggle::set_jiggle_data_chain_length);
- ClassDB::bind_method(D_METHOD("get_jiggle_data_chain_length"), &SkeletonModification3DJiggle::get_jiggle_data_chain_length);
-
- ClassDB::bind_method(D_METHOD("set_stiffness", "stiffness"), &SkeletonModification3DJiggle::set_stiffness);
- ClassDB::bind_method(D_METHOD("get_stiffness"), &SkeletonModification3DJiggle::get_stiffness);
- ClassDB::bind_method(D_METHOD("set_mass", "mass"), &SkeletonModification3DJiggle::set_mass);
- ClassDB::bind_method(D_METHOD("get_mass"), &SkeletonModification3DJiggle::get_mass);
- ClassDB::bind_method(D_METHOD("set_damping", "damping"), &SkeletonModification3DJiggle::set_damping);
- ClassDB::bind_method(D_METHOD("get_damping"), &SkeletonModification3DJiggle::get_damping);
- ClassDB::bind_method(D_METHOD("set_use_gravity", "use_gravity"), &SkeletonModification3DJiggle::set_use_gravity);
- ClassDB::bind_method(D_METHOD("get_use_gravity"), &SkeletonModification3DJiggle::get_use_gravity);
- ClassDB::bind_method(D_METHOD("set_gravity", "gravity"), &SkeletonModification3DJiggle::set_gravity);
- ClassDB::bind_method(D_METHOD("get_gravity"), &SkeletonModification3DJiggle::get_gravity);
-
- ClassDB::bind_method(D_METHOD("set_use_colliders", "use_colliders"), &SkeletonModification3DJiggle::set_use_colliders);
- ClassDB::bind_method(D_METHOD("get_use_colliders"), &SkeletonModification3DJiggle::get_use_colliders);
- ClassDB::bind_method(D_METHOD("set_collision_mask", "mask"), &SkeletonModification3DJiggle::set_collision_mask);
- ClassDB::bind_method(D_METHOD("get_collision_mask"), &SkeletonModification3DJiggle::get_collision_mask);
-
- // Jiggle joint data functions
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_name", "joint_idx", "name"), &SkeletonModification3DJiggle::set_jiggle_joint_bone_name);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_name", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_bone_name);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_bone_index", "joint_idx", "bone_idx"), &SkeletonModification3DJiggle::set_jiggle_joint_bone_index);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_bone_index", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_bone_index);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_override", "joint_idx", "override"), &SkeletonModification3DJiggle::set_jiggle_joint_override);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_override", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_override);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_stiffness", "joint_idx", "stiffness"), &SkeletonModification3DJiggle::set_jiggle_joint_stiffness);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_stiffness", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_stiffness);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_mass", "joint_idx", "mass"), &SkeletonModification3DJiggle::set_jiggle_joint_mass);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_mass", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_mass);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_damping", "joint_idx", "damping"), &SkeletonModification3DJiggle::set_jiggle_joint_damping);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_damping", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_damping);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_use_gravity", "joint_idx", "use_gravity"), &SkeletonModification3DJiggle::set_jiggle_joint_use_gravity);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_use_gravity", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_use_gravity);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_gravity", "joint_idx", "gravity"), &SkeletonModification3DJiggle::set_jiggle_joint_gravity);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_gravity", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_gravity);
- ClassDB::bind_method(D_METHOD("set_jiggle_joint_roll", "joint_idx", "roll"), &SkeletonModification3DJiggle::set_jiggle_joint_roll);
- ClassDB::bind_method(D_METHOD("get_jiggle_joint_roll", "joint_idx"), &SkeletonModification3DJiggle::get_jiggle_joint_roll);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "jiggle_data_chain_length", PROPERTY_HINT_RANGE, "0,100,1"), "set_jiggle_data_chain_length", "get_jiggle_data_chain_length");
- ADD_GROUP("Default Joint Settings", "");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "stiffness"), "set_stiffness", "get_stiffness");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "mass"), "set_mass", "get_mass");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "damping", PROPERTY_HINT_RANGE, "0, 1, 0.01"), "set_damping", "get_damping");
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_gravity"), "set_use_gravity", "get_use_gravity");
- ADD_PROPERTY(PropertyInfo(Variant::VECTOR3, "gravity"), "set_gravity", "get_gravity");
- ADD_GROUP("", "");
-}
-
-SkeletonModification3DJiggle::SkeletonModification3DJiggle() {
- stack = nullptr;
- is_setup = false;
- jiggle_data_chain = Vector<Jiggle_Joint_Data>();
- stiffness = 3;
- mass = 0.75;
- damping = 0.75;
- use_gravity = false;
- gravity = Vector3(0, -6.0, 0);
- enabled = true;
-}
-
-SkeletonModification3DJiggle::~SkeletonModification3DJiggle() {
-}
diff --git a/scene/resources/skeleton_modification_3d_jiggle.h b/scene/resources/skeleton_modification_3d_jiggle.h
deleted file mode 100644
index cca620a72d..0000000000
--- a/scene/resources/skeleton_modification_3d_jiggle.h
+++ /dev/null
@@ -1,138 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_jiggle.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 SKELETON_MODIFICATION_3D_JIGGLE_H
-#define SKELETON_MODIFICATION_3D_JIGGLE_H
-
-#include "core/templates/local_vector.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DJiggle : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DJiggle, SkeletonModification3D);
-
-private:
- struct Jiggle_Joint_Data {
- String bone_name = "";
- int bone_idx = -1;
-
- bool override_defaults = false;
- real_t stiffness = 3;
- real_t mass = 0.75;
- real_t damping = 0.75;
- bool use_gravity = false;
- Vector3 gravity = Vector3(0, -6.0, 0);
- real_t roll = 0;
-
- Vector3 cached_rotation = Vector3(0, 0, 0);
- Vector3 force = Vector3(0, 0, 0);
- Vector3 acceleration = Vector3(0, 0, 0);
- Vector3 velocity = Vector3(0, 0, 0);
- Vector3 last_position = Vector3(0, 0, 0);
- Vector3 dynamic_position = Vector3(0, 0, 0);
-
- Vector3 last_noncollision_position = Vector3(0, 0, 0);
- };
-
- NodePath target_node;
- ObjectID target_node_cache;
- LocalVector<Jiggle_Joint_Data> jiggle_data_chain;
-
- real_t stiffness = 3;
- real_t mass = 0.75;
- real_t damping = 0.75;
- bool use_gravity = false;
- Vector3 gravity = Vector3(0, -6.0, 0);
-
- bool use_colliders = false;
- uint32_t collision_mask = 1;
-
- void update_cache();
- void _execute_jiggle_joint(int p_joint_idx, Node3D *p_target, real_t p_delta);
- void _update_jiggle_joint_data();
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- void set_stiffness(real_t p_stiffness);
- real_t get_stiffness() const;
- void set_mass(real_t p_mass);
- real_t get_mass() const;
- void set_damping(real_t p_damping);
- real_t get_damping() const;
-
- void set_use_gravity(bool p_use_gravity);
- bool get_use_gravity() const;
- void set_gravity(Vector3 p_gravity);
- Vector3 get_gravity() const;
-
- void set_use_colliders(bool p_use_colliders);
- bool get_use_colliders() const;
- void set_collision_mask(int p_mask);
- int get_collision_mask() const;
-
- int get_jiggle_data_chain_length();
- void set_jiggle_data_chain_length(int p_new_length);
-
- void set_jiggle_joint_bone_name(int p_joint_idx, String p_name);
- String get_jiggle_joint_bone_name(int p_joint_idx) const;
- void set_jiggle_joint_bone_index(int p_joint_idx, int p_idx);
- int get_jiggle_joint_bone_index(int p_joint_idx) const;
-
- void set_jiggle_joint_override(int p_joint_idx, bool p_override);
- bool get_jiggle_joint_override(int p_joint_idx) const;
- void set_jiggle_joint_stiffness(int p_joint_idx, real_t p_stiffness);
- real_t get_jiggle_joint_stiffness(int p_joint_idx) const;
- void set_jiggle_joint_mass(int p_joint_idx, real_t p_mass);
- real_t get_jiggle_joint_mass(int p_joint_idx) const;
- void set_jiggle_joint_damping(int p_joint_idx, real_t p_damping);
- real_t get_jiggle_joint_damping(int p_joint_idx) const;
- void set_jiggle_joint_use_gravity(int p_joint_idx, bool p_use_gravity);
- bool get_jiggle_joint_use_gravity(int p_joint_idx) const;
- void set_jiggle_joint_gravity(int p_joint_idx, Vector3 p_gravity);
- Vector3 get_jiggle_joint_gravity(int p_joint_idx) const;
- void set_jiggle_joint_roll(int p_joint_idx, real_t p_roll);
- real_t get_jiggle_joint_roll(int p_joint_idx) const;
-
- SkeletonModification3DJiggle();
- ~SkeletonModification3DJiggle();
-};
-
-#endif // SKELETON_MODIFICATION_3D_JIGGLE_H
diff --git a/scene/resources/skeleton_modification_3d_lookat.cpp b/scene/resources/skeleton_modification_3d_lookat.cpp
deleted file mode 100644
index 57eedeb64e..0000000000
--- a/scene/resources/skeleton_modification_3d_lookat.cpp
+++ /dev/null
@@ -1,267 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_lookat.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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/resources/skeleton_modification_3d_lookat.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DLookAt::_set(const StringName &p_path, const Variant &p_value) {
- if (p_path == "lock_rotation_to_plane") {
- set_lock_rotation_to_plane(p_value);
- } else if (p_path == "lock_rotation_plane") {
- set_lock_rotation_plane(p_value);
- } else if (p_path == "additional_rotation") {
- Vector3 tmp = p_value;
- tmp.x = Math::deg_to_rad(tmp.x);
- tmp.y = Math::deg_to_rad(tmp.y);
- tmp.z = Math::deg_to_rad(tmp.z);
- set_additional_rotation(tmp);
- }
-
- return true;
-}
-
-bool SkeletonModification3DLookAt::_get(const StringName &p_path, Variant &r_ret) const {
- if (p_path == "lock_rotation_to_plane") {
- r_ret = get_lock_rotation_to_plane();
- } else if (p_path == "lock_rotation_plane") {
- r_ret = get_lock_rotation_plane();
- } else if (p_path == "additional_rotation") {
- Vector3 tmp = get_additional_rotation();
- tmp.x = Math::rad_to_deg(tmp.x);
- tmp.y = Math::rad_to_deg(tmp.y);
- tmp.z = Math::rad_to_deg(tmp.z);
- r_ret = tmp;
- }
-
- return true;
-}
-
-void SkeletonModification3DLookAt::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "lock_rotation_to_plane", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (lock_rotation_to_plane) {
- p_list->push_back(PropertyInfo(Variant::INT, "lock_rotation_plane", PROPERTY_HINT_ENUM, "X plane,Y plane,Z plane", PROPERTY_USAGE_DEFAULT));
- }
- p_list->push_back(PropertyInfo(Variant::VECTOR3, "additional_rotation", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
-}
-
-void SkeletonModification3DLookAt::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
- if (!enabled) {
- return;
- }
-
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update...");
- update_cache();
- return;
- }
-
- if (bone_idx <= -2) {
- bone_idx = stack->skeleton->find_bone(bone_name);
- }
-
- Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- if (_print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- if (_print_execution_error(bone_idx <= -1, "Bone index is invalid. Cannot execute modification!")) {
- return;
- }
- Transform3D new_bone_trans = stack->skeleton->get_bone_local_pose_override(bone_idx);
- if (new_bone_trans == Transform3D()) {
- new_bone_trans = stack->skeleton->get_bone_pose(bone_idx);
- }
- Vector3 target_pos = stack->skeleton->global_pose_to_local_pose(bone_idx, stack->skeleton->world_transform_to_global_pose(target->get_global_transform())).origin;
-
- // Lock the rotation to a plane relative to the bone by changing the target position
- if (lock_rotation_to_plane) {
- if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_X) {
- target_pos.x = new_bone_trans.origin.x;
- } else if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_Y) {
- target_pos.y = new_bone_trans.origin.y;
- } else if (lock_rotation_plane == ROTATION_PLANE::ROTATION_PLANE_Z) {
- target_pos.z = new_bone_trans.origin.z;
- }
- }
-
- // Look at the target!
- new_bone_trans = new_bone_trans.looking_at(target_pos, Vector3(0, 1, 0));
- // Convert from Z-forward to whatever direction the bone faces.
- stack->skeleton->update_bone_rest_forward_vector(bone_idx);
- new_bone_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(bone_idx, new_bone_trans.basis);
-
- // Apply additional rotation
- new_bone_trans.basis.rotate_local(Vector3(1, 0, 0), additional_rotation.x);
- new_bone_trans.basis.rotate_local(Vector3(0, 1, 0), additional_rotation.y);
- new_bone_trans.basis.rotate_local(Vector3(0, 0, 1), additional_rotation.z);
-
- stack->skeleton->set_bone_local_pose_override(bone_idx, new_bone_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(bone_idx);
-
- // If we completed it successfully, then we can set execution_error_found to false
- execution_error_found = false;
-}
-
-void SkeletonModification3DLookAt::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
-
- if (stack != nullptr) {
- is_setup = true;
- execution_error_found = false;
- update_cache();
- }
-}
-
-void SkeletonModification3DLookAt::set_bone_name(String p_name) {
- bone_name = p_name;
- if (stack) {
- if (stack->skeleton) {
- bone_idx = stack->skeleton->find_bone(bone_name);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-String SkeletonModification3DLookAt::get_bone_name() const {
- return bone_name;
-}
-
-int SkeletonModification3DLookAt::get_bone_index() const {
- return bone_idx;
-}
-
-void SkeletonModification3DLookAt::set_bone_index(int p_bone_idx) {
- ERR_FAIL_COND_MSG(p_bone_idx < 0, "Bone index is out of range: The index is too low!");
- bone_idx = p_bone_idx;
-
- if (stack) {
- if (stack->skeleton) {
- bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-void SkeletonModification3DLookAt::update_cache() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
-
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: Node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: Node is not in the scene tree!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DLookAt::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_cache();
-}
-
-NodePath SkeletonModification3DLookAt::get_target_node() const {
- return target_node;
-}
-
-Vector3 SkeletonModification3DLookAt::get_additional_rotation() const {
- return additional_rotation;
-}
-
-void SkeletonModification3DLookAt::set_additional_rotation(Vector3 p_offset) {
- additional_rotation = p_offset;
-}
-
-bool SkeletonModification3DLookAt::get_lock_rotation_to_plane() const {
- return lock_rotation_plane;
-}
-
-void SkeletonModification3DLookAt::set_lock_rotation_to_plane(bool p_lock_rotation) {
- lock_rotation_to_plane = p_lock_rotation;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DLookAt::get_lock_rotation_plane() const {
- return lock_rotation_plane;
-}
-
-void SkeletonModification3DLookAt::set_lock_rotation_plane(int p_plane) {
- lock_rotation_plane = p_plane;
-}
-
-void SkeletonModification3DLookAt::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_bone_name", "name"), &SkeletonModification3DLookAt::set_bone_name);
- ClassDB::bind_method(D_METHOD("get_bone_name"), &SkeletonModification3DLookAt::get_bone_name);
-
- ClassDB::bind_method(D_METHOD("set_bone_index", "bone_idx"), &SkeletonModification3DLookAt::set_bone_index);
- ClassDB::bind_method(D_METHOD("get_bone_index"), &SkeletonModification3DLookAt::get_bone_index);
-
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DLookAt::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DLookAt::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_additional_rotation", "additional_rotation"), &SkeletonModification3DLookAt::set_additional_rotation);
- ClassDB::bind_method(D_METHOD("get_additional_rotation"), &SkeletonModification3DLookAt::get_additional_rotation);
-
- ClassDB::bind_method(D_METHOD("set_lock_rotation_to_plane", "lock_to_plane"), &SkeletonModification3DLookAt::set_lock_rotation_to_plane);
- ClassDB::bind_method(D_METHOD("get_lock_rotation_to_plane"), &SkeletonModification3DLookAt::get_lock_rotation_to_plane);
- ClassDB::bind_method(D_METHOD("set_lock_rotation_plane", "plane"), &SkeletonModification3DLookAt::set_lock_rotation_plane);
- ClassDB::bind_method(D_METHOD("get_lock_rotation_plane"), &SkeletonModification3DLookAt::get_lock_rotation_plane);
-
- ADD_PROPERTY(PropertyInfo(Variant::STRING_NAME, "bone_name"), "set_bone_name", "get_bone_name");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "bone_index"), "set_bone_index", "get_bone_index");
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
-}
-
-SkeletonModification3DLookAt::SkeletonModification3DLookAt() {
- stack = nullptr;
- is_setup = false;
- bone_name = "";
- bone_idx = -2;
- additional_rotation = Vector3();
- lock_rotation_to_plane = false;
- enabled = true;
-}
-
-SkeletonModification3DLookAt::~SkeletonModification3DLookAt() {
-}
diff --git a/scene/resources/skeleton_modification_3d_lookat.h b/scene/resources/skeleton_modification_3d_lookat.h
deleted file mode 100644
index 9a25ac530d..0000000000
--- a/scene/resources/skeleton_modification_3d_lookat.h
+++ /dev/null
@@ -1,89 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_lookat.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 SKELETON_MODIFICATION_3D_LOOKAT_H
-#define SKELETON_MODIFICATION_3D_LOOKAT_H
-
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DLookAt : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DLookAt, SkeletonModification3D);
-
-private:
- String bone_name = "";
- int bone_idx = -1;
- NodePath target_node;
- ObjectID target_node_cache;
-
- Vector3 additional_rotation = Vector3(1, 0, 0);
- bool lock_rotation_to_plane = false;
- int lock_rotation_plane = ROTATION_PLANE_X;
-
- void update_cache();
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- enum ROTATION_PLANE {
- ROTATION_PLANE_X,
- ROTATION_PLANE_Y,
- ROTATION_PLANE_Z
- };
-
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_bone_name(String p_name);
- String get_bone_name() const;
-
- void set_bone_index(int p_idx);
- int get_bone_index() const;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- void set_additional_rotation(Vector3 p_offset);
- Vector3 get_additional_rotation() const;
-
- void set_lock_rotation_to_plane(bool p_lock_to_plane);
- bool get_lock_rotation_to_plane() const;
- void set_lock_rotation_plane(int p_plane);
- int get_lock_rotation_plane() const;
-
- SkeletonModification3DLookAt();
- ~SkeletonModification3DLookAt();
-};
-
-#endif // SKELETON_MODIFICATION_3D_LOOKAT_H
diff --git a/scene/resources/skeleton_modification_3d_stackholder.cpp b/scene/resources/skeleton_modification_3d_stackholder.cpp
deleted file mode 100644
index 1598badb30..0000000000
--- a/scene/resources/skeleton_modification_3d_stackholder.cpp
+++ /dev/null
@@ -1,104 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_stackholder.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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/resources/skeleton_modification_3d_stackholder.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DStackHolder::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path == "held_modification_stack") {
- set_held_modification_stack(p_value);
- }
- return true;
-}
-
-bool SkeletonModification3DStackHolder::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path == "held_modification_stack") {
- r_ret = get_held_modification_stack();
- }
- return true;
-}
-
-void SkeletonModification3DStackHolder::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::OBJECT, "held_modification_stack", PROPERTY_HINT_RESOURCE_TYPE, "SkeletonModificationStack3D", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
-}
-
-void SkeletonModification3DStackHolder::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
-
- if (held_modification_stack.is_valid()) {
- held_modification_stack->execute(p_delta, execution_mode);
- }
-}
-
-void SkeletonModification3DStackHolder::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
-
- if (stack != nullptr) {
- is_setup = true;
-
- if (held_modification_stack.is_valid()) {
- held_modification_stack->set_skeleton(stack->get_skeleton());
- held_modification_stack->setup();
- }
- }
-}
-
-void SkeletonModification3DStackHolder::set_held_modification_stack(Ref<SkeletonModificationStack3D> p_held_stack) {
- held_modification_stack = p_held_stack;
-
- if (is_setup && held_modification_stack.is_valid()) {
- held_modification_stack->set_skeleton(stack->get_skeleton());
- held_modification_stack->setup();
- }
-}
-
-Ref<SkeletonModificationStack3D> SkeletonModification3DStackHolder::get_held_modification_stack() const {
- return held_modification_stack;
-}
-
-void SkeletonModification3DStackHolder::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_held_modification_stack", "held_modification_stack"), &SkeletonModification3DStackHolder::set_held_modification_stack);
- ClassDB::bind_method(D_METHOD("get_held_modification_stack"), &SkeletonModification3DStackHolder::get_held_modification_stack);
-}
-
-SkeletonModification3DStackHolder::SkeletonModification3DStackHolder() {
- stack = nullptr;
- is_setup = false;
- enabled = true;
-}
-
-SkeletonModification3DStackHolder::~SkeletonModification3DStackHolder() {
-}
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.cpp b/scene/resources/skeleton_modification_3d_twoboneik.cpp
deleted file mode 100644
index 7d5b4d2b55..0000000000
--- a/scene/resources/skeleton_modification_3d_twoboneik.cpp
+++ /dev/null
@@ -1,617 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_twoboneik.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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/resources/skeleton_modification_3d_twoboneik.h"
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-bool SkeletonModification3DTwoBoneIK::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path == "use_tip_node") {
- set_use_tip_node(p_value);
- } else if (path == "tip_node") {
- set_tip_node(p_value);
- } else if (path == "auto_calculate_joint_length") {
- set_auto_calculate_joint_length(p_value);
- } else if (path == "use_pole_node") {
- set_use_pole_node(p_value);
- } else if (path == "pole_node") {
- set_pole_node(p_value);
- } else if (path == "joint_one_length") {
- set_joint_one_length(p_value);
- } else if (path == "joint_two_length") {
- set_joint_two_length(p_value);
- } else if (path == "joint_one/bone_name") {
- set_joint_one_bone_name(p_value);
- } else if (path == "joint_one/bone_idx") {
- set_joint_one_bone_idx(p_value);
- } else if (path == "joint_one/roll") {
- set_joint_one_roll(Math::deg_to_rad(real_t(p_value)));
- } else if (path == "joint_two/bone_name") {
- set_joint_two_bone_name(p_value);
- } else if (path == "joint_two/bone_idx") {
- set_joint_two_bone_idx(p_value);
- } else if (path == "joint_two/roll") {
- set_joint_two_roll(Math::deg_to_rad(real_t(p_value)));
- }
-
- return true;
-}
-
-bool SkeletonModification3DTwoBoneIK::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path == "use_tip_node") {
- r_ret = get_use_tip_node();
- } else if (path == "tip_node") {
- r_ret = get_tip_node();
- } else if (path == "auto_calculate_joint_length") {
- r_ret = get_auto_calculate_joint_length();
- } else if (path == "use_pole_node") {
- r_ret = get_use_pole_node();
- } else if (path == "pole_node") {
- r_ret = get_pole_node();
- } else if (path == "joint_one_length") {
- r_ret = get_joint_one_length();
- } else if (path == "joint_two_length") {
- r_ret = get_joint_two_length();
- } else if (path == "joint_one/bone_name") {
- r_ret = get_joint_one_bone_name();
- } else if (path == "joint_one/bone_idx") {
- r_ret = get_joint_one_bone_idx();
- } else if (path == "joint_one/roll") {
- r_ret = Math::rad_to_deg(get_joint_one_roll());
- } else if (path == "joint_two/bone_name") {
- r_ret = get_joint_two_bone_name();
- } else if (path == "joint_two/bone_idx") {
- r_ret = get_joint_two_bone_idx();
- } else if (path == "joint_two/roll") {
- r_ret = Math::rad_to_deg(get_joint_two_roll());
- }
-
- return true;
-}
-
-void SkeletonModification3DTwoBoneIK::_get_property_list(List<PropertyInfo> *p_list) const {
- p_list->push_back(PropertyInfo(Variant::BOOL, "use_tip_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (use_tip_node) {
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "tip_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT));
- }
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "auto_calculate_joint_length", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (!auto_calculate_joint_length) {
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_one_length", PROPERTY_HINT_RANGE, "-1, 10000, 0.001", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_two_length", PROPERTY_HINT_RANGE, "-1, 10000, 0.001", PROPERTY_USAGE_DEFAULT));
- }
-
- p_list->push_back(PropertyInfo(Variant::BOOL, "use_pole_node", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- if (use_pole_node) {
- p_list->push_back(PropertyInfo(Variant::NODE_PATH, "pole_node", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D", PROPERTY_USAGE_DEFAULT));
- }
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "joint_one/bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, "joint_one/bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_one/roll", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
-
- p_list->push_back(PropertyInfo(Variant::STRING_NAME, "joint_two/bone_name", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::INT, "joint_two/bone_idx", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT));
- p_list->push_back(PropertyInfo(Variant::FLOAT, "joint_two/roll", PROPERTY_HINT_RANGE, "-360, 360, 0.01", PROPERTY_USAGE_DEFAULT));
-}
-
-void SkeletonModification3DTwoBoneIK::_execute(real_t p_delta) {
- ERR_FAIL_COND_MSG(!stack || !is_setup || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot execute!");
-
- if (!enabled) {
- return;
- }
-
- if (_print_execution_error(joint_one_bone_idx < 0 || joint_two_bone_idx < 0,
- "One (or more) of the bones in the modification have invalid bone indexes. Cannot execute modification!")) {
- return;
- }
-
- if (target_node_cache.is_null()) {
- _print_execution_error(true, "Target cache is out of date. Attempting to update...");
- update_cache_target();
- return;
- }
-
- // Update joint lengths (if needed)
- if (auto_calculate_joint_length && (joint_one_length < 0 || joint_two_length < 0)) {
- calculate_joint_lengths();
- }
-
- // Adopted from the links below:
- // http://theorangeduck.com/page/simple-two-joint
- // https://www.alanzucconi.com/2018/05/02/ik-2d-2/
- // With modifications by TwistedTwigleg
- Node3D *target = Object::cast_to<Node3D>(ObjectDB::get_instance(target_node_cache));
- if (_print_execution_error(!target || !target->is_inside_tree(), "Target node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- Transform3D target_trans = stack->skeleton->world_transform_to_global_pose(target->get_global_transform());
-
- Transform3D bone_one_trans;
- Transform3D bone_two_trans;
-
- // Make the first joint look at the pole, and the second look at the target. That way, the
- // TwoBoneIK solver has to really only handle extension/contraction, which should make it align with the pole.
- if (use_pole_node) {
- if (pole_node_cache.is_null()) {
- _print_execution_error(true, "Pole cache is out of date. Attempting to update...");
- update_cache_pole();
- return;
- }
-
- Node3D *pole = Object::cast_to<Node3D>(ObjectDB::get_instance(pole_node_cache));
- if (_print_execution_error(!pole || !pole->is_inside_tree(), "Pole node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- Transform3D pole_trans = stack->skeleton->world_transform_to_global_pose(pole->get_global_transform());
-
- Transform3D bone_one_local_pos = stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx);
- if (bone_one_local_pos == Transform3D()) {
- bone_one_local_pos = stack->skeleton->get_bone_pose(joint_one_bone_idx);
- }
- Transform3D bone_two_local_pos = stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx);
- if (bone_two_local_pos == Transform3D()) {
- bone_two_local_pos = stack->skeleton->get_bone_pose(joint_two_bone_idx);
- }
-
- bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, bone_one_local_pos);
- bone_one_trans = bone_one_trans.looking_at(pole_trans.origin, Vector3(0, 1, 0));
- bone_one_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(joint_one_bone_idx, bone_one_trans.basis);
- stack->skeleton->update_bone_rest_forward_vector(joint_one_bone_idx);
- bone_one_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_one_bone_idx), joint_one_roll);
- stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, stack->skeleton->global_pose_to_local_pose(joint_one_bone_idx, bone_one_trans), stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_one_bone_idx);
-
- bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, bone_two_local_pos);
- bone_two_trans = bone_two_trans.looking_at(target_trans.origin, Vector3(0, 1, 0));
- bone_two_trans.basis = stack->skeleton->global_pose_z_forward_to_bone_forward(joint_two_bone_idx, bone_two_trans.basis);
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll);
- stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans), stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx);
- } else {
- Transform3D bone_one_local_pos = stack->skeleton->get_bone_local_pose_override(joint_one_bone_idx);
- if (bone_one_local_pos == Transform3D()) {
- bone_one_local_pos = stack->skeleton->get_bone_pose(joint_one_bone_idx);
- }
- Transform3D bone_two_local_pos = stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx);
- if (bone_two_local_pos == Transform3D()) {
- bone_two_local_pos = stack->skeleton->get_bone_pose(joint_two_bone_idx);
- }
-
- bone_one_trans = stack->skeleton->local_pose_to_global_pose(joint_one_bone_idx, bone_one_local_pos);
- bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, bone_two_local_pos);
- }
-
- Transform3D bone_two_tip_trans;
- if (use_tip_node) {
- if (tip_node_cache.is_null()) {
- _print_execution_error(true, "Tip cache is out of date. Attempting to update...");
- update_cache_tip();
- return;
- }
- Node3D *tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache));
- if (_print_execution_error(!tip || !tip->is_inside_tree(), "Tip node is not in the scene tree. Cannot execute modification!")) {
- return;
- }
- bone_two_tip_trans = stack->skeleton->world_transform_to_global_pose(tip->get_global_transform());
- } else {
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- bone_two_tip_trans = bone_two_trans;
- bone_two_tip_trans.origin += bone_two_trans.basis.xform(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx)).normalized() * joint_two_length;
- }
-
- real_t joint_one_to_target_length = bone_one_trans.origin.distance_to(target_trans.origin);
- if (joint_one_length + joint_two_length < joint_one_to_target_length) {
- // Set the target *just* out of reach to straighten the bones
- joint_one_to_target_length = joint_one_length + joint_two_length + 0.01;
- } else if (joint_one_to_target_length < joint_one_length) {
- // Place the target in reach so the solver doesn't do crazy things
- joint_one_to_target_length = joint_one_length;
- }
-
- // Get the square lengths for all three sides of the triangle we'll use to calculate the angles
- real_t sqr_one_length = joint_one_length * joint_one_length;
- real_t sqr_two_length = joint_two_length * joint_two_length;
- real_t sqr_three_length = joint_one_to_target_length * joint_one_to_target_length;
-
- // Calculate the angles for the first joint using the law of cosigns
- real_t ac_ab_0 = Math::acos(CLAMP(bone_two_tip_trans.origin.direction_to(bone_one_trans.origin).dot(bone_two_trans.origin.direction_to(bone_one_trans.origin)), -1, 1));
- real_t ac_at_0 = Math::acos(CLAMP(bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).dot(bone_one_trans.origin.direction_to(target_trans.origin)), -1, 1));
- real_t ac_ab_1 = Math::acos(CLAMP((sqr_two_length - sqr_one_length - sqr_three_length) / (-2.0 * joint_one_length * joint_one_to_target_length), -1, 1));
-
- // Calculate the angles of rotation. Angle 0 is the extension/contraction axis, while angle 1 is the rotation axis to align the triangle to the target
- Vector3 axis_0 = bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).cross(bone_one_trans.origin.direction_to(bone_two_trans.origin));
- Vector3 axis_1 = bone_one_trans.origin.direction_to(bone_two_tip_trans.origin).cross(bone_one_trans.origin.direction_to(target_trans.origin));
-
- // Make a quaternion with the delta rotation needed to rotate the first joint into alignment and apply it to the transform.
- Quaternion bone_one_quat = bone_one_trans.basis.get_rotation_quaternion();
- Quaternion rot_0 = Quaternion(bone_one_quat.inverse().xform(axis_0).normalized(), (ac_ab_1 - ac_ab_0));
- Quaternion rot_2 = Quaternion(bone_one_quat.inverse().xform(axis_1).normalized(), ac_at_0);
- bone_one_trans.basis.set_quaternion(bone_one_quat * (rot_0 * rot_2));
-
- stack->skeleton->update_bone_rest_forward_vector(joint_one_bone_idx);
- bone_one_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_one_bone_idx), joint_one_roll);
-
- // Apply the rotation to the first joint
- bone_one_trans = stack->skeleton->global_pose_to_local_pose(joint_one_bone_idx, bone_one_trans);
- bone_one_trans.origin = Vector3(0, 0, 0);
- stack->skeleton->set_bone_local_pose_override(joint_one_bone_idx, bone_one_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_one_bone_idx);
-
- if (use_pole_node) {
- // Update bone_two_trans so its at the latest position, with the rotation of bone_one_trans taken into account, then look at the target.
- bone_two_trans = stack->skeleton->local_pose_to_global_pose(joint_two_bone_idx, stack->skeleton->get_bone_local_pose_override(joint_two_bone_idx));
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- Vector3 forward_vector = stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx);
- bone_two_trans.basis.rotate_to_align(forward_vector, bone_two_trans.origin.direction_to(target_trans.origin));
-
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll);
-
- bone_two_trans = stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans);
- stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, bone_two_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx);
- } else {
- // Calculate the angles for the second joint using the law of cosigns, make a quaternion with the delta rotation needed to rotate the joint into
- // alignment, and then apply it to the second joint.
- real_t ba_bc_0 = Math::acos(CLAMP(bone_two_trans.origin.direction_to(bone_one_trans.origin).dot(bone_two_trans.origin.direction_to(bone_two_tip_trans.origin)), -1, 1));
- real_t ba_bc_1 = Math::acos(CLAMP((sqr_three_length - sqr_one_length - sqr_two_length) / (-2.0 * joint_one_length * joint_two_length), -1, 1));
- Quaternion bone_two_quat = bone_two_trans.basis.get_rotation_quaternion();
- Quaternion rot_1 = Quaternion(bone_two_quat.inverse().xform(axis_0).normalized(), (ba_bc_1 - ba_bc_0));
- bone_two_trans.basis.set_quaternion(bone_two_quat * rot_1);
-
- stack->skeleton->update_bone_rest_forward_vector(joint_two_bone_idx);
- bone_two_trans.basis.rotate_local(stack->skeleton->get_bone_axis_forward_vector(joint_two_bone_idx), joint_two_roll);
-
- bone_two_trans = stack->skeleton->global_pose_to_local_pose(joint_two_bone_idx, bone_two_trans);
- bone_two_trans.origin = Vector3(0, 0, 0);
- stack->skeleton->set_bone_local_pose_override(joint_two_bone_idx, bone_two_trans, stack->strength, true);
- stack->skeleton->force_update_bone_children_transforms(joint_two_bone_idx);
- }
-}
-
-void SkeletonModification3DTwoBoneIK::_setup_modification(SkeletonModificationStack3D *p_stack) {
- stack = p_stack;
-
- if (stack != nullptr) {
- is_setup = true;
- execution_error_found = false;
- update_cache_target();
- update_cache_tip();
- }
-}
-
-void SkeletonModification3DTwoBoneIK::update_cache_target() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update target cache: modification is not properly setup!");
- return;
- }
-
- target_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree() && target_node.is_empty() == false) {
- if (stack->skeleton->has_node(target_node)) {
- Node *node = stack->skeleton->get_node(target_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update target cache: Target node is this modification's skeleton or cannot be found. Cannot execute modification");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update target cache: Target node is not in the scene tree. Cannot execute modification!");
- target_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DTwoBoneIK::update_cache_tip() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update tip cache: modification is not properly setup!");
- return;
- }
-
- tip_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(tip_node)) {
- Node *node = stack->skeleton->get_node(tip_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update tip cache: Tip node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update tip cache: Tip node is not in the scene tree. Cannot execute modification!");
- tip_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DTwoBoneIK::update_cache_pole() {
- if (!is_setup || !stack) {
- _print_execution_error(true, "Cannot update pole cache: modification is not properly setup!");
- return;
- }
-
- pole_node_cache = ObjectID();
- if (stack->skeleton) {
- if (stack->skeleton->is_inside_tree()) {
- if (stack->skeleton->has_node(pole_node)) {
- Node *node = stack->skeleton->get_node(pole_node);
- ERR_FAIL_COND_MSG(!node || stack->skeleton == node,
- "Cannot update pole cache: Pole node is this modification's skeleton or cannot be found!");
- ERR_FAIL_COND_MSG(!node->is_inside_tree(),
- "Cannot update pole cache: Pole node is not in the scene tree. Cannot execute modification!");
- pole_node_cache = node->get_instance_id();
-
- execution_error_found = false;
- }
- }
- }
-}
-
-void SkeletonModification3DTwoBoneIK::set_target_node(const NodePath &p_target_node) {
- target_node = p_target_node;
- update_cache_target();
-}
-
-NodePath SkeletonModification3DTwoBoneIK::get_target_node() const {
- return target_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_use_tip_node(const bool p_use_tip_node) {
- use_tip_node = p_use_tip_node;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DTwoBoneIK::get_use_tip_node() const {
- return use_tip_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_tip_node(const NodePath &p_tip_node) {
- tip_node = p_tip_node;
- update_cache_tip();
-}
-
-NodePath SkeletonModification3DTwoBoneIK::get_tip_node() const {
- return tip_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_use_pole_node(const bool p_use_pole_node) {
- use_pole_node = p_use_pole_node;
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DTwoBoneIK::get_use_pole_node() const {
- return use_pole_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_pole_node(const NodePath &p_pole_node) {
- pole_node = p_pole_node;
- update_cache_pole();
-}
-
-NodePath SkeletonModification3DTwoBoneIK::get_pole_node() const {
- return pole_node;
-}
-
-void SkeletonModification3DTwoBoneIK::set_auto_calculate_joint_length(bool p_calculate) {
- auto_calculate_joint_length = p_calculate;
- if (p_calculate) {
- calculate_joint_lengths();
- }
- notify_property_list_changed();
-}
-
-bool SkeletonModification3DTwoBoneIK::get_auto_calculate_joint_length() const {
- return auto_calculate_joint_length;
-}
-
-void SkeletonModification3DTwoBoneIK::calculate_joint_lengths() {
- if (!is_setup) {
- return; // fail silently, as we likely just loaded the scene.
- }
- ERR_FAIL_COND_MSG(!stack || stack->skeleton == nullptr,
- "Modification is not setup and therefore cannot calculate joint lengths!");
- ERR_FAIL_COND_MSG(joint_one_bone_idx <= -1 || joint_two_bone_idx <= -1,
- "One of the bones in the TwoBoneIK modification are not set! Cannot calculate joint lengths!");
-
- Transform3D bone_one_rest_trans = stack->skeleton->get_bone_global_pose(joint_one_bone_idx);
- Transform3D bone_two_rest_trans = stack->skeleton->get_bone_global_pose(joint_two_bone_idx);
-
- joint_one_length = bone_one_rest_trans.origin.distance_to(bone_two_rest_trans.origin);
-
- if (use_tip_node) {
- if (tip_node_cache.is_null()) {
- update_cache_tip();
- WARN_PRINT("Tip cache is out of date. Updating...");
- }
-
- Node3D *tip = Object::cast_to<Node3D>(ObjectDB::get_instance(tip_node_cache));
- if (tip) {
- Transform3D bone_tip_trans = stack->skeleton->world_transform_to_global_pose(tip->get_global_transform());
- joint_two_length = bone_two_rest_trans.origin.distance_to(bone_tip_trans.origin);
- }
- } else {
- // Attempt to use children bones to get the length
- Vector<int> bone_two_children = stack->skeleton->get_bone_children(joint_two_bone_idx);
- if (bone_two_children.size() > 0) {
- joint_two_length = 0;
- for (int i = 0; i < bone_two_children.size(); i++) {
- joint_two_length += bone_two_rest_trans.origin.distance_to(
- stack->skeleton->get_bone_global_pose(bone_two_children[i]).origin);
- }
- joint_two_length = joint_two_length / bone_two_children.size();
- } else {
- WARN_PRINT("TwoBoneIK modification: Cannot auto calculate length for joint 2! Auto setting the length to 1...");
- joint_two_length = 1.0;
- }
- }
- execution_error_found = false;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_one_bone_name(String p_bone_name) {
- joint_one_bone_name = p_bone_name;
- if (stack && stack->skeleton) {
- joint_one_bone_idx = stack->skeleton->find_bone(p_bone_name);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-String SkeletonModification3DTwoBoneIK::get_joint_one_bone_name() const {
- return joint_one_bone_name;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_one_bone_idx(int p_bone_idx) {
- joint_one_bone_idx = p_bone_idx;
- if (stack && stack->skeleton) {
- joint_one_bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DTwoBoneIK::get_joint_one_bone_idx() const {
- return joint_one_bone_idx;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_one_length(real_t p_length) {
- joint_one_length = p_length;
-}
-
-real_t SkeletonModification3DTwoBoneIK::get_joint_one_length() const {
- return joint_one_length;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_two_bone_name(String p_bone_name) {
- joint_two_bone_name = p_bone_name;
- if (stack && stack->skeleton) {
- joint_two_bone_idx = stack->skeleton->find_bone(p_bone_name);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-String SkeletonModification3DTwoBoneIK::get_joint_two_bone_name() const {
- return joint_two_bone_name;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_two_bone_idx(int p_bone_idx) {
- joint_two_bone_idx = p_bone_idx;
- if (stack && stack->skeleton) {
- joint_two_bone_name = stack->skeleton->get_bone_name(p_bone_idx);
- }
- execution_error_found = false;
- notify_property_list_changed();
-}
-
-int SkeletonModification3DTwoBoneIK::get_joint_two_bone_idx() const {
- return joint_two_bone_idx;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_two_length(real_t p_length) {
- joint_two_length = p_length;
-}
-
-real_t SkeletonModification3DTwoBoneIK::get_joint_two_length() const {
- return joint_two_length;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_one_roll(real_t p_roll) {
- joint_one_roll = p_roll;
-}
-
-real_t SkeletonModification3DTwoBoneIK::get_joint_one_roll() const {
- return joint_one_roll;
-}
-
-void SkeletonModification3DTwoBoneIK::set_joint_two_roll(real_t p_roll) {
- joint_two_roll = p_roll;
-}
-
-real_t SkeletonModification3DTwoBoneIK::get_joint_two_roll() const {
- return joint_two_roll;
-}
-
-void SkeletonModification3DTwoBoneIK::_bind_methods() {
- ClassDB::bind_method(D_METHOD("set_target_node", "target_nodepath"), &SkeletonModification3DTwoBoneIK::set_target_node);
- ClassDB::bind_method(D_METHOD("get_target_node"), &SkeletonModification3DTwoBoneIK::get_target_node);
-
- ClassDB::bind_method(D_METHOD("set_use_pole_node", "use_pole_node"), &SkeletonModification3DTwoBoneIK::set_use_pole_node);
- ClassDB::bind_method(D_METHOD("get_use_pole_node"), &SkeletonModification3DTwoBoneIK::get_use_pole_node);
- ClassDB::bind_method(D_METHOD("set_pole_node", "pole_nodepath"), &SkeletonModification3DTwoBoneIK::set_pole_node);
- ClassDB::bind_method(D_METHOD("get_pole_node"), &SkeletonModification3DTwoBoneIK::get_pole_node);
-
- ClassDB::bind_method(D_METHOD("set_use_tip_node", "use_tip_node"), &SkeletonModification3DTwoBoneIK::set_use_tip_node);
- ClassDB::bind_method(D_METHOD("get_use_tip_node"), &SkeletonModification3DTwoBoneIK::get_use_tip_node);
- ClassDB::bind_method(D_METHOD("set_tip_node", "tip_nodepath"), &SkeletonModification3DTwoBoneIK::set_tip_node);
- ClassDB::bind_method(D_METHOD("get_tip_node"), &SkeletonModification3DTwoBoneIK::get_tip_node);
-
- ClassDB::bind_method(D_METHOD("set_auto_calculate_joint_length", "auto_calculate_joint_length"), &SkeletonModification3DTwoBoneIK::set_auto_calculate_joint_length);
- ClassDB::bind_method(D_METHOD("get_auto_calculate_joint_length"), &SkeletonModification3DTwoBoneIK::get_auto_calculate_joint_length);
-
- ClassDB::bind_method(D_METHOD("set_joint_one_bone_name", "bone_name"), &SkeletonModification3DTwoBoneIK::set_joint_one_bone_name);
- ClassDB::bind_method(D_METHOD("get_joint_one_bone_name"), &SkeletonModification3DTwoBoneIK::get_joint_one_bone_name);
- ClassDB::bind_method(D_METHOD("set_joint_one_bone_idx", "bone_idx"), &SkeletonModification3DTwoBoneIK::set_joint_one_bone_idx);
- ClassDB::bind_method(D_METHOD("get_joint_one_bone_idx"), &SkeletonModification3DTwoBoneIK::get_joint_one_bone_idx);
- ClassDB::bind_method(D_METHOD("set_joint_one_length", "bone_length"), &SkeletonModification3DTwoBoneIK::set_joint_one_length);
- ClassDB::bind_method(D_METHOD("get_joint_one_length"), &SkeletonModification3DTwoBoneIK::get_joint_one_length);
-
- ClassDB::bind_method(D_METHOD("set_joint_two_bone_name", "bone_name"), &SkeletonModification3DTwoBoneIK::set_joint_two_bone_name);
- ClassDB::bind_method(D_METHOD("get_joint_two_bone_name"), &SkeletonModification3DTwoBoneIK::get_joint_two_bone_name);
- ClassDB::bind_method(D_METHOD("set_joint_two_bone_idx", "bone_idx"), &SkeletonModification3DTwoBoneIK::set_joint_two_bone_idx);
- ClassDB::bind_method(D_METHOD("get_joint_two_bone_idx"), &SkeletonModification3DTwoBoneIK::get_joint_two_bone_idx);
- ClassDB::bind_method(D_METHOD("set_joint_two_length", "bone_length"), &SkeletonModification3DTwoBoneIK::set_joint_two_length);
- ClassDB::bind_method(D_METHOD("get_joint_two_length"), &SkeletonModification3DTwoBoneIK::get_joint_two_length);
-
- ClassDB::bind_method(D_METHOD("set_joint_one_roll", "roll"), &SkeletonModification3DTwoBoneIK::set_joint_one_roll);
- ClassDB::bind_method(D_METHOD("get_joint_one_roll"), &SkeletonModification3DTwoBoneIK::get_joint_one_roll);
- ClassDB::bind_method(D_METHOD("set_joint_two_roll", "roll"), &SkeletonModification3DTwoBoneIK::set_joint_two_roll);
- ClassDB::bind_method(D_METHOD("get_joint_two_roll"), &SkeletonModification3DTwoBoneIK::get_joint_two_roll);
-
- ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "target_nodepath", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "Node3D"), "set_target_node", "get_target_node");
- ADD_GROUP("", "");
-}
-
-SkeletonModification3DTwoBoneIK::SkeletonModification3DTwoBoneIK() {
- stack = nullptr;
- is_setup = false;
-}
-
-SkeletonModification3DTwoBoneIK::~SkeletonModification3DTwoBoneIK() {
-}
diff --git a/scene/resources/skeleton_modification_3d_twoboneik.h b/scene/resources/skeleton_modification_3d_twoboneik.h
deleted file mode 100644
index 57481e0181..0000000000
--- a/scene/resources/skeleton_modification_3d_twoboneik.h
+++ /dev/null
@@ -1,118 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_3d_twoboneik.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 SKELETON_MODIFICATION_3D_TWOBONEIK_H
-#define SKELETON_MODIFICATION_3D_TWOBONEIK_H
-
-#include "scene/3d/skeleton_3d.h"
-#include "scene/resources/skeleton_modification_3d.h"
-
-class SkeletonModification3DTwoBoneIK : public SkeletonModification3D {
- GDCLASS(SkeletonModification3DTwoBoneIK, SkeletonModification3D);
-
-private:
- NodePath target_node;
- ObjectID target_node_cache;
-
- bool use_tip_node = false;
- NodePath tip_node;
- ObjectID tip_node_cache;
-
- bool use_pole_node = false;
- NodePath pole_node;
- ObjectID pole_node_cache;
-
- String joint_one_bone_name = "";
- int joint_one_bone_idx = -1;
- String joint_two_bone_name = "";
- int joint_two_bone_idx = -1;
-
- bool auto_calculate_joint_length = false;
- real_t joint_one_length = -1;
- real_t joint_two_length = -1;
-
- real_t joint_one_roll = 0;
- real_t joint_two_roll = 0;
-
- void update_cache_target();
- void update_cache_tip();
- void update_cache_pole();
-
-protected:
- static void _bind_methods();
- bool _get(const StringName &p_path, Variant &r_ret) const;
- bool _set(const StringName &p_path, const Variant &p_value);
- void _get_property_list(List<PropertyInfo> *p_list) const;
-
-public:
- virtual void _execute(real_t p_delta) override;
- virtual void _setup_modification(SkeletonModificationStack3D *p_stack) override;
-
- void set_target_node(const NodePath &p_target_node);
- NodePath get_target_node() const;
-
- void set_use_tip_node(const bool p_use_tip_node);
- bool get_use_tip_node() const;
- void set_tip_node(const NodePath &p_tip_node);
- NodePath get_tip_node() const;
-
- void set_use_pole_node(const bool p_use_pole_node);
- bool get_use_pole_node() const;
- void set_pole_node(const NodePath &p_pole_node);
- NodePath get_pole_node() const;
-
- void set_auto_calculate_joint_length(bool p_calculate);
- bool get_auto_calculate_joint_length() const;
- void calculate_joint_lengths();
-
- void set_joint_one_bone_name(String p_bone_name);
- String get_joint_one_bone_name() const;
- void set_joint_one_bone_idx(int p_bone_idx);
- int get_joint_one_bone_idx() const;
- void set_joint_one_length(real_t p_length);
- real_t get_joint_one_length() const;
-
- void set_joint_two_bone_name(String p_bone_name);
- String get_joint_two_bone_name() const;
- void set_joint_two_bone_idx(int p_bone_idx);
- int get_joint_two_bone_idx() const;
- void set_joint_two_length(real_t p_length);
- real_t get_joint_two_length() const;
-
- void set_joint_one_roll(real_t p_roll);
- real_t get_joint_one_roll() const;
- void set_joint_two_roll(real_t p_roll);
- real_t get_joint_two_roll() const;
-
- SkeletonModification3DTwoBoneIK();
- ~SkeletonModification3DTwoBoneIK();
-};
-
-#endif // SKELETON_MODIFICATION_3D_TWOBONEIK_H
diff --git a/scene/resources/skeleton_modification_stack_3d.cpp b/scene/resources/skeleton_modification_stack_3d.cpp
deleted file mode 100644
index 32708e198a..0000000000
--- a/scene/resources/skeleton_modification_stack_3d.cpp
+++ /dev/null
@@ -1,224 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_stack_3d.cpp */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 "skeleton_modification_stack_3d.h"
-#include "scene/3d/skeleton_3d.h"
-
-///////////////////////////////////////
-// ModificationStack3D
-///////////////////////////////////////
-
-void SkeletonModificationStack3D::_get_property_list(List<PropertyInfo> *p_list) const {
- for (uint32_t i = 0; i < modifications.size(); i++) {
- p_list->push_back(
- PropertyInfo(Variant::OBJECT, "modifications/" + itos(i),
- PROPERTY_HINT_RESOURCE_TYPE,
- "SkeletonModification3D",
- PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_DEFERRED_SET_RESOURCE | PROPERTY_USAGE_DO_NOT_SHARE_ON_DUPLICATE));
- }
-}
-
-bool SkeletonModificationStack3D::_set(const StringName &p_path, const Variant &p_value) {
- String path = p_path;
-
- if (path.begins_with("modifications/")) {
- int mod_idx = path.get_slicec('/', 1).to_int();
- set_modification(mod_idx, p_value);
- return true;
- }
- return true;
-}
-
-bool SkeletonModificationStack3D::_get(const StringName &p_path, Variant &r_ret) const {
- String path = p_path;
-
- if (path.begins_with("modifications/")) {
- int mod_idx = path.get_slicec('/', 1).to_int();
- r_ret = get_modification(mod_idx);
- return true;
- }
- return true;
-}
-
-void SkeletonModificationStack3D::setup() {
- if (is_setup) {
- return;
- }
-
- if (skeleton != nullptr) {
- is_setup = true;
- for (uint32_t i = 0; i < modifications.size(); i++) {
- if (!modifications[i].is_valid()) {
- continue;
- }
- modifications[i]->_setup_modification(this);
- }
- } else {
- WARN_PRINT("Cannot setup SkeletonModificationStack3D: no skeleton set!");
- }
-}
-
-void SkeletonModificationStack3D::execute(real_t p_delta, int p_execution_mode) {
- ERR_FAIL_COND_MSG(!is_setup || skeleton == nullptr || is_queued_for_deletion(),
- "Modification stack is not properly setup and therefore cannot execute!");
-
- if (!skeleton->is_inside_tree()) {
- ERR_PRINT_ONCE("Skeleton is not inside SceneTree! Cannot execute modification!");
- return;
- }
-
- if (!enabled) {
- return;
- }
-
- for (uint32_t i = 0; i < modifications.size(); i++) {
- if (!modifications[i].is_valid()) {
- continue;
- }
-
- if (modifications[i]->get_execution_mode() == p_execution_mode) {
- modifications[i]->_execute(p_delta);
- }
- }
-}
-
-void SkeletonModificationStack3D::enable_all_modifications(bool p_enabled) {
- for (uint32_t i = 0; i < modifications.size(); i++) {
- if (!modifications[i].is_valid()) {
- continue;
- }
- modifications[i]->set_enabled(p_enabled);
- }
-}
-
-Ref<SkeletonModification3D> SkeletonModificationStack3D::get_modification(int p_mod_idx) const {
- const int modifications_size = modifications.size();
- ERR_FAIL_INDEX_V(p_mod_idx, modifications_size, nullptr);
- return modifications[p_mod_idx];
-}
-
-void SkeletonModificationStack3D::add_modification(Ref<SkeletonModification3D> p_mod) {
- ERR_FAIL_NULL(p_mod);
- p_mod->_setup_modification(this);
- modifications.push_back(p_mod);
-}
-
-void SkeletonModificationStack3D::delete_modification(int p_mod_idx) {
- const int modifications_size = modifications.size();
- ERR_FAIL_INDEX(p_mod_idx, modifications_size);
- modifications.remove_at(p_mod_idx);
-}
-
-void SkeletonModificationStack3D::set_modification(int p_mod_idx, Ref<SkeletonModification3D> p_mod) {
- const int modifications_size = modifications.size();
- ERR_FAIL_INDEX(p_mod_idx, modifications_size);
-
- if (p_mod == nullptr) {
- modifications.remove_at(p_mod_idx);
- } else {
- p_mod->_setup_modification(this);
- modifications[p_mod_idx] = p_mod;
- }
-}
-
-void SkeletonModificationStack3D::set_modification_count(int p_count) {
- ERR_FAIL_COND_MSG(p_count < 0, "Modification count cannot be less than zero.");
- modifications.resize(p_count);
- notify_property_list_changed();
-}
-
-int SkeletonModificationStack3D::get_modification_count() const {
- return modifications.size();
-}
-
-void SkeletonModificationStack3D::set_skeleton(Skeleton3D *p_skeleton) {
- skeleton = p_skeleton;
-}
-
-Skeleton3D *SkeletonModificationStack3D::get_skeleton() const {
- return skeleton;
-}
-
-bool SkeletonModificationStack3D::get_is_setup() const {
- return is_setup;
-}
-
-void SkeletonModificationStack3D::set_enabled(bool p_enabled) {
- enabled = p_enabled;
-
- if (!enabled && is_setup && skeleton != nullptr) {
- skeleton->clear_bones_local_pose_override();
- }
-}
-
-bool SkeletonModificationStack3D::get_enabled() const {
- return enabled;
-}
-
-void SkeletonModificationStack3D::set_strength(real_t p_strength) {
- ERR_FAIL_COND_MSG(p_strength < 0, "Strength cannot be less than zero!");
- ERR_FAIL_COND_MSG(p_strength > 1, "Strength cannot be more than one!");
- strength = p_strength;
-}
-
-real_t SkeletonModificationStack3D::get_strength() const {
- return strength;
-}
-
-void SkeletonModificationStack3D::_bind_methods() {
- ClassDB::bind_method(D_METHOD("setup"), &SkeletonModificationStack3D::setup);
- ClassDB::bind_method(D_METHOD("execute", "delta", "execution_mode"), &SkeletonModificationStack3D::execute);
-
- ClassDB::bind_method(D_METHOD("enable_all_modifications", "enabled"), &SkeletonModificationStack3D::enable_all_modifications);
- ClassDB::bind_method(D_METHOD("get_modification", "mod_idx"), &SkeletonModificationStack3D::get_modification);
- ClassDB::bind_method(D_METHOD("add_modification", "modification"), &SkeletonModificationStack3D::add_modification);
- ClassDB::bind_method(D_METHOD("delete_modification", "mod_idx"), &SkeletonModificationStack3D::delete_modification);
- ClassDB::bind_method(D_METHOD("set_modification", "mod_idx", "modification"), &SkeletonModificationStack3D::set_modification);
-
- ClassDB::bind_method(D_METHOD("set_modification_count", "count"), &SkeletonModificationStack3D::set_modification_count);
- ClassDB::bind_method(D_METHOD("get_modification_count"), &SkeletonModificationStack3D::get_modification_count);
-
- ClassDB::bind_method(D_METHOD("get_is_setup"), &SkeletonModificationStack3D::get_is_setup);
-
- ClassDB::bind_method(D_METHOD("set_enabled", "enabled"), &SkeletonModificationStack3D::set_enabled);
- ClassDB::bind_method(D_METHOD("get_enabled"), &SkeletonModificationStack3D::get_enabled);
-
- ClassDB::bind_method(D_METHOD("set_strength", "strength"), &SkeletonModificationStack3D::set_strength);
- ClassDB::bind_method(D_METHOD("get_strength"), &SkeletonModificationStack3D::get_strength);
-
- ClassDB::bind_method(D_METHOD("get_skeleton"), &SkeletonModificationStack3D::get_skeleton);
-
- ADD_PROPERTY(PropertyInfo(Variant::BOOL, "enabled"), "set_enabled", "get_enabled");
- ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "strength", PROPERTY_HINT_RANGE, "0, 1, 0.001"), "set_strength", "get_strength");
- ADD_PROPERTY(PropertyInfo(Variant::INT, "modification_count", PROPERTY_HINT_RANGE, "0, 100, 1", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_ARRAY, "Modifications,modifications/"), "set_modification_count", "get_modification_count");
-}
-
-SkeletonModificationStack3D::SkeletonModificationStack3D() {
-}
diff --git a/scene/resources/skeleton_modification_stack_3d.h b/scene/resources/skeleton_modification_stack_3d.h
deleted file mode 100644
index fd490c49e9..0000000000
--- a/scene/resources/skeleton_modification_stack_3d.h
+++ /dev/null
@@ -1,91 +0,0 @@
-/**************************************************************************/
-/* skeleton_modification_stack_3d.h */
-/**************************************************************************/
-/* This file is part of: */
-/* GODOT ENGINE */
-/* https://godotengine.org */
-/**************************************************************************/
-/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
-/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
-/* */
-/* 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 SKELETON_MODIFICATION_STACK_3D_H
-#define SKELETON_MODIFICATION_STACK_3D_H
-
-#include "core/templates/local_vector.h"
-#include "scene/3d/skeleton_3d.h"
-
-class Skeleton3D;
-class SkeletonModification3D;
-
-class SkeletonModificationStack3D : public Resource {
- GDCLASS(SkeletonModificationStack3D, Resource);
- friend class Skeleton3D;
- friend class SkeletonModification3D;
-
-protected:
- static void _bind_methods();
- virtual void _get_property_list(List<PropertyInfo> *p_list) const;
- virtual bool _set(const StringName &p_path, const Variant &p_value);
- virtual bool _get(const StringName &p_path, Variant &r_ret) const;
-
-public:
- Skeleton3D *skeleton = nullptr;
- bool is_setup = false;
- bool enabled = false;
- real_t strength = 1.0;
-
- enum EXECUTION_MODE {
- execution_mode_process,
- execution_mode_physics_process,
- };
-
- LocalVector<Ref<SkeletonModification3D>> modifications = LocalVector<Ref<SkeletonModification3D>>();
- int modifications_count = 0;
-
- virtual void setup();
- virtual void execute(real_t p_delta, int p_execution_mode);
-
- void enable_all_modifications(bool p_enable);
- Ref<SkeletonModification3D> get_modification(int p_mod_idx) const;
- void add_modification(Ref<SkeletonModification3D> p_mod);
- void delete_modification(int p_mod_idx);
- void set_modification(int p_mod_idx, Ref<SkeletonModification3D> p_mod);
-
- void set_modification_count(int p_count);
- int get_modification_count() const;
-
- void set_skeleton(Skeleton3D *p_skeleton);
- Skeleton3D *get_skeleton() const;
-
- bool get_is_setup() const;
-
- void set_enabled(bool p_enabled);
- bool get_enabled() const;
-
- void set_strength(real_t p_strength);
- real_t get_strength() const;
-
- SkeletonModificationStack3D();
-};
-
-#endif // SKELETON_MODIFICATION_STACK_3D_H
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index 4043b73b71..94e78fc3aa 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -473,6 +473,7 @@ void TileSet::_compute_next_source_id() {
int TileSet::add_source(Ref<TileSetSource> p_tile_set_source, int p_atlas_source_id_override) {
ERR_FAIL_COND_V(!p_tile_set_source.is_valid(), TileSet::INVALID_SOURCE);
ERR_FAIL_COND_V_MSG(p_atlas_source_id_override >= 0 && (sources.has(p_atlas_source_id_override)), TileSet::INVALID_SOURCE, vformat("Cannot create TileSet atlas source. Another atlas source exists with id %d.", p_atlas_source_id_override));
+ ERR_FAIL_COND_V_MSG(p_atlas_source_id_override < 0 && p_atlas_source_id_override != TileSet::INVALID_SOURCE, TileSet::INVALID_SOURCE, vformat("Provided source ID %d is not valid. Negative source IDs are not allowed.", p_atlas_source_id_override));
int new_source_id = p_atlas_source_id_override >= 0 ? p_atlas_source_id_override : next_source_id;
sources[new_source_id] = p_tile_set_source;
diff --git a/scene/resources/visual_shader.cpp b/scene/resources/visual_shader.cpp
index 4c99563a91..1cbeaae428 100644
--- a/scene/resources/visual_shader.cpp
+++ b/scene/resources/visual_shader.cpp
@@ -399,7 +399,6 @@ void VisualShaderNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "output_port_for_preview"), "set_output_port_for_preview", "get_output_port_for_preview");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "default_input_values", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "set_default_input_values", "get_default_input_values");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "expanded_output_ports", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL), "_set_output_ports_expanded", "_get_output_ports_expanded");
- ADD_SIGNAL(MethodInfo("editor_refresh_request"));
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR);
BIND_ENUM_CONSTANT(PORT_TYPE_SCALAR_INT);
@@ -2734,9 +2733,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "viewport_size", "VIEWPORT_SIZE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "output_is_srgb", "OUTPUT_IS_SRGB" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "front_facing", "FRONT_FACING" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_roughness_texture", "NORMAL_ROUGHNESS_TEXTURE" },
- { Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "depth_texture", "DEPTH_TEXTURE" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_index", "VIEW_INDEX" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_mono_left", "VIEW_MONO_LEFT" },
{ Shader::MODE_SPATIAL, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SCALAR_INT, "view_right", "VIEW_RIGHT" },
@@ -2799,7 +2795,6 @@ const VisualShaderNodeInput::Port VisualShaderNodeInput::ports[] = {
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_BOOLEAN, "at_light_pass", "AT_LIGHT_PASS" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "texture", "TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "normal_texture", "NORMAL_TEXTURE" },
- { Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "screen_texture", "SCREEN_TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_4D, "specular_shininess", "SPECULAR_SHININESS" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_SAMPLER, "specular_shininess_texture", "SPECULAR_SHININESS_TEXTURE" },
{ Shader::MODE_CANVAS_ITEM, VisualShader::TYPE_FRAGMENT, VisualShaderNode::PORT_TYPE_VECTOR_2D, "vertex", "VERTEX" },
diff --git a/scene/resources/visual_shader_nodes.cpp b/scene/resources/visual_shader_nodes.cpp
index 432d5a5b59..e78d9b924d 100644
--- a/scene/resources/visual_shader_nodes.cpp
+++ b/scene/resources/visual_shader_nodes.cpp
@@ -756,141 +756,157 @@ Vector<VisualShader::DefaultTextureParam> VisualShaderNodeTexture::get_default_t
}
String VisualShaderNodeTexture::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
- if (source == SOURCE_TEXTURE) {
- String u = "uniform sampler2D " + make_unique_id(p_type, p_id, "tex");
- switch (texture_type) {
- case TYPE_DATA:
- break;
- case TYPE_COLOR:
- u += " : source_color";
- break;
- case TYPE_NORMAL_MAP:
- u += " : hint_normal";
- break;
- default:
- break;
- }
- return u + ";\n";
+ String code;
+
+ switch (source) {
+ case SOURCE_TEXTURE: {
+ code += "uniform sampler2D " + make_unique_id(p_type, p_id, "tex");
+ switch (texture_type) {
+ case TYPE_DATA: {
+ } break;
+ case TYPE_COLOR: {
+ code += " : source_color";
+ } break;
+ case TYPE_NORMAL_MAP: {
+ code += " : hint_normal";
+ } break;
+ default: {
+ } break;
+ }
+ code += ";\n";
+ } break;
+ case SOURCE_SCREEN: {
+ if ((p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
+ code += "uniform sampler2D " + make_unique_id(p_type, p_id, "screen_tex") + " : hint_screen_texture;\n";
+ }
+ } break;
+ case SOURCE_DEPTH:
+ case SOURCE_3D_NORMAL:
+ case SOURCE_ROUGHNESS: {
+ if (p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
+ String sampler_name = "";
+ String hint = " : ";
+ if (source == SOURCE_DEPTH) {
+ sampler_name = "depth_tex";
+ hint += "hint_depth_texture;\n";
+ } else {
+ sampler_name = source == SOURCE_ROUGHNESS ? "roughness_tex" : "normal_roughness_tex";
+ hint += "hint_normal_roughness_texture;\n";
+ }
+ code += "uniform sampler2D " + make_unique_id(p_type, p_id, sampler_name) + hint;
+ }
+ } break;
+ default: {
+ } break;
}
- return String();
+ return code;
}
String VisualShaderNodeTexture::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 {
String default_uv;
if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
- default_uv = "UV";
+ if (source == SOURCE_SCREEN) {
+ default_uv = "SCREEN_UV";
+ } else {
+ default_uv = "UV";
+ }
} else {
default_uv = "vec2(0.0)";
}
String code;
- if (source == SOURCE_TEXTURE) {
- String id = make_unique_id(p_type, p_id, "tex");
- if (p_input_vars[0].is_empty()) { // Use UV by default.
+ String uv = p_input_vars[0].is_empty() ? default_uv : p_input_vars[0];
+
+ switch (source) {
+ case SOURCE_PORT:
+ case SOURCE_TEXTURE: {
+ String id;
+ if (source == SOURCE_PORT) {
+ id = p_input_vars[2];
+ if (id.is_empty()) {
+ break;
+ }
+ } else { // SOURCE_TEXTURE
+ id = make_unique_id(p_type, p_id, "tex");
+ }
if (p_input_vars[1].is_empty()) {
- code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n";
} else {
- code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n";
}
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
- }
- return code;
- }
-
- if (source == SOURCE_PORT) {
- String id = p_input_vars[2];
- if (id.is_empty()) {
- code += " " + p_output_vars[0] + " = vec4(0.0);\n";
- } else {
- if (p_input_vars[0].is_empty()) { // Use UV by default.
+ return code;
+ } break;
+ case SOURCE_SCREEN: {
+ if ((p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
+ String id = make_unique_id(p_type, p_id, "screen_tex");
if (p_input_vars[1].is_empty()) {
- code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n";
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n";
} else {
- code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n";
}
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
- }
- }
- return code;
- }
-
- if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
- if (p_input_vars[0].is_empty() || p_for_preview) { // Use UV by default.
- if (p_input_vars[1].is_empty()) {
- code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + default_uv + ", 0.0);\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
+ return code;
}
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", 0.0);\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(SCREEN_TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
- }
- return code;
- }
+ } break;
+ case SOURCE_2D_NORMAL:
+ case SOURCE_2D_TEXTURE: {
+ if (p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
+ String id = source == SOURCE_2D_TEXTURE ? "TEXTURE" : "NORMAL_TEXTURE";
- if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
- if (p_input_vars[0].is_empty()) { // Use UV by default.
- if (p_input_vars[1].is_empty()) {
- code += " " + p_output_vars[0] + " = texture(TEXTURE, " + default_uv + ");\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
+ if (p_input_vars[1].is_empty()) {
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n";
+ } else {
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n";
+ }
+ return code;
}
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " " + p_output_vars[0] + " = texture(TEXTURE, " + p_input_vars[0] + ");\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(TEXTURE, " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
- }
- return code;
- }
+ } break;
+ case SOURCE_3D_NORMAL:
+ case SOURCE_ROUGHNESS:
+ case SOURCE_DEPTH: {
+ if (!p_for_preview && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
+ String var_name = "";
+ String sampler_name = "";
+
+ switch (source) {
+ case SOURCE_DEPTH: {
+ var_name = "_depth";
+ sampler_name = "depth_tex";
+ } break;
+ case SOURCE_ROUGHNESS: {
+ var_name = "_roughness";
+ sampler_name = "roughness_tex";
+ } break;
+ case SOURCE_3D_NORMAL: {
+ var_name = "_normal";
+ sampler_name = "normal_roughness_tex";
+ } break;
+ default: {
+ } break;
+ }
- if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
- if (p_input_vars[0].is_empty()) { // Use UV by default.
- if (p_input_vars[1].is_empty()) {
- code += " " + p_output_vars[0] + " = texture(NORMAL_TEXTURE, " + default_uv + ");\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(NORMAL_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ");\n";
- }
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " " + p_output_vars[0] + " = texture(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy);\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(NORMAL_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ");\n";
- }
- return code;
- }
+ String id = make_unique_id(p_type, p_id, sampler_name);
+ String type = source == SOURCE_3D_NORMAL ? "vec3" : "float";
+ String components = source == SOURCE_3D_NORMAL ? "rgb" : "r";
- if (source == SOURCE_DEPTH) {
- if (!p_for_preview && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
- code += " {\n";
- if (p_input_vars[0].is_empty()) { // Use UV by default.
+ code += " {\n";
if (p_input_vars[1].is_empty()) {
- code += " float _depth = texture(DEPTH_TEXTURE, " + default_uv + ").r;\n";
+ code += " " + type + " " + var_name + " = texture(" + id + ", " + uv + ")." + components + ";\n";
} else {
- code += " float _depth = textureLod(DEPTH_TEXTURE, " + default_uv + ", " + p_input_vars[1] + ").r;\n";
+ code += " " + type + " " + var_name + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ")." + components + ";\n";
}
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " float _depth = texture(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy).r;\n";
- } else {
- code += " float _depth = textureLod(DEPTH_TEXTURE, " + p_input_vars[0] + ".xy, " + p_input_vars[1] + ").r;\n";
- }
+ if (source == SOURCE_3D_NORMAL) {
+ code += " " + p_output_vars[0] + " = vec4(" + var_name + ", 1.0);\n";
+ } else {
+ code += " " + p_output_vars[0] + " = vec4(" + var_name + ", " + var_name + ", " + var_name + ", 1.0);\n";
+ }
+ code += " }\n";
- code += " " + p_output_vars[0] + " = vec4(_depth, _depth, _depth, 1.0);\n";
- code += " }\n";
- return code;
- }
+ return code;
+ }
+ } break;
+ default: {
+ } break;
}
code += " " + p_output_vars[0] + " = vec4(0.0);\n";
@@ -921,12 +937,17 @@ void VisualShaderNodeTexture::set_source(Source p_source) {
case SOURCE_PORT:
simple_decl = false;
break;
+ case SOURCE_3D_NORMAL:
+ simple_decl = false;
+ break;
+ case SOURCE_ROUGHNESS:
+ simple_decl = false;
+ break;
default:
break;
}
source = p_source;
emit_changed();
- emit_signal(SNAME("editor_refresh_request"));
}
VisualShaderNodeTexture::Source VisualShaderNodeTexture::get_source() const {
@@ -970,31 +991,34 @@ String VisualShaderNodeTexture::get_warning(Shader::Mode p_mode, VisualShader::T
return RTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'.");
}
- if (source == SOURCE_TEXTURE) {
- return String(); // all good
- }
-
- if (source == SOURCE_PORT) {
- return String(); // all good
- }
-
- if (source == SOURCE_SCREEN && (p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
- return String(); // all good
- }
-
- if (source == SOURCE_2D_TEXTURE && p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
- return String(); // all good
- }
-
- if (source == SOURCE_2D_NORMAL && p_mode == Shader::MODE_CANVAS_ITEM) {
- return String(); // all good
- }
-
- if (source == SOURCE_DEPTH && p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
- if (get_output_port_for_preview() == 0) { // DEPTH_TEXTURE is not supported in preview(canvas_item) shader
- return RTR("Invalid source for preview.");
- }
- return String(); // all good
+ switch (source) {
+ case SOURCE_TEXTURE:
+ case SOURCE_PORT: {
+ return String(); // All good.
+ } break;
+ case SOURCE_SCREEN: {
+ if ((p_mode == Shader::MODE_SPATIAL || p_mode == Shader::MODE_CANVAS_ITEM) && p_type == VisualShader::TYPE_FRAGMENT) {
+ return String(); // All good.
+ }
+ } break;
+ case SOURCE_2D_NORMAL:
+ case SOURCE_2D_TEXTURE: {
+ if (p_mode == Shader::MODE_CANVAS_ITEM && p_type == VisualShader::TYPE_FRAGMENT) {
+ return String(); // All good.
+ }
+ } break;
+ case SOURCE_3D_NORMAL:
+ case SOURCE_ROUGHNESS:
+ case SOURCE_DEPTH: {
+ if (p_mode == Shader::MODE_SPATIAL && p_type == VisualShader::TYPE_FRAGMENT) {
+ if (get_output_port_for_preview() == 0) { // Not supported in preview(canvas_item) shader.
+ return RTR("Invalid source for preview.");
+ }
+ return String(); // All good.
+ }
+ } break;
+ default: {
+ } break;
}
return RTR("Invalid source for shader.");
@@ -1010,7 +1034,7 @@ void VisualShaderNodeTexture::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_type", "value"), &VisualShaderNodeTexture::set_texture_type);
ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTexture::get_texture_type);
- ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort"), "set_source", "get_source");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "source", PROPERTY_HINT_ENUM, "Texture,Screen,Texture2D,NormalMap2D,Depth,SamplerPort,Normal3D,Roughness"), "set_source", "get_source");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "texture", PROPERTY_HINT_RESOURCE_TYPE, "Texture2D"), "set_texture", "get_texture");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map"), "set_texture_type", "get_texture_type");
@@ -1020,6 +1044,8 @@ void VisualShaderNodeTexture::_bind_methods() {
BIND_ENUM_CONSTANT(SOURCE_2D_NORMAL);
BIND_ENUM_CONSTANT(SOURCE_DEPTH);
BIND_ENUM_CONSTANT(SOURCE_PORT);
+ BIND_ENUM_CONSTANT(SOURCE_3D_NORMAL);
+ BIND_ENUM_CONSTANT(SOURCE_ROUGHNESS);
BIND_ENUM_CONSTANT(SOURCE_MAX);
BIND_ENUM_CONSTANT(TYPE_DATA);
@@ -1260,6 +1286,17 @@ bool VisualShaderNodeSample3D::is_input_port_default(int p_port, Shader::Mode p_
}
String VisualShaderNodeSample3D::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 {
+ String code;
+ String id;
+ if (source == SOURCE_TEXTURE) {
+ id = make_unique_id(p_type, p_id, "tex3d");
+ } else { // SOURCE_PORT
+ id = p_input_vars[2];
+ if (id.is_empty()) {
+ code += " " + p_output_vars[0] + " = vec4(0.0);\n";
+ return code;
+ }
+ }
String default_uv;
if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
default_uv = "vec3(UV, 0.0)";
@@ -1267,33 +1304,12 @@ String VisualShaderNodeSample3D::generate_code(Shader::Mode p_mode, VisualShader
default_uv = "vec3(0.0)";
}
- String code;
- if (source == SOURCE_TEXTURE || source == SOURCE_PORT) {
- String id;
- if (source == SOURCE_TEXTURE) {
- id = make_unique_id(p_type, p_id, "tex3d");
- } else {
- id = p_input_vars[2];
- }
- if (!id.is_empty()) {
- if (p_input_vars[0].is_empty()) { // Use UV by default.
- if (p_input_vars[1].is_empty()) {
- code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
- }
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
- }
- } else {
- code += " " + p_output_vars[0] + " = vec4(0.0);\n";
- }
- return code;
+ String uv = p_input_vars[0].is_empty() ? default_uv : p_input_vars[0];
+ if (p_input_vars[1].is_empty()) {
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n";
+ } else {
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n";
}
- code += " " + p_output_vars[0] + " = vec4(0.0);\n";
return code;
}
@@ -1304,7 +1320,6 @@ void VisualShaderNodeSample3D::set_source(Source p_source) {
}
source = p_source;
emit_changed();
- emit_signal(SNAME("editor_refresh_request"));
}
VisualShaderNodeSample3D::Source VisualShaderNodeSample3D::get_source() const {
@@ -1326,14 +1341,7 @@ String VisualShaderNodeSample3D::get_warning(Shader::Mode p_mode, VisualShader::
if (is_input_port_connected(2) && source != SOURCE_PORT) {
return RTR("The sampler port is connected but not used. Consider changing the source to 'SamplerPort'.");
}
-
- if (source == SOURCE_TEXTURE) {
- return String(); // all good
- }
- if (source == SOURCE_PORT) {
- return String(); // all good
- }
- return RTR("Invalid source for shader.");
+ return String();
}
VisualShaderNodeSample3D::VisualShaderNodeSample3D() {
@@ -1539,42 +1547,33 @@ String VisualShaderNodeCubemap::generate_global(Shader::Mode p_mode, VisualShade
}
String VisualShaderNodeCubemap::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 {
- String default_uv;
- if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
- default_uv = "vec3(UV, 0.0)";
- } else {
- default_uv = "vec3(0.0)";
- }
-
String code;
String id;
+
if (source == SOURCE_TEXTURE) {
id = make_unique_id(p_type, p_id, "cube");
- } else if (source == SOURCE_PORT) {
+ } else { // SOURCE_PORT
id = p_input_vars[2];
- } else {
- return code;
+ if (id.is_empty()) {
+ code += " " + p_output_vars[0] + " = vec4(0.0);\n";
+ return code;
+ }
}
- if (id.is_empty()) {
- code += " " + p_output_vars[0] + " = vec4(0.0);\n";
- return code;
+ String default_uv;
+ if (p_mode == Shader::MODE_CANVAS_ITEM || p_mode == Shader::MODE_SPATIAL) {
+ default_uv = "vec3(UV, 0.0)";
+ } else {
+ default_uv = "vec3(0.0)";
}
- if (p_input_vars[0].is_empty()) { // Use UV by default.
-
- if (p_input_vars[1].is_empty()) {
- code += " " + p_output_vars[0] + " = texture(" + id + ", " + default_uv + ");\n";
- } else {
- code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + default_uv + ", " + p_input_vars[1] + ");\n";
- }
-
- } else if (p_input_vars[1].is_empty()) {
- //no lod
- code += " " + p_output_vars[0] + " = texture(" + id + ", " + p_input_vars[0] + ");\n";
+ String uv = p_input_vars[0].is_empty() ? default_uv : p_input_vars[0];
+ if (p_input_vars[1].is_empty()) {
+ code += " " + p_output_vars[0] + " = texture(" + id + ", " + uv + ");\n";
} else {
- code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + p_input_vars[0] + ", " + p_input_vars[1] + ");\n";
+ code += " " + p_output_vars[0] + " = textureLod(" + id + ", " + uv + ", " + p_input_vars[1] + ");\n";
}
+
return code;
}
@@ -1594,7 +1593,6 @@ void VisualShaderNodeCubemap::set_source(Source p_source) {
}
source = p_source;
emit_changed();
- emit_signal(SNAME("editor_refresh_request"));
}
VisualShaderNodeCubemap::Source VisualShaderNodeCubemap::get_source() const {
@@ -1702,11 +1700,15 @@ bool VisualShaderNodeLinearSceneDepth::has_output_port_preview(int p_port) const
return false;
}
+String VisualShaderNodeLinearSceneDepth::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "depth_tex") + " : hint_depth_texture;\n";
+}
+
String VisualShaderNodeLinearSceneDepth::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 {
String code;
code += " {\n";
- code += " float __log_depth = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).x;\n";
+ code += " float __log_depth = textureLod(" + make_unique_id(p_type, p_id, "depth_tex") + ", SCREEN_UV, 0.0).x;\n";
code += " vec3 __depth_ndc = vec3(SCREEN_UV * 2.0 - 1.0, __log_depth);\n";
code += " vec4 __depth_view = INV_PROJECTION_MATRIX * vec4(__depth_ndc, 1.0);\n";
code += " __depth_view.xyz /= __depth_view.w;\n";
@@ -6101,7 +6103,7 @@ VisualShaderNodeTransformParameter::VisualShaderNodeTransformParameter() {
//////////////
-String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat) {
+String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_type, VisualShaderNodeTextureParameter::ColorDefault p_color_default, VisualShaderNodeTextureParameter::TextureFilter p_texture_filter, VisualShaderNodeTextureParameter::TextureRepeat p_texture_repeat, VisualShaderNodeTextureParameter::TextureSource p_texture_source) {
String code;
bool has_colon = false;
@@ -6204,6 +6206,33 @@ String get_sampler_hint(VisualShaderNodeTextureParameter::TextureType p_texture_
}
}
+ {
+ String source_code;
+
+ switch (p_texture_source) {
+ case VisualShaderNodeTextureParameter::SOURCE_SCREEN:
+ source_code = "hint_screen_texture";
+ break;
+ case VisualShaderNodeTextureParameter::SOURCE_DEPTH:
+ source_code = "hint_depth_texture";
+ break;
+ case VisualShaderNodeTextureParameter::SOURCE_NORMAL_ROUGHNESS:
+ source_code = "hint_normal_roughness_texture";
+ break;
+ default:
+ break;
+ }
+
+ if (!source_code.is_empty()) {
+ if (!has_colon) {
+ code += " : ";
+ } else {
+ code += ", ";
+ }
+ code += source_code;
+ }
+ }
+
return code;
}
@@ -6290,6 +6319,19 @@ VisualShaderNodeTextureParameter::TextureRepeat VisualShaderNodeTextureParameter
return texture_repeat;
}
+void VisualShaderNodeTextureParameter::set_texture_source(TextureSource p_source) {
+ ERR_FAIL_INDEX(int(p_source), int(SOURCE_MAX));
+ if (texture_source == p_source) {
+ return;
+ }
+ texture_source = p_source;
+ emit_changed();
+}
+
+VisualShaderNodeTextureParameter::TextureSource VisualShaderNodeTextureParameter::get_texture_source() const {
+ return texture_source;
+}
+
Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() const {
Vector<StringName> props = VisualShaderNodeParameter::get_editable_properties();
props.push_back("texture_type");
@@ -6298,6 +6340,7 @@ Vector<StringName> VisualShaderNodeTextureParameter::get_editable_properties() c
}
props.push_back("texture_filter");
props.push_back("texture_repeat");
+ props.push_back("texture_source");
return props;
}
@@ -6311,6 +6354,7 @@ HashMap<StringName, String> VisualShaderNodeTextureParameter::get_editable_prope
names.insert("color_default", RTR("Default Color"));
names.insert("texture_filter", RTR("Filter"));
names.insert("texture_repeat", RTR("Repeat"));
+ names.insert("texture_source", RTR("Source"));
return names;
}
@@ -6318,19 +6362,23 @@ void VisualShaderNodeTextureParameter::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_texture_type", "type"), &VisualShaderNodeTextureParameter::set_texture_type);
ClassDB::bind_method(D_METHOD("get_texture_type"), &VisualShaderNodeTextureParameter::get_texture_type);
- ClassDB::bind_method(D_METHOD("set_color_default", "type"), &VisualShaderNodeTextureParameter::set_color_default);
+ ClassDB::bind_method(D_METHOD("set_color_default", "color"), &VisualShaderNodeTextureParameter::set_color_default);
ClassDB::bind_method(D_METHOD("get_color_default"), &VisualShaderNodeTextureParameter::get_color_default);
ClassDB::bind_method(D_METHOD("set_texture_filter", "filter"), &VisualShaderNodeTextureParameter::set_texture_filter);
ClassDB::bind_method(D_METHOD("get_texture_filter"), &VisualShaderNodeTextureParameter::get_texture_filter);
- ClassDB::bind_method(D_METHOD("set_texture_repeat", "type"), &VisualShaderNodeTextureParameter::set_texture_repeat);
+ ClassDB::bind_method(D_METHOD("set_texture_repeat", "repeat"), &VisualShaderNodeTextureParameter::set_texture_repeat);
ClassDB::bind_method(D_METHOD("get_texture_repeat"), &VisualShaderNodeTextureParameter::get_texture_repeat);
+ ClassDB::bind_method(D_METHOD("set_texture_source", "source"), &VisualShaderNodeTextureParameter::set_texture_source);
+ ClassDB::bind_method(D_METHOD("get_texture_source"), &VisualShaderNodeTextureParameter::get_texture_source);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_type", PROPERTY_HINT_ENUM, "Data,Color,Normal Map,Anisotropic"), "set_texture_type", "get_texture_type");
ADD_PROPERTY(PropertyInfo(Variant::INT, "color_default", PROPERTY_HINT_ENUM, "White,Black,Transparent"), "set_color_default", "get_color_default");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_filter", PROPERTY_HINT_ENUM, "Default,Nearest,Linear,Nearest Mipmap,Linear Mipmap,Nearest Mipmap Anisotropic,Linear Mipmap Anisotropic"), "set_texture_filter", "get_texture_filter");
ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_repeat", PROPERTY_HINT_ENUM, "Default,Enabled,Disabled"), "set_texture_repeat", "get_texture_repeat");
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "texture_source", PROPERTY_HINT_ENUM, "None,Screen,Depth,NormalRoughness"), "set_texture_source", "get_texture_source");
BIND_ENUM_CONSTANT(TYPE_DATA);
BIND_ENUM_CONSTANT(TYPE_COLOR);
@@ -6356,6 +6404,12 @@ void VisualShaderNodeTextureParameter::_bind_methods() {
BIND_ENUM_CONSTANT(REPEAT_ENABLED);
BIND_ENUM_CONSTANT(REPEAT_DISABLED);
BIND_ENUM_CONSTANT(REPEAT_MAX);
+
+ BIND_ENUM_CONSTANT(SOURCE_NONE);
+ BIND_ENUM_CONSTANT(SOURCE_SCREEN);
+ BIND_ENUM_CONSTANT(SOURCE_DEPTH);
+ BIND_ENUM_CONSTANT(SOURCE_NORMAL_ROUGHNESS);
+ BIND_ENUM_CONSTANT(SOURCE_MAX);
}
bool VisualShaderNodeTextureParameter::is_qualifier_supported(Qualifier p_qual) const {
@@ -6396,7 +6450,7 @@ String VisualShaderNodeTexture2DParameter::get_output_port_name(int p_port) cons
String VisualShaderNodeTexture2DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -6407,7 +6461,7 @@ VisualShaderNodeTexture2DParameter::VisualShaderNodeTexture2DParameter() {
////////////// Texture Parameter (Triplanar)
String VisualShaderNodeTextureParameterTriplanar::get_caption() const {
- return "TextureUniformTriplanar";
+ return "TextureParameterTriplanar";
}
int VisualShaderNodeTextureParameterTriplanar::get_input_port_count() const {
@@ -6496,7 +6550,7 @@ String VisualShaderNodeTextureParameterTriplanar::generate_global_per_func(Shade
String VisualShaderNodeTextureParameterTriplanar::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler2D " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -6542,7 +6596,7 @@ String VisualShaderNodeTexture2DArrayParameter::get_output_port_name(int p_port)
String VisualShaderNodeTexture2DArrayParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler2DArray " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -6562,7 +6616,7 @@ String VisualShaderNodeTexture3DParameter::get_output_port_name(int p_port) cons
String VisualShaderNodeTexture3DParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform sampler3D " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -6582,7 +6636,7 @@ String VisualShaderNodeCubemapParameter::get_output_port_name(int p_port) const
String VisualShaderNodeCubemapParameter::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
String code = _get_qual_str() + "uniform samplerCube " + get_parameter_name();
- code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat);
+ code += get_sampler_hint(texture_type, color_default, texture_filter, texture_repeat, texture_source);
code += ";\n";
return code;
}
@@ -7640,12 +7694,15 @@ bool VisualShaderNodeProximityFade::has_output_port_preview(int p_port) const {
return false;
}
+String VisualShaderNodeProximityFade::generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) const {
+ return "uniform sampler2D " + make_unique_id(p_type, p_id, "depth_tex") + " : hint_depth_texture;\n";
+}
+
String VisualShaderNodeProximityFade::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 {
String code;
code += " {\n";
- String proximity_fade_distance = vformat("%s", p_input_vars[0]);
- code += " float __depth_tex = textureLod(DEPTH_TEXTURE, SCREEN_UV, 0.0).r;\n";
+ code += " float __depth_tex = texture(" + make_unique_id(p_type, p_id, "depth_tex") + ", SCREEN_UV).r;\n";
if (!RenderingServer::get_singleton()->is_low_end()) {
code += " vec4 __depth_world_pos = INV_PROJECTION_MATRIX * vec4(SCREEN_UV * 2.0 - 1.0, __depth_tex, 1.0);\n";
} else {
diff --git a/scene/resources/visual_shader_nodes.h b/scene/resources/visual_shader_nodes.h
index 07843c0264..e3b101cf84 100644
--- a/scene/resources/visual_shader_nodes.h
+++ b/scene/resources/visual_shader_nodes.h
@@ -385,6 +385,8 @@ public:
SOURCE_2D_NORMAL,
SOURCE_DEPTH,
SOURCE_PORT,
+ SOURCE_3D_NORMAL,
+ SOURCE_ROUGHNESS,
SOURCE_MAX,
};
@@ -668,6 +670,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual bool has_output_port_preview(int p_port) const override;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) 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;
VisualShaderNodeLinearSceneDepth();
@@ -2362,11 +2365,20 @@ public:
REPEAT_MAX,
};
+ enum TextureSource {
+ SOURCE_NONE,
+ SOURCE_SCREEN,
+ SOURCE_DEPTH,
+ SOURCE_NORMAL_ROUGHNESS,
+ SOURCE_MAX,
+ };
+
protected:
TextureType texture_type = TYPE_DATA;
ColorDefault color_default = COLOR_DEFAULT_WHITE;
TextureFilter texture_filter = FILTER_DEFAULT;
TextureRepeat texture_repeat = REPEAT_DEFAULT;
+ TextureSource texture_source = SOURCE_NONE;
protected:
static void _bind_methods();
@@ -2398,6 +2410,9 @@ public:
void set_texture_repeat(TextureRepeat p_repeat);
TextureRepeat get_texture_repeat() const;
+ void set_texture_source(TextureSource p_source);
+ TextureSource get_texture_source() const;
+
bool is_qualifier_supported(Qualifier p_qual) const override;
bool is_convertible_to_constant() const override;
@@ -2408,6 +2423,7 @@ VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureType)
VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::ColorDefault)
VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureFilter)
VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureRepeat)
+VARIANT_ENUM_CAST(VisualShaderNodeTextureParameter::TextureSource)
///////////////////////////////////////
@@ -2833,6 +2849,7 @@ public:
virtual String get_output_port_name(int p_port) const override;
virtual bool has_output_port_preview(int p_port) const override;
+ virtual String generate_global(Shader::Mode p_mode, VisualShader::Type p_type, int p_id) 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;
VisualShaderNodeProximityFade();
diff --git a/servers/display_server.cpp b/servers/display_server.cpp
index 82343e0402..39f14439f4 100644
--- a/servers/display_server.cpp
+++ b/servers/display_server.cpp
@@ -848,6 +848,7 @@ void DisplayServer::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_FLAG_NO_FOCUS);
BIND_ENUM_CONSTANT(WINDOW_FLAG_POPUP);
BIND_ENUM_CONSTANT(WINDOW_FLAG_EXTEND_TO_TITLE);
+ BIND_ENUM_CONSTANT(WINDOW_FLAG_MOUSE_PASSTHROUGH);
BIND_ENUM_CONSTANT(WINDOW_FLAG_MAX);
BIND_ENUM_CONSTANT(WINDOW_EVENT_MOUSE_ENTER);
diff --git a/servers/display_server.h b/servers/display_server.h
index f8ade60aca..aa30b25b65 100644
--- a/servers/display_server.h
+++ b/servers/display_server.h
@@ -311,6 +311,7 @@ public:
WINDOW_FLAG_NO_FOCUS,
WINDOW_FLAG_POPUP,
WINDOW_FLAG_EXTEND_TO_TITLE,
+ WINDOW_FLAG_MOUSE_PASSTHROUGH,
WINDOW_FLAG_MAX,
};
@@ -323,6 +324,7 @@ public:
WINDOW_FLAG_NO_FOCUS_BIT = (1 << WINDOW_FLAG_NO_FOCUS),
WINDOW_FLAG_POPUP_BIT = (1 << WINDOW_FLAG_POPUP),
WINDOW_FLAG_EXTEND_TO_TITLE_BIT = (1 << WINDOW_FLAG_EXTEND_TO_TITLE),
+ WINDOW_FLAG_MOUSE_PASSTHROUGH_BIT = (1 << WINDOW_FLAG_MOUSE_PASSTHROUGH),
};
virtual WindowID create_sub_window(WindowMode p_mode, VSyncMode p_vsync_mode, uint32_t p_flags, const Rect2i &p_rect = Rect2i());
diff --git a/servers/physics_3d/gjk_epa.cpp b/servers/physics_3d/gjk_epa.cpp
index 88f2040d17..e5678914fe 100644
--- a/servers/physics_3d/gjk_epa.cpp
+++ b/servers/physics_3d/gjk_epa.cpp
@@ -1011,9 +1011,11 @@ bool gjk_epa_calculate_penetration(const GodotShape3D *p_shape_A, const Transfor
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], 0, res.witnesses[0], 0, p_userdata);
+ Vector3 normal = (res.witnesses[1] - res.witnesses[0]).normalized();
+ p_result_callback(res.witnesses[1], 0, res.witnesses[0], 0, normal, p_userdata);
} else {
- p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, p_userdata);
+ Vector3 normal = (res.witnesses[0] - res.witnesses[1]).normalized();
+ p_result_callback(res.witnesses[0], 0, res.witnesses[1], 0, normal, p_userdata);
}
}
return true;
diff --git a/servers/physics_3d/godot_body_pair_3d.cpp b/servers/physics_3d/godot_body_pair_3d.cpp
index ce3da390cb..619e6c00be 100644
--- a/servers/physics_3d/godot_body_pair_3d.cpp
+++ b/servers/physics_3d/godot_body_pair_3d.cpp
@@ -38,12 +38,12 @@
#define MIN_VELOCITY 0.0001
#define MAX_BIAS_ROTATION (Math_PI / 8)
-void GodotBodyPair3D::_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 GodotBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
GodotBodyPair3D *pair = static_cast<GodotBodyPair3D *>(p_userdata);
- pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B, normal);
}
-void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
+void GodotBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal) {
Vector3 local_A = A->get_inv_transform().basis.xform(p_point_A);
Vector3 local_B = B->get_inv_transform().basis.xform(p_point_B - offset_B);
@@ -577,12 +577,12 @@ GodotBodyPair3D::~GodotBodyPair3D() {
B->remove_constraint(this);
}
-void GodotBodySoftBodyPair3D::_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 GodotBodySoftBodyPair3D::_contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
GodotBodySoftBodyPair3D *pair = static_cast<GodotBodySoftBodyPair3D *>(p_userdata);
- pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B);
+ pair->contact_added_callback(p_point_A, p_index_A, p_point_B, p_index_B, normal);
}
-void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B) {
+void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal) {
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);
@@ -591,7 +591,7 @@ void GodotBodySoftBodyPair3D::contact_added_callback(const Vector3 &p_point_A, i
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();
+ contact.normal = (normal.dot((p_point_A - p_point_B)) < 0 ? -normal : normal);
contact.used = true;
// Attempt to determine if the contact will be reused.
diff --git a/servers/physics_3d/godot_body_pair_3d.h b/servers/physics_3d/godot_body_pair_3d.h
index c3165c7fcf..a8f5180dd5 100644
--- a/servers/physics_3d/godot_body_pair_3d.h
+++ b/servers/physics_3d/godot_body_pair_3d.h
@@ -97,9 +97,9 @@ class GodotBodyPair3D : public GodotBodyContact3D {
Contact contacts[MAX_CONTACTS];
int contact_count = 0;
- 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);
+ static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, 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 contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal);
void validate_contacts();
bool _test_ccd(real_t p_step, GodotBody3D *p_A, int p_shape_A, const Transform3D &p_xform_A, GodotBody3D *p_B, int p_shape_B, const Transform3D &p_xform_B);
@@ -126,9 +126,9 @@ class GodotBodySoftBodyPair3D : public GodotBodyContact3D {
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);
+ static void _contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, 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 contact_added_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal);
void validate_contacts();
diff --git a/servers/physics_3d/godot_collision_solver_3d.cpp b/servers/physics_3d/godot_collision_solver_3d.cpp
index 0b92b745fe..fb5a67c008 100644
--- a/servers/physics_3d/godot_collision_solver_3d.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d.cpp
@@ -81,9 +81,11 @@ bool GodotCollisionSolver3D::solve_static_world_boundary(const GodotShape3D *p_s
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(supports[i], 0, support_A, 0, p_userdata);
+ Vector3 normal = (support_A - supports[i]).normalized();
+ p_result_callback(supports[i], 0, support_A, 0, normal, p_userdata);
} else {
- p_result_callback(support_A, 0, supports[i], 0, p_userdata);
+ Vector3 normal = (supports[i] - support_A).normalized();
+ p_result_callback(support_A, 0, supports[i], 0, normal, p_userdata);
}
}
}
@@ -126,9 +128,11 @@ bool GodotCollisionSolver3D::solve_separation_ray(const GodotShape3D *p_shape_A,
if (p_result_callback) {
if (p_swap_result) {
- p_result_callback(support_B, 0, support_A, 0, p_userdata);
+ Vector3 normal = (support_B - support_A).normalized();
+ p_result_callback(support_B, 0, support_A, 0, normal, p_userdata);
} else {
- p_result_callback(support_A, 0, support_B, 0, p_userdata);
+ Vector3 normal = (support_A - support_B).normalized();
+ p_result_callback(support_A, 0, support_B, 0, normal, p_userdata);
}
}
return true;
@@ -142,7 +146,7 @@ struct _SoftBodyContactCollisionInfo {
int contact_count = 0;
};
-void GodotCollisionSolver3D::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) {
+void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
_SoftBodyContactCollisionInfo &cinfo = *(static_cast<_SoftBodyContactCollisionInfo *>(p_userdata));
++cinfo.contact_count;
@@ -152,9 +156,9 @@ void GodotCollisionSolver3D::soft_body_contact_callback(const Vector3 &p_point_A
}
if (cinfo.swap_result) {
- cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, cinfo.userdata);
+ cinfo.result_callback(p_point_B, cinfo.node_index, p_point_A, p_index_A, -normal, cinfo.userdata);
} else {
- cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, cinfo.userdata);
+ cinfo.result_callback(p_point_A, p_index_A, p_point_B, cinfo.node_index, normal, cinfo.userdata);
}
}
diff --git a/servers/physics_3d/godot_collision_solver_3d.h b/servers/physics_3d/godot_collision_solver_3d.h
index 7ef0dc97ac..36ea79576e 100644
--- a/servers/physics_3d/godot_collision_solver_3d.h
+++ b/servers/physics_3d/godot_collision_solver_3d.h
@@ -35,11 +35,11 @@
class GodotCollisionSolver3D {
public:
- typedef void (*CallbackResult)(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_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, const Vector3 &normal, 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_contact_callback(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata);
static bool soft_body_concave_callback(void *p_userdata, GodotShape3D *p_convex);
static bool concave_callback(void *p_userdata, GodotShape3D *p_convex);
static bool solve_static_world_boundary(const GodotShape3D *p_shape_A, const Transform3D &p_transform_A, const GodotShape3D *p_shape_B, const Transform3D &p_transform_B, CallbackResult p_result_callback, void *p_userdata, bool p_swap_result, real_t p_margin = 0);
diff --git a/servers/physics_3d/godot_collision_solver_3d_sat.cpp b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
index d13f4ee801..66d1811abb 100644
--- a/servers/physics_3d/godot_collision_solver_3d_sat.cpp
+++ b/servers/physics_3d/godot_collision_solver_3d_sat.cpp
@@ -75,11 +75,13 @@ struct _CollectorCallback {
Vector3 normal;
Vector3 *prev_axis = nullptr;
- _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B) {
+ _FORCE_INLINE_ void call(const Vector3 &p_point_A, const Vector3 &p_point_B, Vector3 p_normal) {
+ if (p_normal.dot(p_point_B - p_point_A) < 0)
+ p_normal = -p_normal;
if (swap) {
- callback(p_point_B, 0, p_point_A, 0, userdata);
+ callback(p_point_B, 0, p_point_A, 0, -p_normal, userdata);
} else {
- callback(p_point_A, 0, p_point_B, 0, userdata);
+ callback(p_point_A, 0, p_point_B, 0, p_normal, userdata);
}
}
};
@@ -92,7 +94,7 @@ static void _generate_contacts_point_point(const Vector3 *p_points_A, int p_poin
ERR_FAIL_COND(p_point_count_B != 1);
#endif
- p_callback->call(*p_points_A, *p_points_B);
+ p_callback->call(*p_points_A, *p_points_B, p_callback->normal);
}
static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -102,7 +104,7 @@ static void _generate_contacts_point_edge(const Vector3 *p_points_A, int p_point
#endif
Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(*p_points_A, p_points_B);
- p_callback->call(*p_points_A, closest_B);
+ p_callback->call(*p_points_A, closest_B, p_callback->normal);
}
static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -111,9 +113,9 @@ static void _generate_contacts_point_face(const Vector3 *p_points_A, int p_point
ERR_FAIL_COND(p_point_count_B < 3);
#endif
- Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A);
-
- p_callback->call(*p_points_A, closest_B);
+ Plane plane(p_points_B[0], p_points_B[1], p_points_B[2]);
+ Vector3 closest_B = plane.project(*p_points_A);
+ p_callback->call(*p_points_A, closest_B, plane.get_normal());
}
static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -122,9 +124,9 @@ static void _generate_contacts_point_circle(const Vector3 *p_points_A, int p_poi
ERR_FAIL_COND(p_point_count_B != 3);
#endif
- Vector3 closest_B = Plane(p_points_B[0], p_points_B[1], p_points_B[2]).project(*p_points_A);
-
- p_callback->call(*p_points_A, closest_B);
+ Plane plane(p_points_B[0], p_points_B[1], p_points_B[2]);
+ Vector3 closest_B = plane.project(*p_points_A);
+ p_callback->call(*p_points_A, closest_B, plane.get_normal());
}
static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -154,8 +156,8 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
sa.sort(dvec, 4);
//use the middle ones as contacts
- p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1]);
- p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2]);
+ p_callback->call(base_A + axis * dvec[1], base_B + axis * dvec[1], p_callback->normal);
+ p_callback->call(base_A + axis * dvec[2], base_B + axis * dvec[2], p_callback->normal);
return;
}
@@ -170,7 +172,14 @@ static void _generate_contacts_edge_edge(const Vector3 *p_points_A, int p_point_
Vector3 closest_A = p_points_A[0] + rel_A * d;
Vector3 closest_B = Geometry3D::get_closest_point_to_segment_uncapped(closest_A, p_points_B);
- p_callback->call(closest_A, closest_B);
+ // The normal should be perpendicular to both edges.
+ Vector3 normal = rel_A.cross(rel_B);
+ real_t normal_len = normal.length();
+ if (normal_len > 1e-3)
+ normal /= normal_len;
+ else
+ normal = p_callback->normal;
+ p_callback->call(closest_A, closest_B, normal);
}
static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_point_count_A, const Vector3 *p_points_B, int p_point_count_B, _CollectorCallback *p_callback) {
@@ -267,7 +276,7 @@ static void _generate_contacts_edge_circle(const Vector3 *p_points_A, int p_poin
continue;
}
- p_callback->call(contact_point_A, closest_B);
+ p_callback->call(contact_point_A, closest_B, circle_plane.get_normal());
}
}
@@ -352,7 +361,7 @@ static void _generate_contacts_face_face(const Vector3 *p_points_A, int p_point_
continue;
}
- p_callback->call(clipbuf_src[i], closest_B);
+ p_callback->call(clipbuf_src[i], closest_B, plane_B.get_normal());
}
}
@@ -431,7 +440,7 @@ static void _generate_contacts_face_circle(const Vector3 *p_points_A, int p_poin
continue;
}
- p_callback->call(contact_point_A, closest_B);
+ p_callback->call(contact_point_A, closest_B, circle_plane.get_normal());
}
}
@@ -534,7 +543,7 @@ static void _generate_contacts_circle_circle(const Vector3 *p_points_A, int p_po
continue;
}
- p_callback->call(contact_point_A, closest_B);
+ p_callback->call(contact_point_A, closest_B, circle_B_plane.get_normal());
}
}
@@ -678,7 +687,7 @@ public:
return true;
}
- 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) {
+ 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, const Vector3 &normal, 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();
@@ -802,11 +811,11 @@ static void analytic_sphere_collision(const Vector3 &p_origin_a, real_t p_radius
if (p_radius_a < p_radius_b) {
Vector3 point_a = p_origin_a - b_to_a * p_radius_a;
Vector3 point_b = point_a + b_to_a * overlap;
- p_collector->call(point_a, point_b); // Consider adding b_to_a vector
+ p_collector->call(point_a, point_b, b_to_a); // Consider adding b_to_a vector
} else {
Vector3 point_b = p_origin_b + b_to_a * p_radius_b;
Vector3 point_a = point_b - b_to_a * overlap;
- p_collector->call(point_a, point_b); // Consider adding b_to_a vector
+ p_collector->call(point_a, point_b, b_to_a); // Consider adding b_to_a vector
}
}
@@ -859,8 +868,8 @@ static void _collision_sphere_box(const GodotShape3D *p_a, const Transform3D &p_
axis = delta / length;
}
Vector3 point_a = p_transform_a.origin + (sphere_A->get_radius() + p_margin_a) * axis;
- Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest);
- p_collector->call(point_a, point_b);
+ Vector3 point_b = (withMargin ? nearest - p_margin_b * axis : nearest);
+ p_collector->call(point_a, point_b, axis);
}
template <bool withMargin>
@@ -926,8 +935,8 @@ static void analytic_sphere_cylinder_collision(real_t p_radius_a, real_t p_radiu
axis = delta / length;
}
Vector3 point_a = p_transform_a.origin + (p_radius_a + p_margin_a) * axis;
- Vector3 point_b = (withMargin ? nearest + p_margin_b * axis : nearest);
- p_collector->call(point_a, point_b);
+ Vector3 point_b = (withMargin ? nearest - p_margin_b * axis : nearest);
+ p_collector->call(point_a, point_b, axis);
}
template <bool withMargin>
diff --git a/servers/physics_3d/godot_physics_server_3d.cpp b/servers/physics_3d/godot_physics_server_3d.cpp
index e8250acb45..b6d8acfbf3 100644
--- a/servers/physics_3d/godot_physics_server_3d.cpp
+++ b/servers/physics_3d/godot_physics_server_3d.cpp
@@ -1737,7 +1737,7 @@ void GodotPhysicsServer3D::_update_shapes() {
}
}
-void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, void *p_userdata) {
+void GodotPhysicsServer3D::_shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
CollCbkData *cbk = static_cast<CollCbkData *>(p_userdata);
if (cbk->max == 0) {
diff --git a/servers/physics_3d/godot_physics_server_3d.h b/servers/physics_3d/godot_physics_server_3d.h
index 3da0c6debe..040e673dcd 100644
--- a/servers/physics_3d/godot_physics_server_3d.h
+++ b/servers/physics_3d/godot_physics_server_3d.h
@@ -77,7 +77,7 @@ public:
Vector3 *ptr = nullptr;
};
- 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);
+ static void _shape_col_cbk(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata);
virtual RID world_boundary_shape_create() override;
virtual RID separation_ray_shape_create() override;
diff --git a/servers/physics_3d/godot_space_3d.cpp b/servers/physics_3d/godot_space_3d.cpp
index c3aad22932..93572965d2 100644
--- a/servers/physics_3d/godot_space_3d.cpp
+++ b/servers/physics_3d/godot_space_3d.cpp
@@ -445,7 +445,7 @@ struct _RestCallbackData {
_RestResultData *other_results = nullptr;
};
-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) {
+static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vector3 &p_point_B, int p_index_B, const Vector3 &normal, void *p_userdata) {
_RestCallbackData *rd = static_cast<_RestCallbackData *>(p_userdata);
Vector3 contact_rel = p_point_B - p_point_A;
@@ -480,7 +480,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect
// Keep this result as separate result.
result.len = len;
result.contact = p_point_B;
- result.normal = contact_rel / len;
+ result.normal = normal;
result.object = rd->object;
result.shape = rd->shape;
result.local_shape = rd->local_shape;
@@ -499,7 +499,7 @@ static void _rest_cbk_result(const Vector3 &p_point_A, int p_index_A, const Vect
rd->best_result.len = len;
rd->best_result.contact = p_point_B;
- rd->best_result.normal = contact_rel / len;
+ rd->best_result.normal = normal;
rd->best_result.object = rd->object;
rd->best_result.shape = rd->shape;
rd->best_result.local_shape = rd->local_shape;
diff --git a/servers/rendering/dummy/storage/texture_storage.h b/servers/rendering/dummy/storage/texture_storage.h
index 62e1eb326d..fd36e7ac10 100644
--- a/servers/rendering/dummy/storage/texture_storage.h
+++ b/servers/rendering/dummy/storage/texture_storage.h
@@ -154,6 +154,7 @@ public:
virtual RID decal_instance_create(RID p_decal) override { return RID(); }
virtual void decal_instance_free(RID p_decal_instance) override {}
virtual void decal_instance_set_transform(RID p_decal, const Transform3D &p_transform) override {}
+ virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override {}
/* RENDER TARGET */
diff --git a/servers/rendering/renderer_canvas_cull.cpp b/servers/rendering/renderer_canvas_cull.cpp
index 3510b415d8..b9e3c4f303 100644
--- a/servers/rendering/renderer_canvas_cull.cpp
+++ b/servers/rendering/renderer_canvas_cull.cpp
@@ -597,7 +597,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
Vector2 end_left;
Vector2 end_right;
- if (p_width > 1.001) {
+ if (p_width >= 0.0) {
begin_left = p_from + t;
begin_right = p_from - t;
end_left = p_to + t;
@@ -628,7 +628,7 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
// This value is empirically determined to provide good antialiasing quality
// while not making lines appear too soft.
float border_size = 1.25f;
- if (p_width < 1.0f) {
+ if (0.0f <= p_width && p_width < 1.0f) {
border_size *= p_width;
}
Vector2 dir2 = diff.normalized();
@@ -769,6 +769,49 @@ void RendererCanvasCull::canvas_item_add_line(RID p_item, const Point2 &p_from,
}
}
+static Vector2 compute_polyline_segment_dir(const Vector<Point2> &p_points, int p_index, const Vector2 &p_prev_segment_dir) {
+ int point_count = p_points.size();
+
+ bool is_last_point = (p_index == point_count - 1);
+
+ Vector2 segment_dir;
+
+ if (is_last_point) {
+ segment_dir = p_prev_segment_dir;
+ } else {
+ segment_dir = (p_points[p_index + 1] - p_points[p_index]).normalized();
+
+ if (segment_dir.is_zero_approx()) {
+ segment_dir = p_prev_segment_dir;
+ }
+ }
+
+ return segment_dir;
+}
+
+static Vector2 compute_polyline_edge_offset_clamped(const Vector2 &p_segment_dir, const Vector2 &p_prev_segment_dir) {
+ Vector2 bisector;
+ float length = 1.0f;
+
+ bisector = (p_prev_segment_dir * p_segment_dir.length() - p_segment_dir * p_prev_segment_dir.length()).normalized();
+
+ float angle = atan2f(bisector.cross(p_prev_segment_dir), bisector.dot(p_prev_segment_dir));
+ float sin_angle = sinf(angle);
+
+ if (!Math::is_zero_approx(sin_angle) && !p_segment_dir.is_equal_approx(p_prev_segment_dir)) {
+ length = 1.0f / sin_angle;
+ length = CLAMP(length, -3.0f, 3.0f);
+ } else {
+ bisector = p_segment_dir.orthogonal();
+ }
+
+ if (bisector.is_zero_approx()) {
+ bisector = p_segment_dir.orthogonal();
+ }
+
+ return bisector * length;
+}
+
void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width, bool p_antialiased) {
ERR_FAIL_COND(p_points.size() < 2);
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
@@ -777,20 +820,68 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
Color color = Color(1, 1, 1, 1);
Vector<int> indices;
- int pc = p_points.size();
- int pc2 = pc * 2;
-
- Vector2 prev_t;
- int j2;
+ int point_count = p_points.size();
Item::CommandPolygon *pline = canvas_item->alloc_command<Item::CommandPolygon>();
ERR_FAIL_COND(!pline);
+ if (p_width < 0) {
+ if (p_antialiased) {
+ WARN_PRINT("Antialiasing is not supported for thin polylines drawn using line strips (`p_width < 0`).");
+ }
+
+ pline->primitive = RS::PRIMITIVE_LINE_STRIP;
+
+ if (p_colors.size() == 1 || p_colors.size() == point_count) {
+ pline->polygon.create(indices, p_points, p_colors);
+ } else {
+ Vector<Color> colors;
+ if (p_colors.is_empty()) {
+ colors.push_back(color);
+ } else {
+ colors.resize(point_count);
+ Color *colors_ptr = colors.ptrw();
+ for (int i = 0; i < point_count; i++) {
+ if (i < p_colors.size()) {
+ color = p_colors[i];
+ }
+ colors_ptr[i] = color;
+ }
+ }
+ pline->polygon.create(indices, p_points, colors);
+ }
+ return;
+ }
+
+ int polyline_point_count = point_count * 2;
+
+ bool loop = p_points[0].is_equal_approx(p_points[point_count - 1]);
+ Vector2 first_segment_dir;
+ Vector2 last_segment_dir;
+
+ // Search for first non-zero vector between two segments.
+ for (int i = 1; i < point_count; i++) {
+ first_segment_dir = (p_points[i] - p_points[i - 1]).normalized();
+
+ if (!first_segment_dir.is_zero_approx()) {
+ break;
+ }
+ }
+
+ // Search for last non-zero vector between two segments.
+ for (int i = point_count - 1; i >= 1; i--) {
+ last_segment_dir = (p_points[i] - p_points[i - 1]).normalized();
+
+ if (!last_segment_dir.is_zero_approx()) {
+ break;
+ }
+ }
+
PackedColorArray colors;
PackedVector2Array points;
- colors.resize(pc2);
- points.resize(pc2);
+ colors.resize(polyline_point_count);
+ points.resize(polyline_point_count);
Vector2 *points_ptr = points.ptrw();
Color *colors_ptr = colors.ptrw();
@@ -845,14 +936,14 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
PackedColorArray colors_left;
PackedVector2Array points_left;
- colors_left.resize(pc2);
- points_left.resize(pc2);
+ colors_left.resize(polyline_point_count);
+ points_left.resize(polyline_point_count);
PackedColorArray colors_right;
PackedVector2Array points_right;
- colors_right.resize(pc2);
- points_right.resize(pc2);
+ colors_right.resize(polyline_point_count);
+ points_right.resize(polyline_point_count);
Item::CommandPolygon *pline_begin = canvas_item->alloc_command<Item::CommandPolygon>();
ERR_FAIL_COND(!pline_begin);
@@ -898,79 +989,81 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
Color *colors_left_ptr = colors_left.ptrw();
Color *colors_right_ptr = colors_right.ptrw();
- for (int i = 0, j = 0; i < pc; i++, j += 2) {
- bool is_begin = i == 0;
- bool is_end = i == pc - 1;
+ Vector2 prev_segment_dir;
+ for (int i = 0; i < point_count; i++) {
+ bool is_first_point = (i == 0);
+ bool is_last_point = (i == point_count - 1);
- Vector2 t;
- Vector2 end_border;
- Vector2 begin_border;
- if (is_end) {
- t = prev_t;
- end_border = (p_points[i] - p_points[i - 1]).normalized() * border_size;
- } else {
- t = (p_points[i + 1] - p_points[i]).normalized().orthogonal();
- if (is_begin) {
- prev_t = t;
- begin_border = (p_points[i] - p_points[i + 1]).normalized() * border_size;
- }
+ Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir);
+ if (is_first_point && loop) {
+ prev_segment_dir = last_segment_dir;
+ } else if (is_last_point && loop) {
+ prev_segment_dir = first_segment_dir;
}
- j2 = j + 1;
+ Vector2 base_edge_offset;
+ if (is_first_point && !loop) {
+ base_edge_offset = first_segment_dir.orthogonal();
+ } else if (is_last_point && !loop) {
+ base_edge_offset = last_segment_dir.orthogonal();
+ } else {
+ base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir);
+ }
- Vector2 dir = (t + prev_t).normalized();
- Vector2 tangent = dir * p_width * 0.5;
- Vector2 border = dir * border_size;
+ Vector2 edge_offset = base_edge_offset * (p_width * 0.5f);
+ Vector2 border = base_edge_offset * border_size;
Vector2 pos = p_points[i];
- points_ptr[j] = pos + tangent;
- points_ptr[j2] = pos - tangent;
+ points_ptr[i * 2 + 0] = pos + edge_offset;
+ points_ptr[i * 2 + 1] = pos - edge_offset;
- points_left_ptr[j] = pos + tangent + border;
- points_left_ptr[j2] = pos + tangent;
+ points_left_ptr[i * 2 + 0] = pos + edge_offset + border;
+ points_left_ptr[i * 2 + 1] = pos + edge_offset;
- points_right_ptr[j] = pos - tangent;
- points_right_ptr[j2] = pos - tangent - border;
+ points_right_ptr[i * 2 + 0] = pos - edge_offset;
+ points_right_ptr[i * 2 + 1] = pos - edge_offset - border;
if (i < p_colors.size()) {
color = p_colors[i];
color2 = Color(color.r, color.g, color.b, 0);
}
- colors_ptr[j] = color;
- colors_ptr[j2] = color;
+ colors_ptr[i * 2 + 0] = color;
+ colors_ptr[i * 2 + 1] = color;
+
+ colors_left_ptr[i * 2 + 0] = color2;
+ colors_left_ptr[i * 2 + 1] = color;
- colors_left_ptr[j] = color2;
- colors_left_ptr[j2] = color;
+ colors_right_ptr[i * 2 + 0] = color;
+ colors_right_ptr[i * 2 + 1] = color2;
- colors_right_ptr[j] = color;
- colors_right_ptr[j2] = color2;
+ if (is_first_point) {
+ Vector2 begin_border = loop ? Vector2() : -segment_dir * border_size;
- if (is_begin) {
- points_begin_ptr[0] = pos + tangent + begin_border;
- points_begin_ptr[1] = pos - tangent + begin_border;
- points_begin_ptr[2] = pos + tangent;
- points_begin_ptr[3] = pos - tangent;
+ points_begin_ptr[0] = pos + edge_offset + begin_border;
+ points_begin_ptr[1] = pos - edge_offset + begin_border;
+ points_begin_ptr[2] = pos + edge_offset;
+ points_begin_ptr[3] = pos - edge_offset;
colors_begin_ptr[0] = color2;
colors_begin_ptr[1] = color2;
colors_begin_ptr[2] = color;
colors_begin_ptr[3] = color;
- points_begin_left_corner_ptr[0] = pos - tangent - border;
- points_begin_left_corner_ptr[1] = pos - tangent + begin_border - border;
- points_begin_left_corner_ptr[2] = pos - tangent;
- points_begin_left_corner_ptr[3] = pos - tangent + begin_border;
+ points_begin_left_corner_ptr[0] = pos - edge_offset - border;
+ points_begin_left_corner_ptr[1] = pos - edge_offset + begin_border - border;
+ points_begin_left_corner_ptr[2] = pos - edge_offset;
+ points_begin_left_corner_ptr[3] = pos - edge_offset + begin_border;
colors_begin_left_corner_ptr[0] = color2;
colors_begin_left_corner_ptr[1] = color2;
colors_begin_left_corner_ptr[2] = color;
colors_begin_left_corner_ptr[3] = color2;
- points_begin_right_corner_ptr[0] = pos + tangent + begin_border;
- points_begin_right_corner_ptr[1] = pos + tangent + begin_border + border;
- points_begin_right_corner_ptr[2] = pos + tangent;
- points_begin_right_corner_ptr[3] = pos + tangent + border;
+ points_begin_right_corner_ptr[0] = pos + edge_offset + begin_border;
+ points_begin_right_corner_ptr[1] = pos + edge_offset + begin_border + border;
+ points_begin_right_corner_ptr[2] = pos + edge_offset;
+ points_begin_right_corner_ptr[3] = pos + edge_offset + border;
colors_begin_right_corner_ptr[0] = color2;
colors_begin_right_corner_ptr[1] = color2;
@@ -978,31 +1071,33 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
colors_begin_right_corner_ptr[3] = color2;
}
- if (is_end) {
- points_end_ptr[0] = pos + tangent + end_border;
- points_end_ptr[1] = pos - tangent + end_border;
- points_end_ptr[2] = pos + tangent;
- points_end_ptr[3] = pos - tangent;
+ if (is_last_point) {
+ Vector2 end_border = loop ? Vector2() : prev_segment_dir * border_size;
+
+ points_end_ptr[0] = pos + edge_offset + end_border;
+ points_end_ptr[1] = pos - edge_offset + end_border;
+ points_end_ptr[2] = pos + edge_offset;
+ points_end_ptr[3] = pos - edge_offset;
colors_end_ptr[0] = color2;
colors_end_ptr[1] = color2;
colors_end_ptr[2] = color;
colors_end_ptr[3] = color;
- points_end_left_corner_ptr[0] = pos - tangent - border;
- points_end_left_corner_ptr[1] = pos - tangent + end_border - border;
- points_end_left_corner_ptr[2] = pos - tangent;
- points_end_left_corner_ptr[3] = pos - tangent + end_border;
+ points_end_left_corner_ptr[0] = pos - edge_offset - border;
+ points_end_left_corner_ptr[1] = pos - edge_offset + end_border - border;
+ points_end_left_corner_ptr[2] = pos - edge_offset;
+ points_end_left_corner_ptr[3] = pos - edge_offset + end_border;
colors_end_left_corner_ptr[0] = color2;
colors_end_left_corner_ptr[1] = color2;
colors_end_left_corner_ptr[2] = color;
colors_end_left_corner_ptr[3] = color2;
- points_end_right_corner_ptr[0] = pos + tangent + end_border;
- points_end_right_corner_ptr[1] = pos + tangent + end_border + border;
- points_end_right_corner_ptr[2] = pos + tangent;
- points_end_right_corner_ptr[3] = pos + tangent + border;
+ points_end_right_corner_ptr[0] = pos + edge_offset + end_border;
+ points_end_right_corner_ptr[1] = pos + edge_offset + end_border + border;
+ points_end_right_corner_ptr[2] = pos + edge_offset;
+ points_end_right_corner_ptr[3] = pos + edge_offset + border;
colors_end_right_corner_ptr[0] = color2;
colors_end_right_corner_ptr[1] = color2;
@@ -1010,7 +1105,7 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
colors_end_right_corner_ptr[3] = color2;
}
- prev_t = t;
+ prev_segment_dir = segment_dir;
}
pline_begin->primitive = RS::PRIMITIVE_TRIANGLE_STRIP;
@@ -1039,33 +1134,41 @@ void RendererCanvasCull::canvas_item_add_polyline(RID p_item, const Vector<Point
} else {
// Makes a single triangle strip for drawing the line.
- for (int i = 0, j = 0; i < pc; i++, j += 2) {
- Vector2 t;
- if (i == pc - 1) {
- t = prev_t;
- } else {
- t = (p_points[i + 1] - p_points[i]).normalized().orthogonal();
- if (i == 0) {
- prev_t = t;
- }
+ Vector2 prev_segment_dir;
+ for (int i = 0; i < point_count; i++) {
+ bool is_first_point = (i == 0);
+ bool is_last_point = (i == point_count - 1);
+
+ Vector2 segment_dir = compute_polyline_segment_dir(p_points, i, prev_segment_dir);
+ if (is_first_point && loop) {
+ prev_segment_dir = last_segment_dir;
+ } else if (is_last_point && loop) {
+ prev_segment_dir = first_segment_dir;
}
- j2 = j + 1;
+ Vector2 base_edge_offset;
+ if (is_first_point && !loop) {
+ base_edge_offset = first_segment_dir.orthogonal();
+ } else if (is_last_point && !loop) {
+ base_edge_offset = last_segment_dir.orthogonal();
+ } else {
+ base_edge_offset = compute_polyline_edge_offset_clamped(segment_dir, prev_segment_dir);
+ }
- Vector2 tangent = ((t + prev_t).normalized()) * p_width * 0.5;
+ Vector2 edge_offset = base_edge_offset * (p_width * 0.5f);
Vector2 pos = p_points[i];
- points_ptr[j] = pos + tangent;
- points_ptr[j2] = pos - tangent;
+ points_ptr[i * 2 + 0] = pos + edge_offset;
+ points_ptr[i * 2 + 1] = pos - edge_offset;
if (i < p_colors.size()) {
color = p_colors[i];
}
- colors_ptr[j] = color;
- colors_ptr[j2] = color;
+ colors_ptr[i * 2 + 0] = color;
+ colors_ptr[i * 2 + 1] = color;
- prev_t = t;
+ prev_segment_dir = segment_dir;
}
}
@@ -1077,7 +1180,7 @@ void RendererCanvasCull::canvas_item_add_multiline(RID p_item, const Vector<Poin
ERR_FAIL_COND(p_points.size() < 2);
// TODO: `canvas_item_add_line`(`multiline`, `polyline`) share logic, should factor out.
- if (p_width <= 1) {
+ if (p_width < 0) {
Item *canvas_item = canvas_item_owner.get_or_null(p_item);
ERR_FAIL_COND(!canvas_item);
@@ -1133,20 +1236,23 @@ void RendererCanvasCull::canvas_item_add_circle(RID p_item, const Point2 &p_pos,
static const int circle_points = 64;
points.resize(circle_points);
+ Vector2 *points_ptr = points.ptrw();
const real_t circle_point_step = Math_TAU / circle_points;
for (int i = 0; i < circle_points; i++) {
float angle = i * circle_point_step;
- points.write[i].x = Math::cos(angle) * p_radius;
- points.write[i].y = Math::sin(angle) * p_radius;
- points.write[i] += p_pos;
+ points_ptr[i].x = Math::cos(angle) * p_radius;
+ points_ptr[i].y = Math::sin(angle) * p_radius;
+ points_ptr[i] += p_pos;
}
+
indices.resize((circle_points - 2) * 3);
+ int *indices_ptr = indices.ptrw();
for (int i = 0; i < circle_points - 2; i++) {
- indices.write[i * 3 + 0] = 0;
- indices.write[i * 3 + 1] = i + 1;
- indices.write[i * 3 + 2] = i + 2;
+ indices_ptr[i * 3 + 0] = 0;
+ indices_ptr[i * 3 + 1] = i + 1;
+ indices_ptr[i * 3 + 2] = i + 2;
}
Vector<Color> color;
@@ -1313,7 +1419,7 @@ void RendererCanvasCull::canvas_item_add_nine_patch(RID p_item, const Rect2 &p_r
style->axis_y = p_y_axis_mode;
}
-void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width) {
+void RendererCanvasCull::canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) {
uint32_t pc = p_points.size();
ERR_FAIL_COND(pc == 0 || pc > 4);
diff --git a/servers/rendering/renderer_canvas_cull.h b/servers/rendering/renderer_canvas_cull.h
index 4d0be48cc0..1106fc4f1e 100644
--- a/servers/rendering/renderer_canvas_cull.h
+++ b/servers/rendering/renderer_canvas_cull.h
@@ -221,9 +221,9 @@ public:
void canvas_item_set_update_when_visible(RID p_item, bool p_update);
- void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false);
- void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false);
- void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0);
+ void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false);
+ void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false);
+ void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0);
void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color);
void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color);
void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false);
@@ -231,7 +231,7 @@ public:
void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0);
void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1));
void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, RS::NinePatchAxisMode p_x_axis_mode = RS::NINE_PATCH_STRETCH, RS::NinePatchAxisMode p_y_axis_mode = RS::NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1));
- void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0);
+ void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture);
void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID());
void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1);
void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID());
diff --git a/servers/rendering/renderer_rd/environment/sky.cpp b/servers/rendering/renderer_rd/environment/sky.cpp
index 863e8d6c15..7e02f98ce9 100644
--- a/servers/rendering/renderer_rd/environment/sky.cpp
+++ b/servers/rendering/renderer_rd/environment/sky.cpp
@@ -1085,8 +1085,8 @@ void SkyRD::setup_sky(RID p_env, Ref<RenderSceneBuffersRD> p_render_buffers, con
sky->reflection.dirty = true;
}
+ sky_scene_state.ubo.directional_light_count = 0;
if (shader_data->uses_light) {
- sky_scene_state.ubo.directional_light_count = 0;
// Run through the list of lights in the scene and pick out the Directional Lights.
// This can't be done in RenderSceneRenderRD::_setup lights because that needs to be called
// after the depth prepass, but this runs before the depth prepass
diff --git a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
index 93c741fd34..3fd8d55a71 100644
--- a/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/render_forward_clustered.cpp
@@ -1480,7 +1480,7 @@ void RenderForwardClustered::_pre_opaque_render(RenderDataRD *p_render_data, boo
uint32_t directional_light_count = 0;
uint32_t positional_light_count = 0;
light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
- texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse());
+ texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform);
p_render_data->directional_light_count = directional_light_count;
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
index 7eabce2f79..412406c0b4 100644
--- a/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
+++ b/servers/rendering/renderer_rd/forward_clustered/scene_shader_forward_clustered.cpp
@@ -44,7 +44,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
valid = false;
ubo_size = 0;
uniforms.clear();
- uses_screen_texture = false;
if (code.is_empty()) {
return; //just invalid, but no error
@@ -73,9 +72,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
uses_position = 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;
@@ -120,9 +116,6 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
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_ROUGHNESS_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;
@@ -151,6 +144,9 @@ void SceneShaderForwardClustered::ShaderData::set_code(const String &p_code) {
depth_test = DepthTest(depth_testi);
cull_mode = Cull(cull_modei);
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
+ uses_depth_texture = gen_code.uses_depth_texture;
+ uses_normal_texture = gen_code.uses_normal_roughness_texture;
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;
@@ -607,9 +603,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
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"] = "fog";
@@ -674,7 +667,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
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";
@@ -707,10 +699,6 @@ void SceneShaderForwardClustered::init(const String p_defines) {
actions.render_mode_defines["specular_schlick_ggx"] = "#define SPECULAR_SCHLICK_GGX\n";
- actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; // linear filter with mipmaps
- actions.custom_samplers["DEPTH_TEXTURE"] = "material_samplers[3]";
- actions.custom_samplers["NORMAL_ROUGHNESS_TEXTURE"] = "material_samplers[1]"; // linear filter
-
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";
diff --git a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
index 78d29e2a41..5d4e3c1ac1 100644
--- a/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/render_forward_mobile.cpp
@@ -251,7 +251,7 @@ RID RenderForwardMobile::RenderBufferDataForwardMobile::get_color_fbs(Framebuffe
Size2i target_size = render_buffers->get_target_size();
Size2i internal_size = render_buffers->get_internal_size();
- // can't do our blit pass if resolutions don't match
+ // can't do our blit pass if resolutions don't match, this should already have been checked.
ERR_FAIL_COND_V(target_size != internal_size, RID());
// - opaque pass
@@ -632,7 +632,7 @@ void RenderForwardMobile::_pre_opaque_render(RenderDataRD *p_render_data) {
uint32_t directional_light_count = 0;
uint32_t positional_light_count = 0;
light_storage->update_light_buffers(p_render_data, *p_render_data->lights, p_render_data->scene_data->cam_transform, p_render_data->shadow_atlas, using_shadows, directional_light_count, positional_light_count, p_render_data->directional_light_soft_shadows);
- texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform.affine_inverse());
+ texture_storage->update_decal_buffer(*p_render_data->decals, p_render_data->scene_data->cam_transform);
p_render_data->directional_light_count = directional_light_count;
}
@@ -715,20 +715,26 @@ void RenderForwardMobile::_render_scene(RenderDataRD *p_render_data, const Color
// setup rendering to render buffer
screen_size = p_render_data->render_buffers->get_internal_size();
- if (rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES).is_null()) {
- // can't do blit subpass
+ if (rb->get_scaling_3d_mode() != RS::VIEWPORT_SCALING_3D_MODE_OFF) {
+ // can't do blit subpass because we're scaling
using_subpass_post_process = false;
} else if (p_render_data->environment.is_valid() && (environment_get_glow_enabled(p_render_data->environment) || RSG::camera_attributes->camera_attributes_uses_auto_exposure(p_render_data->camera_attributes) || RSG::camera_attributes->camera_attributes_uses_dof(p_render_data->camera_attributes))) {
- // can't do blit subpass
+ // can't do blit subpass because we're using post processes
using_subpass_post_process = false;
}
if (scene_state.used_screen_texture || scene_state.used_depth_texture) {
- // can't use our last two subpasses
+ // can't use our last two subpasses because we're reading from screen texture or depth texture
using_subpass_transparent = false;
using_subpass_post_process = false;
}
+ // We do this last because our get_color_fbs creates and caches the framebuffer if we need it.
+ if (using_subpass_post_process && rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES).is_null()) {
+ // can't do blit subpass because we don't have all subpasses
+ using_subpass_post_process = false;
+ }
+
if (using_subpass_post_process) {
// all as subpasses
framebuffer = rb_data->get_color_fbs(RenderBufferDataForwardMobile::FB_CONFIG_FOUR_SUBPASSES);
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
index ee4c8001eb..3d1d78c63d 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.cpp
@@ -46,7 +46,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
valid = false;
ubo_size = 0;
uniforms.clear();
- uses_screen_texture = false;
if (code.is_empty()) {
return; //just invalid, but no error
@@ -74,9 +73,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
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;
@@ -121,9 +117,6 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
// 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_ROUGHNESS_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;
@@ -152,6 +145,10 @@ void SceneShaderForwardMobile::ShaderData::set_code(const String &p_code) {
depth_test = DepthTest(depth_testi);
uses_vertex_time = gen_code.uses_vertex_time;
uses_fragment_time = gen_code.uses_fragment_time;
+ uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
+ uses_depth_texture = gen_code.uses_depth_texture;
+ uses_normal_texture = gen_code.uses_normal_roughness_texture;
#if 0
print_line("**compiling shader:");
@@ -498,9 +495,6 @@ void SceneShaderForwardMobile::init(const String p_defines) {
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"] = "fog";
@@ -565,7 +559,6 @@ void SceneShaderForwardMobile::init(const String p_defines) {
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";
diff --git a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
index 1f92697ecc..6f1f00cedc 100644
--- a/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
+++ b/servers/rendering/renderer_rd/forward_mobile/scene_shader_forward_mobile.h
@@ -128,6 +128,7 @@ public:
bool uses_screen_texture = false;
bool uses_depth_texture = false;
bool uses_normal_texture = false;
+ bool uses_screen_texture_mipmaps = false;
bool uses_time = false;
bool uses_vertex_time = false;
bool uses_fragment_time = false;
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index 0c6dcb553a..638fe44266 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -455,7 +455,7 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
light_count++;
- if (light_count == MAX_LIGHTS_PER_ITEM) {
+ if (light_count == MAX_LIGHTS_PER_ITEM - 1) {
break;
}
}
@@ -525,10 +525,12 @@ void RendererCanvasRenderRD::_render_item(RD::DrawListID p_draw_list, RID p_rend
if (rect->flags & CANVAS_RECT_FLIP_H) {
src_rect.size.x *= -1;
+ push_constant.flags |= FLAGS_FLIP_H;
}
if (rect->flags & CANVAS_RECT_FLIP_V) {
src_rect.size.y *= -1;
+ push_constant.flags |= FLAGS_FLIP_V;
}
if (rect->flags & CANVAS_RECT_TRANSPOSE) {
@@ -2034,7 +2036,6 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
actions.render_mode_values["blend_premul_alpha"] = Pair<int *, int>(&blend_mode, BLEND_MODE_PMALPHA);
actions.render_mode_values["blend_disabled"] = Pair<int *, int>(&blend_mode, BLEND_MODE_DISABLED);
- actions.usage_flag_pointers["SCREEN_TEXTURE"] = &uses_screen_texture;
actions.usage_flag_pointers["texture_sdf"] = &uses_sdf;
actions.usage_flag_pointers["TIME"] = &uses_time;
@@ -2046,6 +2047,7 @@ void RendererCanvasRenderRD::CanvasShaderData::set_code(const String &p_code) {
ERR_FAIL_COND_MSG(err != OK, "Shader compilation failed.");
uses_screen_texture_mipmaps = gen_code.uses_screen_texture_mipmaps;
+ uses_screen_texture = gen_code.uses_screen_texture;
if (version.is_null()) {
version = canvas_singleton->shader.canvas_shader.version_create();
@@ -2423,7 +2425,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.renames["SPECULAR_SHININESS_TEXTURE"] = "specular_texture";
actions.renames["SPECULAR_SHININESS"] = "specular_shininess";
actions.renames["SCREEN_UV"] = "screen_uv";
- actions.renames["SCREEN_TEXTURE"] = "screen_texture";
actions.renames["SCREEN_PIXEL_SIZE"] = "canvas_data.screen_pixel_size";
actions.renames["FRAGCOORD"] = "gl_FragCoord";
actions.renames["POINT_COORD"] = "gl_PointCoord";
@@ -2444,7 +2445,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.renames["screen_uv_to_sdf"] = "screen_uv_to_sdf";
actions.usage_defines["COLOR"] = "#define COLOR_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["SCREEN_PIXEL_SIZE"] = "@SCREEN_UV";
actions.usage_defines["NORMAL"] = "#define NORMAL_USED\n";
@@ -2459,7 +2459,6 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.custom_samplers["TEXTURE"] = "texture_sampler";
actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
actions.custom_samplers["SPECULAR_SHININESS_TEXTURE"] = "texture_sampler";
- actions.custom_samplers["SCREEN_TEXTURE"] = "material_samplers[3]"; //mipmap and filter for screen texture
actions.sampler_array_name = "material_samplers";
actions.base_texture_binding_index = 1;
actions.texture_layout_set = MATERIAL_UNIFORM_SET;
@@ -2632,8 +2631,10 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
if (c.a > 0.0001) {
c.rgb /= c.a;
@@ -2657,8 +2658,10 @@ void fragment() {
shader_type canvas_item;
+uniform sampler2D screen_texture : hint_screen_texture, repeat_disable, filter_nearest;
+
void fragment() {
- vec4 c = textureLod(SCREEN_TEXTURE, SCREEN_UV, 0.0);
+ vec4 c = textureLod(screen_texture, SCREEN_UV, 0.0);
COLOR.rgb = c.rgb;
}
)");
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
index 266083fc49..7dea4a1a65 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.h
@@ -86,6 +86,9 @@ class RendererCanvasRenderRD : public RendererCanvasRender {
FLAGS_USE_MSDF = (1 << 28),
FLAGS_USE_LCD = (1 << 29),
+
+ FLAGS_FLIP_H = (1 << 30),
+ FLAGS_FLIP_V = (1 << 31),
};
enum {
diff --git a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
index 1d45db8eaf..2a87c4fa8d 100644
--- a/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_scene_render_rd.cpp
@@ -539,7 +539,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
tonemap.view_count = rb->get_view_count();
RID dest_fb;
- if (fsr && can_use_effects && (internal_size.x != target_size.x || internal_size.y != target_size.y)) {
+ if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) {
// If we use FSR to upscale we need to write our result into an intermediate buffer.
// Note that this is cached so we only create the texture the first time.
RID dest_texture = rb->create_texture(SNAME("Tonemapper"), SNAME("destination"), _render_buffers_get_color_format(), RD::TEXTURE_USAGE_SAMPLING_BIT | RD::TEXTURE_USAGE_STORAGE_BIT | RD::TEXTURE_USAGE_COLOR_ATTACHMENT_BIT);
@@ -556,10 +556,7 @@ void RendererSceneRenderRD::_render_buffers_post_process_and_tonemap(const Rende
RD::get_singleton()->draw_command_end_label();
}
- if (fsr && can_use_effects && (internal_size.x != target_size.x || internal_size.y != target_size.y)) {
- // TODO Investigate? Does this work? We never write into our render target and we've already done so up above in our tonemapper.
- // I think FSR should either work before our tonemapper or as an alternative of our tonemapper.
-
+ if (fsr && can_use_effects && rb->get_scaling_3d_mode() == RS::VIEWPORT_SCALING_3D_MODE_FSR) {
RD::get_singleton()->draw_command_begin_label("FSR 1.0 Upscale");
for (uint32_t v = 0; v < rb->get_view_count(); v++) {
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index eb5f68849e..1fb8b28b15 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -502,6 +502,12 @@ void main() {
if (normal_used || (using_light && bool(draw_data.flags & FLAGS_DEFAULT_NORMAL_MAP_USED))) {
normal.xy = texture(sampler2D(normal_texture, texture_sampler), uv).xy * vec2(2.0, -2.0) - vec2(1.0, -1.0);
+ if (bool(draw_data.flags & FLAGS_FLIP_H)) {
+ normal.x = -normal.x;
+ }
+ if (bool(draw_data.flags & FLAGS_FLIP_V)) {
+ normal.y = -normal.y;
+ }
normal.z = sqrt(1.0 - dot(normal.xy, normal.xy));
normal_used = true;
} else {
diff --git a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
index 1b627a3e81..a904f4e0a6 100644
--- a/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas_uniforms_inc.glsl
@@ -27,6 +27,9 @@
#define FLAGS_USE_MSDF (1 << 28)
#define FLAGS_USE_LCD (1 << 29)
+#define FLAGS_FLIP_H (1 << 30)
+#define FLAGS_FLIP_V (1 << 31)
+
#define SAMPLER_NEAREST_CLAMP 0
#define SAMPLER_LINEAR_CLAMP 1
#define SAMPLER_NEAREST_WITH_MIPMAPS_CLAMP 2
@@ -134,7 +137,7 @@ layout(set = 0, binding = 4) uniform texture2D shadow_atlas_texture;
layout(set = 0, binding = 5) uniform sampler shadow_sampler;
-layout(set = 0, binding = 6) uniform texture2D screen_texture;
+layout(set = 0, binding = 6) uniform texture2D color_buffer;
layout(set = 0, binding = 7) uniform texture2D sdf_texture;
layout(set = 0, binding = 8) uniform sampler material_samplers[12];
diff --git a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
index 673fc25595..33e35a7a64 100644
--- a/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/light_storage.cpp
@@ -568,8 +568,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
r_directional_light_count = 0;
r_positional_light_count = 0;
- Plane camera_plane(-p_camera_transform.basis.get_column(Vector3::AXIS_Z).normalized(), p_camera_transform.origin);
-
omni_light_count = 0;
spot_light_count = 0;
@@ -720,7 +718,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
}
Transform3D light_transform = light_instance->transform;
- const real_t distance = camera_plane.distance_to(light_transform.origin);
+ const real_t distance = p_camera_transform.origin.distance_to(light_transform.origin);
if (light->distance_fade) {
const float fade_begin = light->distance_fade_begin;
@@ -745,7 +743,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
}
Transform3D light_transform = light_instance->transform;
- const real_t distance = camera_plane.distance_to(light_transform.origin);
+ const real_t distance = p_camera_transform.origin.distance_to(light_transform.origin);
if (light->distance_fade) {
const float fade_begin = light->distance_fade_begin;
@@ -787,6 +785,7 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
RS::LightType type = (i < omni_light_count) ? RS::LIGHT_OMNI : RS::LIGHT_SPOT;
LightInstance *light_instance = (i < omni_light_count) ? omni_light_sort[index].light_instance : spot_light_sort[index].light_instance;
Light *light = (i < omni_light_count) ? omni_light_sort[index].light : spot_light_sort[index].light;
+ real_t distance = (i < omni_light_count) ? omni_light_sort[index].depth : spot_light_sort[index].depth;
if (using_forward_ids) {
forward_id_storage->map_forward_id(type == RS::LIGHT_OMNI ? RendererRD::FORWARD_ID_TYPE_OMNI_LIGHT : RendererRD::FORWARD_ID_TYPE_SPOT_LIGHT, light_instance->forward_id, index);
@@ -803,7 +802,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
float fade_begin = 0.0;
float fade_shadow = 0.0;
float fade_length = 0.0;
- real_t distance = 0.0;
float fade = 1.0;
float shadow_opacity_fade = 1.0;
@@ -811,7 +809,6 @@ void LightStorage::update_light_buffers(RenderDataRD *p_render_data, const Paged
fade_begin = light->distance_fade_begin;
fade_shadow = light->distance_fade_shadow;
fade_length = light->distance_fade_length;
- distance = camera_plane.distance_to(light_transform.origin);
// Use `smoothstep()` to make opacity changes more gradual and less noticeable to the player.
if (distance > fade_begin) {
diff --git a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
index 66ae1e8d1a..d631a89dd2 100644
--- a/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/material_storage.cpp
@@ -2685,6 +2685,14 @@ void MaterialStorage::material_free(RID p_rid) {
Material *material = material_owner.get_or_null(p_rid);
ERR_FAIL_COND(!material);
+ // Need to clear texture arrays to prevent spin locking of their RID's.
+ // This happens when the app is being closed.
+ for (KeyValue<StringName, Variant> &E : material->params) {
+ if (E.value.get_type() == Variant::ARRAY) {
+ Array(E.value).clear();
+ }
+ }
+
material_set_shader(p_rid, RID()); //clean up shader
material->dependency.deleted_notify(p_rid);
diff --git a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
index 6401d0f5d0..e4149f6bbd 100644
--- a/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/particles_storage.cpp
@@ -1415,7 +1415,6 @@ void ParticlesStorage::update_particles() {
}
bool zero_time_scale = Engine::get_singleton()->get_time_scale() <= 0.0;
- bool updated = false;
if (particles->clear && particles->pre_process_time > 0.0) {
double frame_time;
@@ -1430,7 +1429,6 @@ void ParticlesStorage::update_particles() {
while (todo >= 0) {
_particles_process(particles, frame_time);
todo -= frame_time;
- updated = true;
}
}
@@ -1452,10 +1450,9 @@ void ParticlesStorage::update_particles() {
}
double todo = particles->frame_remainder + delta;
- while (todo >= frame_time || (particles->clear && !updated)) {
+ while (todo >= frame_time || particles->clear) {
_particles_process(particles, frame_time);
todo -= decr;
- updated = true;
}
particles->frame_remainder = todo;
@@ -1463,16 +1460,16 @@ void ParticlesStorage::update_particles() {
} else {
if (zero_time_scale) {
_particles_process(particles, 0.0);
- updated = true;
} else {
_particles_process(particles, RendererCompositorRD::singleton->get_frame_delta_time());
- updated = true;
}
}
- //copy particles to instance buffer
+ // Ensure that memory is initialized (the code above should ensure that _particles_process is always called at least once upon clearing).
+ DEV_ASSERT(!particles->clear);
- if (updated && particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
+ // Copy particles to instance buffer.
+ if (particles->draw_order != RS::PARTICLES_DRAW_ORDER_VIEW_DEPTH && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD && particles->transform_align != RS::PARTICLES_TRANSFORM_ALIGN_Z_BILLBOARD_Y_TO_VELOCITY) {
//does not need view dependent operation, do copy here
ParticlesShader::CopyPushConstant copy_push_constant;
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
index d67a848a40..31377a10a0 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.cpp
@@ -96,7 +96,7 @@ void RenderSceneBuffersRD::cleanup() {
named_textures.clear();
}
-void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
RendererRD::TextureStorage *texture_storage = RendererRD::TextureStorage::get_singleton();
RendererRD::MaterialStorage *material_storage = RendererRD::MaterialStorage::get_singleton();
@@ -104,12 +104,7 @@ void RenderSceneBuffersRD::configure(RID p_render_target, const Size2i p_interna
target_size = p_target_size;
internal_size = p_internal_size;
-
- // FIXME, right now we do this because only our clustered renderer supports FSR upscale
- // this does mean that with linear upscale if we use subpasses, we could get into trouble.
- if (!can_be_storage) {
- internal_size = target_size;
- }
+ scaling_3d_mode = p_scaling_3d_mode;
if (p_use_taa) {
// Use negative mipmap LOD bias when TAA is enabled to compensate for loss of sharpness.
@@ -193,6 +188,7 @@ void RenderSceneBuffersRD::configure_for_reflections(const Size2i p_reflection_s
target_size = p_reflection_size;
internal_size = p_reflection_size;
render_target = RID();
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
fsr_sharpness = 0.0;
msaa_3d = RS::VIEWPORT_MSAA_DISABLED;
screen_space_aa = RS::VIEWPORT_SCREEN_SPACE_AA_DISABLED;
diff --git a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
index ff946f410f..dc849fd56a 100644
--- a/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
+++ b/servers/rendering/renderer_rd/storage_rd/render_scene_buffers_rd.h
@@ -73,6 +73,7 @@ private:
// The internal size of the textures we render 3D to in case we render at a lower resolution and upscale
Size2i internal_size = Size2i(0, 0);
+ RS::ViewportScaling3DMode scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
float fsr_sharpness = 0.2f;
// Aliassing settings
@@ -139,7 +140,7 @@ public:
void set_vrs(RendererRD::VRS *p_vrs) { vrs = p_vrs; }
void cleanup();
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) override;
void configure_for_reflections(const Size2i p_reflection_size);
virtual void set_fsr_sharpness(float p_fsr_sharpness) override;
virtual void set_texture_mipmap_bias(float p_texture_mipmap_bias) override;
@@ -172,6 +173,7 @@ public:
_FORCE_INLINE_ uint32_t get_view_count() const { return view_count; }
_FORCE_INLINE_ Size2i get_internal_size() const { return internal_size; }
_FORCE_INLINE_ Size2i get_target_size() const { return target_size; }
+ _FORCE_INLINE_ RS::ViewportScaling3DMode get_scaling_3d_mode() const { return scaling_3d_mode; }
_FORCE_INLINE_ float get_fsr_sharpness() const { return fsr_sharpness; }
_FORCE_INLINE_ RS::ViewportMSAA get_msaa_3d() const { return msaa_3d; }
_FORCE_INLINE_ RS::ViewportScreenSpaceAA get_screen_space_aa() const { return screen_space_aa; }
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
index 06fda8fa9e..e8d9f486bb 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.cpp
@@ -2206,6 +2206,12 @@ void TextureStorage::decal_instance_set_transform(RID p_decal_instance, const Tr
di->transform = p_transform;
}
+void TextureStorage::decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) {
+ DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
+ ERR_FAIL_COND(!di);
+ di->sorting_offset = p_sorting_offset;
+}
+
/* DECAL DATA API */
void TextureStorage::free_decal_data() {
@@ -2233,7 +2239,7 @@ void TextureStorage::set_max_decals(const uint32_t p_max_decals) {
decal_buffer = RD::get_singleton()->storage_buffer_create(decal_buffer_size);
}
-void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform) {
+void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_xform) {
ForwardIDStorage *forward_id_storage = ForwardIDStorage::get_singleton();
Transform3D uv_xform;
@@ -2257,7 +2263,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const
Transform3D xform = decal_instance->transform;
- real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+ real_t distance = p_camera_xform.origin.distance_to(xform.origin);
if (decal->distance_fade) {
float fade_begin = decal->distance_fade_begin;
@@ -2272,7 +2278,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const
decal_sort[decal_count].decal_instance = decal_instance;
decal_sort[decal_count].decal = decal;
- decal_sort[decal_count].depth = distance;
+ decal_sort[decal_count].depth = distance - decal_instance->sorting_offset;
decal_count++;
}
@@ -2292,11 +2298,10 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const
decal_instance->cull_mask = decal->cull_mask;
- Transform3D xform = decal_instance->transform;
float fade = 1.0;
if (decal->distance_fade) {
- const real_t distance = -p_camera_inverse_xform.xform(xform.origin).z;
+ const real_t distance = decal_sort[i].depth + decal_instance->sorting_offset;
const float fade_begin = decal->distance_fade_begin;
const float fade_length = decal->distance_fade_length;
@@ -2312,11 +2317,16 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const
Transform3D scale_xform;
scale_xform.basis.scale(decal_extents);
- Transform3D to_decal_xform = (p_camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse();
+
+ Transform3D xform = decal_instance->transform;
+
+ Transform3D camera_inverse_xform = p_camera_xform.affine_inverse();
+
+ Transform3D to_decal_xform = (camera_inverse_xform * xform * scale_xform * uv_xform).affine_inverse();
MaterialStorage::store_transform(to_decal_xform, dd.xform);
Vector3 normal = xform.basis.get_column(Vector3::AXIS_Y).normalized();
- normal = p_camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
+ normal = camera_inverse_xform.basis.xform(normal); //camera is normalized, so fine
dd.normal[0] = normal.x;
dd.normal[1] = normal.y;
@@ -2350,7 +2360,7 @@ void TextureStorage::update_decal_buffer(const PagedArray<RID> &p_decals, const
dd.normal_rect[2] = rect.size.x;
dd.normal_rect[3] = rect.size.y;
- Basis normal_xform = p_camera_inverse_xform.basis * xform.basis.orthonormalized();
+ Basis normal_xform = camera_inverse_xform.basis * xform.basis.orthonormalized();
MaterialStorage::store_basis_3x4(normal_xform, dd.normal_xform);
} else {
dd.normal_rect[0] = 0;
diff --git a/servers/rendering/renderer_rd/storage_rd/texture_storage.h b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
index 1558342c3b..ea0df0b459 100644
--- a/servers/rendering/renderer_rd/storage_rd/texture_storage.h
+++ b/servers/rendering/renderer_rd/storage_rd/texture_storage.h
@@ -258,6 +258,7 @@ private:
struct DecalInstance {
RID decal;
Transform3D transform;
+ float sorting_offset = 0.0;
uint32_t cull_mask = 0;
RendererRD::ForwardID forward_id = -1;
};
@@ -646,6 +647,7 @@ public:
virtual RID decal_instance_create(RID p_decal) override;
virtual void decal_instance_free(RID p_decal_instance) override;
virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) override;
+ virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) override;
_FORCE_INLINE_ RID decal_instance_get_base(RID p_decal_instance) const {
DecalInstance *di = decal_instance_owner.get_or_null(p_decal_instance);
@@ -677,7 +679,7 @@ public:
void free_decal_data();
void set_max_decals(const uint32_t p_max_decals);
RID get_decal_buffer() { return decal_buffer; }
- void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_inverse_xform);
+ void update_decal_buffer(const PagedArray<RID> &p_decals, const Transform3D &p_camera_xform);
/* RENDER TARGET API */
diff --git a/servers/rendering/renderer_scene_cull.cpp b/servers/rendering/renderer_scene_cull.cpp
index 2ea813aab0..de417082f5 100644
--- a/servers/rendering/renderer_scene_cull.cpp
+++ b/servers/rendering/renderer_scene_cull.cpp
@@ -694,6 +694,7 @@ void RendererSceneCull::instance_set_base(RID p_instance, RID p_base) {
instance->base_data = decal;
decal->instance = RSG::texture_storage->decal_instance_create(p_base);
+ RSG::texture_storage->decal_instance_set_sorting_offset(decal->instance, instance->sorting_offset);
} break;
case RS::INSTANCE_LIGHTMAP: {
InstanceLightmapData *lightmap_data = memnew(InstanceLightmapData);
@@ -748,6 +749,10 @@ void RendererSceneCull::instance_set_scenario(RID p_instance, RID p_scenario) {
switch (instance->base_type) {
case RS::INSTANCE_LIGHT: {
InstanceLightData *light = static_cast<InstanceLightData *>(instance->base_data);
+ if (instance->visible && RSG::light_storage->light_get_type(instance->base) != RS::LIGHT_DIRECTIONAL && light->bake_mode == RS::LIGHT_BAKE_DYNAMIC) {
+ instance->scenario->dynamic_lights.erase(light->instance);
+ }
+
#ifdef DEBUG_ENABLED
if (light->geometries.size()) {
ERR_PRINT("BUG, indexing did not unpair geometries from light.");
@@ -867,6 +872,9 @@ void RendererSceneCull::instance_set_pivot_data(RID p_instance, float p_sorting_
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(instance->base_data);
ERR_FAIL_NULL(geom->geometry_instance);
geom->geometry_instance->set_pivot_data(p_sorting_offset, p_use_aabb_center);
+ } else if (instance->base_type == RS::INSTANCE_DECAL && instance->base_data) {
+ InstanceDecalData *decal = static_cast<InstanceDecalData *>(instance->base_data);
+ RSG::texture_storage->decal_instance_set_sorting_offset(decal->instance, instance->sorting_offset);
}
}
@@ -2820,7 +2828,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
InstanceGeometryData *geom = static_cast<InstanceGeometryData *>(idata.instance->base_data);
ERR_FAIL_NULL(geom->geometry_instance);
+ cull_data.cull->lock.lock();
geom->geometry_instance->set_softshadow_projector_pairing(geom->softshadow_count > 0, geom->projector_count > 0);
+ cull_data.cull->lock.unlock();
idata.flags &= ~uint32_t(InstanceData::FLAG_GEOM_PROJECTOR_SOFTSHADOW_DIRTY);
}
@@ -2887,7 +2897,9 @@ void RendererSceneCull::_scene_cull(CullData &cull_data, InstanceCullResult &cul
sh[j] = sh[j].lerp(target_sh[j], MIN(1.0, lightmap_probe_update_speed));
}
ERR_FAIL_NULL(geom->geometry_instance);
+ cull_data.cull->lock.lock();
geom->geometry_instance->set_lightmap_capture(sh);
+ cull_data.cull->lock.unlock();
idata.instance->last_frame_pass = frame_number;
}
diff --git a/servers/rendering/renderer_scene_render.cpp b/servers/rendering/renderer_scene_render.cpp
index e2e6ea5aa2..a389e3e767 100644
--- a/servers/rendering/renderer_scene_render.cpp
+++ b/servers/rendering/renderer_scene_render.cpp
@@ -84,7 +84,7 @@ void RendererSceneRender::CameraData::set_multiview_camera(uint32_t p_view_count
Transform3D main_transform_inv = main_transform.inverse();
// 5. figure out far plane, this could use some improvement, we may have our far plane too close like this, not sure if this matters
- Vector3 far_center = (planes[0][Projection::PLANE_FAR].center() + planes[1][Projection::PLANE_FAR].center()) * 0.5;
+ Vector3 far_center = (planes[0][Projection::PLANE_FAR].get_center() + planes[1][Projection::PLANE_FAR].get_center()) * 0.5;
Plane far(-z, far_center);
/////////////////////////////////////////////////////////////////////////////
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 05a3fccf1c..3886f5b379 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -115,9 +115,8 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
if (p_viewport->size.width == 0 || p_viewport->size.height == 0) {
p_viewport->render_buffers.unref();
} else {
- const float scaling_3d_scale = p_viewport->scaling_3d_scale;
+ float scaling_3d_scale = p_viewport->scaling_3d_scale;
RS::ViewportScaling3DMode scaling_3d_mode = p_viewport->scaling_3d_mode;
- bool scaling_enabled = true;
if ((scaling_3d_mode == RS::VIEWPORT_SCALING_3D_MODE_FSR) && (scaling_3d_scale > 1.0)) {
// FSR is not designed for downsampling.
@@ -133,7 +132,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
}
if (scaling_3d_scale == 1.0) {
- scaling_enabled = false;
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
}
int width;
@@ -141,36 +140,37 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
int render_width;
int render_height;
- if (scaling_enabled) {
- switch (scaling_3d_mode) {
- case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR:
- // Clamp 3D rendering resolution to reasonable values supported on most hardware.
- // This prevents freezing the engine or outright crashing on lower-end GPUs.
- width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384);
- height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384);
- render_width = width;
- render_height = height;
- break;
- case RS::VIEWPORT_SCALING_3D_MODE_FSR:
- width = p_viewport->size.width;
- height = p_viewport->size.height;
- render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling)
- render_height = MAX(height * scaling_3d_scale, 1.0);
- break;
- default:
- // This is an unknown mode.
- WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode));
- width = p_viewport->size.width;
- height = p_viewport->size.height;
- render_width = width;
- render_height = height;
- break;
- }
- } else {
- width = p_viewport->size.width;
- height = p_viewport->size.height;
- render_width = width;
- render_height = height;
+ switch (scaling_3d_mode) {
+ case RS::VIEWPORT_SCALING_3D_MODE_BILINEAR:
+ // Clamp 3D rendering resolution to reasonable values supported on most hardware.
+ // This prevents freezing the engine or outright crashing on lower-end GPUs.
+ width = CLAMP(p_viewport->size.width * scaling_3d_scale, 1, 16384);
+ height = CLAMP(p_viewport->size.height * scaling_3d_scale, 1, 16384);
+ render_width = width;
+ render_height = height;
+ break;
+ case RS::VIEWPORT_SCALING_3D_MODE_FSR:
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = MAX(width * scaling_3d_scale, 1.0); // width / (width * scaling)
+ render_height = MAX(height * scaling_3d_scale, 1.0);
+ break;
+ case RS::VIEWPORT_SCALING_3D_MODE_OFF:
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = width;
+ render_height = height;
+ break;
+ default:
+ // This is an unknown mode.
+ WARN_PRINT_ONCE(vformat("Unknown scaling mode: %d. Disabling 3D resolution scaling.", scaling_3d_mode));
+ scaling_3d_mode = RS::VIEWPORT_SCALING_3D_MODE_OFF;
+ scaling_3d_scale = 1.0;
+ width = p_viewport->size.width;
+ height = p_viewport->size.height;
+ render_width = width;
+ render_height = height;
+ break;
}
p_viewport->internal_size = Size2(render_width, render_height);
@@ -179,7 +179,7 @@ void RendererViewport::_configure_3d_render_buffers(Viewport *p_viewport) {
// to compensate for the loss of sharpness.
const float texture_mipmap_bias = log2f(MIN(scaling_3d_scale, 1.0)) + p_viewport->texture_mipmap_bias;
- p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count);
+ p_viewport->render_buffers->configure(p_viewport->render_target, Size2i(render_width, render_height), Size2(width, height), scaling_3d_mode, p_viewport->fsr_sharpness, texture_mipmap_bias, p_viewport->msaa_3d, p_viewport->screen_space_aa, p_viewport->use_taa, p_viewport->use_debanding, p_viewport->view_count);
}
}
}
@@ -1138,6 +1138,7 @@ void RendererViewport::viewport_set_screen_space_aa(RID p_viewport, RS::Viewport
void RendererViewport::viewport_set_use_taa(RID p_viewport, bool p_use_taa) {
Viewport *viewport = viewport_owner.get_or_null(p_viewport);
ERR_FAIL_COND(!viewport);
+ ERR_FAIL_COND_EDMSG(OS::get_singleton()->get_current_rendering_method() != "forward_plus", "TAA is only available when using the Forward+ renderer.");
if (viewport->use_taa == p_use_taa) {
return;
diff --git a/servers/rendering/rendering_device_binds.cpp b/servers/rendering/rendering_device_binds.cpp
index 5967835d03..3678b70254 100644
--- a/servers/rendering/rendering_device_binds.cpp
+++ b/servers/rendering/rendering_device_binds.cpp
@@ -31,6 +31,8 @@
#include "rendering_device_binds.h"
Error RDShaderFile::parse_versions_from_text(const String &p_text, const String p_defines, OpenIncludeFunction p_include_func, void *p_include_func_userdata) {
+ ERR_FAIL_NULL_V(RenderingDevice::get_singleton(), ERR_UNAVAILABLE);
+
Vector<String> lines = p_text.split("\n");
bool reading_versions = false;
diff --git a/servers/rendering/rendering_server_default.h b/servers/rendering/rendering_server_default.h
index d053c60b85..8ac522bafe 100644
--- a/servers/rendering/rendering_server_default.h
+++ b/servers/rendering/rendering_server_default.h
@@ -854,7 +854,7 @@ public:
FUNC8(canvas_item_add_msdf_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &, int, float, float)
FUNC5(canvas_item_add_lcd_texture_rect_region, RID, const Rect2 &, RID, const Rect2 &, const Color &)
FUNC10(canvas_item_add_nine_patch, RID, const Rect2 &, const Rect2 &, RID, const Vector2 &, const Vector2 &, NinePatchAxisMode, NinePatchAxisMode, bool, const Color &)
- FUNC6(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID, float)
+ FUNC5(canvas_item_add_primitive, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
FUNC5(canvas_item_add_polygon, RID, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, RID)
FUNC9(canvas_item_add_triangle_array, RID, const Vector<int> &, const Vector<Point2> &, const Vector<Color> &, const Vector<Point2> &, const Vector<int> &, const Vector<float> &, RID, int)
FUNC5(canvas_item_add_mesh, RID, const RID &, const Transform2D &, const Color &, RID)
diff --git a/servers/rendering/shader_compiler.cpp b/servers/rendering/shader_compiler.cpp
index 626da90168..68542f32af 100644
--- a/servers/rendering/shader_compiler.cpp
+++ b/servers/rendering/shader_compiler.cpp
@@ -909,9 +909,6 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (p_default_actions.renames.has(vnode->name)) {
code = p_default_actions.renames[vnode->name];
- if (vnode->name == "SCREEN_TEXTURE") {
- r_gen_code.uses_screen_texture_mipmaps = true;
- }
} else {
if (shader->uniforms.has(vnode->name)) {
//its a uniform!
@@ -919,29 +916,22 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
if (u.texture_order >= 0) {
StringName name = vnode->name;
if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) {
- name = "SCREEN_TEXTURE";
+ name = "color_buffer";
if (u.filter >= ShaderLanguage::FILTER_NEAREST_MIPMAP) {
r_gen_code.uses_screen_texture_mipmaps = true;
}
+ r_gen_code.uses_screen_texture = true;
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) {
- name = "NORMAL_ROUGHNESS_TEXTURE";
+ name = "normal_roughness_buffer";
+ r_gen_code.uses_normal_roughness_texture = true;
} else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_DEPTH_TEXTURE) {
- name = "DEPTH_TEXTURE";
+ name = "depth_buffer";
+ r_gen_code.uses_depth_texture = true;
} else {
name = _mkid(vnode->name); //texture, use as is
}
- if (p_default_actions.renames.has(name)) {
- code = p_default_actions.renames[name];
- } else {
- code = name;
- }
-
- if (p_actions.usage_flag_pointers.has(name) && !used_flag_pointers.has(name)) {
- *p_actions.usage_flag_pointers[name] = true;
- used_flag_pointers.insert(name);
- }
-
+ code = name;
} else {
//a scalar or vector
if (u.scope == ShaderLanguage::ShaderNode::Uniform::SCOPE_GLOBAL) {
@@ -1251,16 +1241,20 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
if (correct_texture_uniform) {
- //TODO Needs to detect screen_texture hint as well
- is_screen_texture = (texture_uniform == "SCREEN_TEXTURE");
-
String sampler_name;
+ bool is_normal_roughness_texture = false;
if (actions.custom_samplers.has(texture_uniform)) {
sampler_name = actions.custom_samplers[texture_uniform];
} else {
if (shader->uniforms.has(texture_uniform)) {
- sampler_name = _get_sampler_name(shader->uniforms[texture_uniform].filter, shader->uniforms[texture_uniform].repeat);
+ const ShaderLanguage::ShaderNode::Uniform &u = shader->uniforms[texture_uniform];
+ if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_SCREEN_TEXTURE) {
+ is_screen_texture = true;
+ } else if (u.hint == ShaderLanguage::ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE) {
+ is_normal_roughness_texture = true;
+ }
+ sampler_name = _get_sampler_name(u.filter, u.repeat);
} else {
bool found = false;
@@ -1287,7 +1281,7 @@ String ShaderCompiler::_dump_node_code(const SL::Node *p_node, int p_level, Gene
}
String data_type_name = "";
- if (texture_uniform == "NORMAL_ROUGHNESS_TEXTURE") {
+ if (is_normal_roughness_texture) {
data_type_name = "multiviewSampler";
normal_roughness_texture_used = true;
} else {
@@ -1515,6 +1509,9 @@ Error ShaderCompiler::compile(RS::ShaderMode p_mode, const String &p_code, Ident
r_gen_code.uses_vertex_time = false;
r_gen_code.uses_global_textures = false;
r_gen_code.uses_screen_texture_mipmaps = false;
+ r_gen_code.uses_screen_texture = false;
+ r_gen_code.uses_depth_texture = false;
+ r_gen_code.uses_normal_roughness_texture = false;
used_name_defines.clear();
used_rmode_defines.clear();
diff --git a/servers/rendering/shader_compiler.h b/servers/rendering/shader_compiler.h
index eeb2916160..43bea213da 100644
--- a/servers/rendering/shader_compiler.h
+++ b/servers/rendering/shader_compiler.h
@@ -81,6 +81,9 @@ public:
bool uses_fragment_time;
bool uses_vertex_time;
bool uses_screen_texture_mipmaps;
+ bool uses_screen_texture;
+ bool uses_depth_texture;
+ bool uses_normal_roughness_texture;
};
struct DefaultIdentifierActions {
diff --git a/servers/rendering/shader_language.cpp b/servers/rendering/shader_language.cpp
index 59a2ff66f3..ba7ffda00a 100644
--- a/servers/rendering/shader_language.cpp
+++ b/servers/rendering/shader_language.cpp
@@ -5399,6 +5399,12 @@ ShaderLanguage::Node *ShaderLanguage::_parse_expression(BlockNode *p_block, cons
}
} else {
if (!_find_identifier(p_block, false, p_function_info, identifier, &data_type, &ident_type, &is_const, &array_size, &struct_name)) {
+ if (identifier == "SCREEN_TEXTURE" || identifier == "DEPTH_TEXTURE" || identifier == "NORMAL_ROUGHNESS_TEXTURE") {
+ String name = String(identifier);
+ String name_lower = name.to_lower();
+ _set_error(vformat(RTR("%s has been removed in favor of using hint_%s with a uniform.\nTo continue with minimal code changes add 'uniform sampler2D %s : hint_%s, filter_linear_mipmap;' near the top of your shader."), name, name_lower, name, name_lower));
+ return nullptr;
+ }
_set_error(vformat(RTR("Unknown identifier in expression: '%s'."), String(identifier)));
return nullptr;
}
@@ -8691,14 +8697,17 @@ Error ShaderLanguage::_parse_shader(const HashMap<StringName, FunctionInfo> &p_f
case TK_HINT_SCREEN_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_SCREEN_TEXTURE;
--texture_uniforms;
+ --texture_binding;
} break;
case TK_HINT_NORMAL_ROUGHNESS_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_NORMAL_ROUGHNESS_TEXTURE;
--texture_uniforms;
+ --texture_binding;
} break;
case TK_HINT_DEPTH_TEXTURE: {
new_hint = ShaderNode::Uniform::HINT_DEPTH_TEXTURE;
--texture_uniforms;
+ --texture_binding;
} break;
case TK_FILTER_NEAREST: {
new_filter = FILTER_NEAREST;
diff --git a/servers/rendering/shader_preprocessor.cpp b/servers/rendering/shader_preprocessor.cpp
index 40c8acffe5..ccbf5defa2 100644
--- a/servers/rendering/shader_preprocessor.cpp
+++ b/servers/rendering/shader_preprocessor.cpp
@@ -1081,21 +1081,17 @@ ShaderPreprocessor::Define *ShaderPreprocessor::create_define(const String &p_bo
return define;
}
-void ShaderPreprocessor::clear() {
- if (state_owner && state != nullptr) {
+void ShaderPreprocessor::clear_state() {
+ if (state != nullptr) {
for (const RBMap<String, Define *>::Element *E = state->defines.front(); E; E = E->next()) {
memdelete(E->get());
}
-
- memdelete(state);
+ state->defines.clear();
}
- state_owner = false;
state = nullptr;
}
Error ShaderPreprocessor::preprocess(State *p_state, const String &p_code, String &r_result) {
- clear();
-
output.clear();
state = p_state;
@@ -1242,6 +1238,9 @@ Error ShaderPreprocessor::preprocess(const String &p_code, const String &p_filen
}
}
}
+
+ clear_state();
+
return err;
}
@@ -1273,5 +1272,4 @@ ShaderPreprocessor::ShaderPreprocessor() {
}
ShaderPreprocessor::~ShaderPreprocessor() {
- clear();
}
diff --git a/servers/rendering/shader_preprocessor.h b/servers/rendering/shader_preprocessor.h
index f5902c64ca..6e5533c575 100644
--- a/servers/rendering/shader_preprocessor.h
+++ b/servers/rendering/shader_preprocessor.h
@@ -167,7 +167,6 @@ private:
private:
LocalVector<char32_t> output;
State *state = nullptr;
- bool state_owner = false;
private:
static bool is_char_word(char32_t p_char);
@@ -211,7 +210,7 @@ private:
static Define *create_define(const String &p_body);
- void clear();
+ void clear_state();
Error preprocess(State *p_state, const String &p_code, String &r_result);
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 38dc806370..ba39328b2e 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -138,9 +138,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["AO_LIGHT_AFFECT"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["EMISSION"] = ShaderLanguage::TYPE_VEC3;
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["NORMAL_ROUGHNESS_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
- shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH_TEXTURE"] = constt(ShaderLanguage::TYPE_SAMPLER2D);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["DEPTH"] = ShaderLanguage::TYPE_FLOAT;
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["SCREEN_UV"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_SPATIAL].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
@@ -267,7 +264,6 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["SCREEN_PIXEL_SIZE"] = constt(ShaderLanguage::TYPE_VEC2);
shader_modes[RS::SHADER_CANVAS_ITEM].functions["fragment"].built_ins["POINT_COORD"] = constt(ShaderLanguage::TYPE_VEC2);
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;
diff --git a/servers/rendering/storage/render_scene_buffers.cpp b/servers/rendering/storage/render_scene_buffers.cpp
index 1320199833..6369139aa6 100644
--- a/servers/rendering/storage/render_scene_buffers.cpp
+++ b/servers/rendering/storage/render_scene_buffers.cpp
@@ -34,8 +34,8 @@ void RenderSceneBuffers::_bind_methods() {
ClassDB::bind_method(D_METHOD("configure", "render_target", "internal_size", "target_size", "fsr_sharpness", "texture_mipmap_bias", "msaa", "screen_space_aa", "use_taa", "use_debanding", "view_count"), &RenderSceneBuffers::configure);
}
-void RenderSceneBuffers::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
- GDVIRTUAL_CALL(_configure, p_render_target, p_internal_size, p_target_size, p_fsr_sharpness, p_texture_mipmap_bias, p_msaa, p_screen_space_aa, p_use_taa, p_use_debanding, p_view_count);
+void RenderSceneBuffers::configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count) {
+ GDVIRTUAL_CALL(_configure, p_render_target, p_internal_size, p_target_size, p_scaling_3d_mode, p_fsr_sharpness, p_texture_mipmap_bias, p_msaa, p_screen_space_aa, p_use_taa, p_use_debanding, p_view_count);
};
void RenderSceneBuffers::set_fsr_sharpness(float p_fsr_sharpness) {
diff --git a/servers/rendering/storage/render_scene_buffers.h b/servers/rendering/storage/render_scene_buffers.h
index 83fc78ca1c..cf96a9f372 100644
--- a/servers/rendering/storage/render_scene_buffers.h
+++ b/servers/rendering/storage/render_scene_buffers.h
@@ -40,7 +40,7 @@ class RenderSceneBuffers : public RefCounted {
protected:
static void _bind_methods();
- GDVIRTUAL10(_configure, RID, Size2i, Size2i, float, float, RS::ViewportMSAA, RenderingServer::ViewportScreenSpaceAA, bool, bool, uint32_t)
+ GDVIRTUAL11(_configure, RID, Size2i, Size2i, RS::ViewportScaling3DMode, float, float, RS::ViewportMSAA, RenderingServer::ViewportScreenSpaceAA, bool, bool, uint32_t)
GDVIRTUAL1(_set_fsr_sharpness, float)
GDVIRTUAL1(_set_texture_mipmap_bias, float)
GDVIRTUAL1(_set_use_debanding, bool)
@@ -49,7 +49,7 @@ public:
RenderSceneBuffers(){};
virtual ~RenderSceneBuffers(){};
- virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count);
+ virtual void configure(RID p_render_target, const Size2i p_internal_size, const Size2i p_target_size, RS::ViewportScaling3DMode p_scaling_3d_mode, float p_fsr_sharpness, float p_texture_mipmap_bias, RS::ViewportMSAA p_msaa_3d, RenderingServer::ViewportScreenSpaceAA p_screen_space_aa, bool p_use_taa, bool p_use_debanding, uint32_t p_view_count);
// for those settings that are unlikely to require buffers to be recreated, we'll add setters
virtual void set_fsr_sharpness(float p_fsr_sharpness);
diff --git a/servers/rendering/storage/texture_storage.h b/servers/rendering/storage/texture_storage.h
index 92149b0064..4c4a84d04e 100644
--- a/servers/rendering/storage/texture_storage.h
+++ b/servers/rendering/storage/texture_storage.h
@@ -127,6 +127,7 @@ public:
virtual RID decal_instance_create(RID p_decal) = 0;
virtual void decal_instance_free(RID p_decal_instance) = 0;
virtual void decal_instance_set_transform(RID p_decal_instance, const Transform3D &p_transform) = 0;
+ virtual void decal_instance_set_sorting_offset(RID p_decal_instance, float p_sorting_offset) = 0;
/* RENDER TARGET */
diff --git a/servers/rendering_server.cpp b/servers/rendering_server.cpp
index 14d8d035e2..675db63b9a 100644
--- a/servers/rendering_server.cpp
+++ b/servers/rendering_server.cpp
@@ -996,6 +996,7 @@ Error RenderingServer::mesh_create_surface_data_from_arrays(SurfaceData *r_surfa
if (index_array_len) {
List<Variant> keys;
p_lods.get_key_list(&keys);
+ keys.sort(); // otherwise lod levels may get skipped
for (const Variant &E : keys) {
float distance = E;
ERR_CONTINUE(distance <= 0.0);
@@ -1826,6 +1827,7 @@ void RenderingServer::_bind_methods() {
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_2D_VERTICES);
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_DYNAMIC_UPDATE);
BIND_BITFIELD_FLAG(ARRAY_FLAG_USE_8_BONE_WEIGHTS);
+ BIND_BITFIELD_FLAG(ARRAY_FLAG_USES_EMPTY_VERTEX_ARRAY);
BIND_ENUM_CONSTANT(PRIMITIVE_POINTS);
BIND_ENUM_CONSTANT(PRIMITIVE_LINES);
@@ -2592,8 +2594,8 @@ void RenderingServer::_bind_methods() {
/* Primitives */
- ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(1.0), DEFVAL(false));
- ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_line", "item", "from", "to", "color", "width", "antialiased"), &RenderingServer::canvas_item_add_line, DEFVAL(-1.0), DEFVAL(false));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_polyline", "item", "points", "colors", "width", "antialiased"), &RenderingServer::canvas_item_add_polyline, DEFVAL(-1.0), DEFVAL(false));
ClassDB::bind_method(D_METHOD("canvas_item_add_rect", "item", "rect", "color"), &RenderingServer::canvas_item_add_rect);
ClassDB::bind_method(D_METHOD("canvas_item_add_circle", "item", "pos", "radius", "color"), &RenderingServer::canvas_item_add_circle);
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect", "item", "rect", "texture", "tile", "modulate", "transpose"), &RenderingServer::canvas_item_add_texture_rect, DEFVAL(false), DEFVAL(Color(1, 1, 1)), DEFVAL(false));
@@ -2601,7 +2603,7 @@ void RenderingServer::_bind_methods() {
ClassDB::bind_method(D_METHOD("canvas_item_add_lcd_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate"), &RenderingServer::canvas_item_add_lcd_texture_rect_region);
ClassDB::bind_method(D_METHOD("canvas_item_add_texture_rect_region", "item", "rect", "texture", "src_rect", "modulate", "transpose", "clip_uv"), &RenderingServer::canvas_item_add_texture_rect_region, DEFVAL(Color(1, 1, 1)), DEFVAL(false), DEFVAL(true));
ClassDB::bind_method(D_METHOD("canvas_item_add_nine_patch", "item", "rect", "source", "texture", "topleft", "bottomright", "x_axis_mode", "y_axis_mode", "draw_center", "modulate"), &RenderingServer::canvas_item_add_nine_patch, DEFVAL(NINE_PATCH_STRETCH), DEFVAL(NINE_PATCH_STRETCH), DEFVAL(true), DEFVAL(Color(1, 1, 1)));
- ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture", "width"), &RenderingServer::canvas_item_add_primitive, DEFVAL(1.0));
+ ClassDB::bind_method(D_METHOD("canvas_item_add_primitive", "item", "points", "colors", "uvs", "texture"), &RenderingServer::canvas_item_add_primitive);
ClassDB::bind_method(D_METHOD("canvas_item_add_polygon", "item", "points", "colors", "uvs", "texture"), &RenderingServer::canvas_item_add_polygon, DEFVAL(Vector<Point2>()), DEFVAL(RID()));
ClassDB::bind_method(D_METHOD("canvas_item_add_triangle_array", "item", "indices", "points", "colors", "uvs", "bones", "weights", "texture", "count"), &RenderingServer::canvas_item_add_triangle_array, DEFVAL(Vector<Point2>()), DEFVAL(Vector<int>()), DEFVAL(Vector<float>()), DEFVAL(RID()), DEFVAL(-1));
ClassDB::bind_method(D_METHOD("canvas_item_add_mesh", "item", "mesh", "transform", "modulate", "texture"), &RenderingServer::canvas_item_add_mesh, DEFVAL(Transform2D()), DEFVAL(Color(1, 1, 1)), DEFVAL(RID()));
@@ -2961,9 +2963,9 @@ void RenderingServer::init() {
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/volume_depth", PROPERTY_HINT_RANGE, "16,512,1"), 64);
GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/environment/volumetric_fog/use_filter", PROPERTY_HINT_ENUM, "No (Faster),Yes (Higher Quality)"), 1);
- GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10);
- GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000);
- GLOBAL_DEF(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/update_iterations_per_frame", PROPERTY_HINT_RANGE, "0,1024,1"), 10);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/spatial_indexer/threaded_cull_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 1000);
+ GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "rendering/limits/forward_renderer/threaded_render_minimum_instances", PROPERTY_HINT_RANGE, "32,65536,1"), 500);
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "rendering/limits/cluster_builder/max_clustered_elements", PROPERTY_HINT_RANGE, "32,8192,1"), 512);
diff --git a/servers/rendering_server.h b/servers/rendering_server.h
index 6efe28a847..231139e9df 100644
--- a/servers/rendering_server.h
+++ b/servers/rendering_server.h
@@ -802,7 +802,8 @@ public:
enum ViewportScaling3DMode {
VIEWPORT_SCALING_3D_MODE_BILINEAR,
VIEWPORT_SCALING_3D_MODE_FSR,
- VIEWPORT_SCALING_3D_MODE_MAX
+ VIEWPORT_SCALING_3D_MODE_MAX,
+ VIEWPORT_SCALING_3D_MODE_OFF = 255, // for internal use only
};
virtual void viewport_set_use_xr(RID p_viewport, bool p_use_xr) = 0;
@@ -1333,9 +1334,9 @@ public:
NINE_PATCH_TILE_FIT,
};
- virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = 1.0, bool p_antialiased = false) = 0;
- virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0, bool p_antialiased = false) = 0;
- virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_line(RID p_item, const Point2 &p_from, const Point2 &p_to, const Color &p_color, float p_width = -1.0, bool p_antialiased = false) = 0;
+ virtual void canvas_item_add_polyline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0, bool p_antialiased = false) = 0;
+ virtual void canvas_item_add_multiline(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, float p_width = -1.0) = 0;
virtual void canvas_item_add_rect(RID p_item, const Rect2 &p_rect, const Color &p_color) = 0;
virtual void canvas_item_add_circle(RID p_item, const Point2 &p_pos, float p_radius, const Color &p_color) = 0;
virtual void canvas_item_add_texture_rect(RID p_item, const Rect2 &p_rect, RID p_texture, bool p_tile = false, const Color &p_modulate = Color(1, 1, 1), bool p_transpose = false) = 0;
@@ -1343,7 +1344,7 @@ public:
virtual void canvas_item_add_msdf_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1), int p_outline_size = 0, float p_px_range = 1.0, float p_scale = 1.0) = 0;
virtual void canvas_item_add_lcd_texture_rect_region(RID p_item, const Rect2 &p_rect, RID p_texture, const Rect2 &p_src_rect, const Color &p_modulate = Color(1, 1, 1)) = 0;
virtual void canvas_item_add_nine_patch(RID p_item, const Rect2 &p_rect, const Rect2 &p_source, RID p_texture, const Vector2 &p_topleft, const Vector2 &p_bottomright, NinePatchAxisMode p_x_axis_mode = NINE_PATCH_STRETCH, NinePatchAxisMode p_y_axis_mode = NINE_PATCH_STRETCH, bool p_draw_center = true, const Color &p_modulate = Color(1, 1, 1)) = 0;
- virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture, float p_width = 1.0) = 0;
+ virtual void canvas_item_add_primitive(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs, RID p_texture) = 0;
virtual void canvas_item_add_polygon(RID p_item, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), RID p_texture = RID()) = 0;
virtual void canvas_item_add_triangle_array(RID p_item, const Vector<int> &p_indices, const Vector<Point2> &p_points, const Vector<Color> &p_colors, const Vector<Point2> &p_uvs = Vector<Point2>(), const Vector<int> &p_bones = Vector<int>(), const Vector<float> &p_weights = Vector<float>(), RID p_texture = RID(), int p_count = -1) = 0;
virtual void canvas_item_add_mesh(RID p_item, const RID &p_mesh, const Transform2D &p_transform = Transform2D(), const Color &p_modulate = Color(1, 1, 1), RID p_texture = RID()) = 0;
diff --git a/servers/text/text_server_extension.cpp b/servers/text/text_server_extension.cpp
index 997b83e32d..cbf37f25d6 100644
--- a/servers/text/text_server_extension.cpp
+++ b/servers/text/text_server_extension.cpp
@@ -1373,8 +1373,8 @@ String TextServerExtension::string_to_lower(const String &p_string, const String
return p_string;
}
-TypedArray<Vector2i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
- TypedArray<Vector2i> ret;
+TypedArray<Vector3i> TextServerExtension::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+ TypedArray<Vector3i> ret;
GDVIRTUAL_CALL(_parse_structured_text, p_parser_type, p_args, p_text, ret);
return ret;
}
diff --git a/servers/text/text_server_extension.h b/servers/text/text_server_extension.h
index fb784f5471..8536836983 100644
--- a/servers/text/text_server_extension.h
+++ b/servers/text/text_server_extension.h
@@ -521,8 +521,8 @@ public:
GDVIRTUAL2RC(String, _string_to_upper, const String &, const String &);
GDVIRTUAL2RC(String, _string_to_lower, const String &, const String &);
- TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
- GDVIRTUAL3RC(TypedArray<Vector2i>, _parse_structured_text, StructuredTextParser, const Array &, const String &);
+ TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ GDVIRTUAL3RC(TypedArray<Vector3i>, _parse_structured_text, StructuredTextParser, const Array &, const String &);
virtual int64_t is_confusable(const String &p_string, const PackedStringArray &p_dict) const override;
virtual bool spoof_check(const String &p_string) const override;
diff --git a/servers/text_server.cpp b/servers/text_server.cpp
index d339533688..027109b67d 100644
--- a/servers/text_server.cpp
+++ b/servers/text_server.cpp
@@ -483,6 +483,7 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(DIRECTION_AUTO);
BIND_ENUM_CONSTANT(DIRECTION_LTR);
BIND_ENUM_CONSTANT(DIRECTION_RTL);
+ BIND_ENUM_CONSTANT(DIRECTION_INHERITED);
/* Orientation */
BIND_ENUM_CONSTANT(ORIENTATION_HORIZONTAL);
@@ -599,7 +600,7 @@ void TextServer::_bind_methods() {
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_FILE);
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_EMAIL);
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_LIST);
- BIND_ENUM_CONSTANT(STRUCTURED_TEXT_NONE);
+ BIND_ENUM_CONSTANT(STRUCTURED_TEXT_GDSCRIPT);
BIND_ENUM_CONSTANT(STRUCTURED_TEXT_CUSTOM);
}
@@ -1692,22 +1693,22 @@ String TextServer::strip_diacritics(const String &p_string) const {
return result;
}
-TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
- TypedArray<Vector2i> ret;
+TypedArray<Vector3i> TextServer::parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const {
+ TypedArray<Vector3i> ret;
switch (p_parser_type) {
case STRUCTURED_TEXT_URI: {
int prev = 0;
for (int i = 0; i < p_text.length(); i++) {
if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == '.') || (p_text[i] == ':') || (p_text[i] == '&') || (p_text[i] == '=') || (p_text[i] == '@') || (p_text[i] == '?') || (p_text[i] == '#')) {
if (prev != i) {
- ret.push_back(Vector2i(prev, i));
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
}
- ret.push_back(Vector2i(i, i + 1));
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
prev = i + 1;
}
}
if (prev != p_text.length()) {
- ret.push_back(Vector2i(prev, p_text.length()));
+ ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
}
} break;
case STRUCTURED_TEXT_FILE: {
@@ -1715,14 +1716,14 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
for (int i = 0; i < p_text.length(); i++) {
if ((p_text[i] == '\\') || (p_text[i] == '/') || (p_text[i] == ':')) {
if (prev != i) {
- ret.push_back(Vector2i(prev, i));
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
}
- ret.push_back(Vector2i(i, i + 1));
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
prev = i + 1;
}
}
if (prev != p_text.length()) {
- ret.push_back(Vector2i(prev, p_text.length()));
+ ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
}
} break;
case STRUCTURED_TEXT_EMAIL: {
@@ -1731,19 +1732,19 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
for (int i = 0; i < p_text.length(); i++) {
if ((p_text[i] == '@') && local) { // Add full "local" as single context.
local = false;
- ret.push_back(Vector2i(prev, i));
- ret.push_back(Vector2i(i, i + 1));
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
prev = i + 1;
} else if (!local && (p_text[i] == '.')) { // Add each dot separated "domain" part as context.
if (prev != i) {
- ret.push_back(Vector2i(prev, i));
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
}
- ret.push_back(Vector2i(i, i + 1));
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
prev = i + 1;
}
}
if (prev != p_text.length()) {
- ret.push_back(Vector2i(prev, p_text.length()));
+ ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
}
} break;
case STRUCTURED_TEXT_LIST: {
@@ -1752,18 +1753,97 @@ TypedArray<Vector2i> TextServer::parse_structured_text(StructuredTextParser p_pa
int prev = 0;
for (int i = 0; i < tags.size(); i++) {
if (prev != i) {
- ret.push_back(Vector2i(prev, prev + tags[i].length()));
+ ret.push_back(Vector3i(prev, prev + tags[i].length(), TextServer::DIRECTION_INHERITED));
}
- ret.push_back(Vector2i(prev + tags[i].length(), prev + tags[i].length() + 1));
+ ret.push_back(Vector3i(prev + tags[i].length(), prev + tags[i].length() + 1, TextServer::DIRECTION_INHERITED));
prev = prev + tags[i].length() + 1;
}
}
} break;
+ case STRUCTURED_TEXT_GDSCRIPT: {
+ bool in_string_literal = false;
+ bool in_string_literal_single = false;
+ bool in_id = false;
+
+ int prev = 0;
+ for (int i = 0; i < p_text.length(); i++) {
+ char32_t c = p_text[i];
+ if (in_string_literal) {
+ if (c == '\\') {
+ i++;
+ continue; // Skip escaped chars.
+ } else if (c == '\"') {
+ // String literal end, push string and ".
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ in_string_literal = false;
+ }
+ } else if (in_string_literal_single) {
+ if (c == '\\') {
+ i++;
+ continue; // Skip escaped chars.
+ } else if (c == '\'') {
+ // String literal end, push string and '.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ in_string_literal_single = false;
+ }
+ } else if (in_id) {
+ if (!is_unicode_identifier_continue(c)) {
+ // End of id, push id.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i;
+ in_id = false;
+ }
+ } else if (is_unicode_identifier_start(c)) {
+ // Start of new id, push prev element.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i;
+ in_id = true;
+ } else if (c == '\"') {
+ // String literal start, push prev element and ".
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ in_string_literal = true;
+ } else if (c == '\'') {
+ // String literal start, push prev element and '.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ in_string_literal_single = true;
+ } else if (c == '#') {
+ // Start of comment, push prev element and #, skip the rest of the text.
+ if (prev != i) {
+ ret.push_back(Vector3i(prev, i, TextServer::DIRECTION_AUTO));
+ }
+ prev = i + 1;
+ ret.push_back(Vector3i(i, i + 1, TextServer::DIRECTION_LTR));
+ break;
+ }
+ }
+ if (prev < p_text.length()) {
+ ret.push_back(Vector3i(prev, p_text.length(), TextServer::DIRECTION_AUTO));
+ }
+ } break;
case STRUCTURED_TEXT_CUSTOM:
- case STRUCTURED_TEXT_NONE:
case STRUCTURED_TEXT_DEFAULT:
default: {
- ret.push_back(Vector2i(0, p_text.length()));
+ ret.push_back(Vector3i(0, p_text.length(), TextServer::DIRECTION_INHERITED));
}
}
return ret;
diff --git a/servers/text_server.h b/servers/text_server.h
index a56c7d8b23..a91d367e97 100644
--- a/servers/text_server.h
+++ b/servers/text_server.h
@@ -65,7 +65,8 @@ public:
enum Direction {
DIRECTION_AUTO,
DIRECTION_LTR,
- DIRECTION_RTL
+ DIRECTION_RTL,
+ DIRECTION_INHERITED,
};
enum Orientation {
@@ -198,7 +199,7 @@ public:
STRUCTURED_TEXT_FILE,
STRUCTURED_TEXT_EMAIL,
STRUCTURED_TEXT_LIST,
- STRUCTURED_TEXT_NONE,
+ STRUCTURED_TEXT_GDSCRIPT,
STRUCTURED_TEXT_CUSTOM
};
@@ -505,7 +506,7 @@ public:
virtual String string_to_upper(const String &p_string, const String &p_language = "") const = 0;
virtual String string_to_lower(const String &p_string, const String &p_language = "") const = 0;
- TypedArray<Vector2i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
+ TypedArray<Vector3i> parse_structured_text(StructuredTextParser p_parser_type, const Array &p_args, const String &p_text) const;
virtual void cleanup() {}
diff --git a/tests/core/io/test_xml_parser.h b/tests/core/io/test_xml_parser.h
index f4e3f34be2..40cbea2dab 100644
--- a/tests/core/io/test_xml_parser.h
+++ b/tests/core/io/test_xml_parser.h
@@ -54,7 +54,7 @@ TEST_CASE("[XMLParser] End-to-end") {
CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_ELEMENT);
CHECK(parser.get_node_name() == "top");
CHECK(parser.has_attribute("attr"));
- CHECK(parser.get_attribute_value("attr") == "attr value");
+ CHECK(parser.get_named_attribute_value("attr") == "attr value");
CHECK(parser.read() == OK);
CHECK(parser.get_node_type() == XMLParser::NodeType::NODE_TEXT);
diff --git a/tests/core/math/test_plane.h b/tests/core/math/test_plane.h
index b2b857ca69..f784a29a17 100644
--- a/tests/core/math/test_plane.h
+++ b/tests/core/math/test_plane.h
@@ -87,8 +87,8 @@ TEST_CASE("[Plane] Plane-point operations") {
const Plane y_facing_plane = Plane(0, 1, 0, 4);
CHECK_MESSAGE(
- plane.center().is_equal_approx(Vector3(32 * 3, 22 * 3, 16 * 3)),
- "center() should return a vector pointing to the center of the plane.");
+ plane.get_center().is_equal_approx(Vector3(32 * 3, 22 * 3, 16 * 3)),
+ "get_center() should return a vector pointing to the center of the plane.");
CHECK_MESSAGE(
y_facing_plane.is_point_over(Vector3(0, 5, 0)),
diff --git a/tests/scene/test_arraymesh.h b/tests/scene/test_arraymesh.h
index 4d9feeb4fa..b2a2ecc3bf 100644
--- a/tests/scene/test_arraymesh.h
+++ b/tests/scene/test_arraymesh.h
@@ -114,6 +114,17 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") {
CHECK(mesh->get_blend_shape_count() == 0);
}
+ SUBCASE("Can't add surface with incorrect number of blend shapes.") {
+ mesh->add_blend_shape(name_a);
+ mesh->add_blend_shape(name_b);
+ Ref<CylinderMesh> cylinder = memnew(CylinderMesh);
+ Array cylinder_array{};
+ ERR_PRINT_OFF
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+ ERR_PRINT_ON
+ CHECK(mesh->get_surface_count() == 0);
+ }
+
SUBCASE("Can't clear blend shapes after surface had been added.") {
mesh->add_blend_shape(name_a);
mesh->add_blend_shape(name_b);
@@ -121,7 +132,15 @@ TEST_CASE("[SceneTree][ArrayMesh] Adding and modifying blendshapes.") {
Array cylinder_array{};
cylinder_array.resize(Mesh::ARRAY_MAX);
cylinder->create_mesh_array(cylinder_array, 3.f, 3.f, 5.f);
- mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array);
+ Array blend_shape{};
+ blend_shape.resize(Mesh::ARRAY_MAX);
+ blend_shape[Mesh::ARRAY_VERTEX] = cylinder_array[Mesh::ARRAY_VERTEX];
+ blend_shape[Mesh::ARRAY_NORMAL] = cylinder_array[Mesh::ARRAY_NORMAL];
+ blend_shape[Mesh::ARRAY_TANGENT] = cylinder_array[Mesh::ARRAY_TANGENT];
+ Array blend_shapes{};
+ blend_shapes.push_back(blend_shape);
+ blend_shapes.push_back(blend_shape);
+ mesh->add_surface_from_arrays(Mesh::PRIMITIVE_TRIANGLES, cylinder_array, blend_shapes);
ERR_PRINT_OFF
mesh->clear_blend_shapes();
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index c68560000c..e98aece305 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -1954,7 +1954,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
code_edit->set_editable(false);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "\t");
code_edit->unindent_lines();
@@ -1963,16 +1963,9 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
code_edit->set_editable(true);
/* Simple unindent. */
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "");
- /* Should inindent inplace. */
- code_edit->set_text("");
- code_edit->insert_text_at_caret("test\t");
-
- code_edit->do_unindent();
- CHECK(code_edit->get_line(0) == "test");
-
/* Backspace does a simple unindent. */
code_edit->set_text("");
code_edit->insert_text_at_caret("\t");
@@ -1987,7 +1980,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
/* Caret on col zero unindent line. */
code_edit->set_text("\t\ttest");
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "\ttest");
/* Check input action. */
@@ -1998,34 +1991,34 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
/* Selection does entire line. */
code_edit->set_text("\t\ttest");
code_edit->select_all();
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "\ttest");
/* Handles multiple lines. */
code_edit->set_text("\ttest\n\ttext");
code_edit->select_all();
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "text");
/* Do not unindent line if last col is zero. */
code_edit->set_text("\ttest\n\ttext");
code_edit->select(0, 0, 1, 0);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "\ttext");
/* Unindent even if last column of first line. */
code_edit->set_text("\ttest\n\ttext");
code_edit->select(0, 5, 1, 1);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "text");
/* Check selection is adjusted. */
code_edit->set_text("\ttest");
code_edit->select(0, 1, 0, 2);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_selection_from_column() == 0);
CHECK(code_edit->get_selection_to_column() == 1);
CHECK(code_edit->get_line(0) == "test");
@@ -2041,7 +2034,7 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
code_edit->set_editable(false);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == " ");
code_edit->unindent_lines();
@@ -2050,16 +2043,9 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
code_edit->set_editable(true);
/* Simple unindent. */
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "");
- /* Should inindent inplace. */
- code_edit->set_text("");
- code_edit->insert_text_at_caret("test ");
-
- code_edit->do_unindent();
- CHECK(code_edit->get_line(0) == "test");
-
/* Backspace does a simple unindent. */
code_edit->set_text("");
code_edit->insert_text_at_caret(" ");
@@ -2080,12 +2066,12 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
/* Caret on col zero unindent line. */
code_edit->set_text(" test");
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == " test");
/* Only as far as needed */
code_edit->set_text(" test");
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == " test");
/* Check input action. */
@@ -2096,34 +2082,34 @@ TEST_CASE("[SceneTree][CodeEdit] indent") {
/* Selection does entire line. */
code_edit->set_text(" test");
code_edit->select_all();
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == " test");
/* Handles multiple lines. */
code_edit->set_text(" test\n text");
code_edit->select_all();
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "text");
/* Do not unindent line if last col is zero. */
code_edit->set_text(" test\n text");
code_edit->select(0, 0, 1, 0);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == " text");
/* Unindent even if last column of first line. */
code_edit->set_text(" test\n text");
code_edit->select(0, 5, 1, 1);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_line(0) == "test");
CHECK(code_edit->get_line(1) == "text");
/* Check selection is adjusted. */
code_edit->set_text(" test");
code_edit->select(0, 4, 0, 5);
- code_edit->do_unindent();
+ code_edit->unindent_lines();
CHECK(code_edit->get_selection_from_column() == 0);
CHECK(code_edit->get_selection_to_column() == 1);
CHECK(code_edit->get_line(0) == "test");
@@ -2930,7 +2916,7 @@ TEST_CASE("[SceneTree][CodeEdit] completion") {
code_edit->add_code_completion_option(CodeEdit::CodeCompletionKind::KIND_NODE_PATH, "\"test", "\"test");
code_edit->update_code_completion_options();
code_edit->confirm_code_completion();
- CHECK(code_edit->get_line(0) == "\"\"test\"\"");
+ CHECK(code_edit->get_line(0) == "\"\"test\"");
CHECK(code_edit->get_caret_column() == 7);
code_edit->undo();
diff --git a/tests/scene/test_curve_2d.h b/tests/scene/test_curve_2d.h
new file mode 100644
index 0000000000..fc141f3d09
--- /dev/null
+++ b/tests/scene/test_curve_2d.h
@@ -0,0 +1,228 @@
+/**************************************************************************/
+/* test_curve_2d.h */
+/**************************************************************************/
+/* This file is part of: */
+/* GODOT ENGINE */
+/* https://godotengine.org */
+/**************************************************************************/
+/* Copyright (c) 2014-present Godot Engine contributors (see AUTHORS.md). */
+/* Copyright (c) 2007-2014 Juan Linietsky, Ariel Manzur. */
+/* */
+/* 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_CURVE_2D_H
+#define TEST_CURVE_2D_H
+
+#include "core/math/math_funcs.h"
+#include "scene/resources/curve.h"
+
+#include "tests/test_macros.h"
+
+namespace TestCurve2D {
+
+void add_sample_curve_points(Ref<Curve2D> &curve) {
+ Vector2 p0 = Vector2(0, 0);
+ Vector2 p1 = Vector2(50, 0);
+ Vector2 p2 = Vector2(50, 50);
+ Vector2 p3 = Vector2(0, 50);
+
+ Vector2 control0 = p1 - p0;
+ Vector2 control1 = p3 - p2;
+
+ curve->add_point(p0, Vector2(), control0);
+ curve->add_point(p3, control1, Vector2());
+}
+
+TEST_CASE("[Curve2D] Default curve is empty") {
+ const Ref<Curve2D> curve = memnew(Curve2D);
+ CHECK(curve->get_point_count() == 0);
+}
+
+TEST_CASE("[Curve2D] Point management") {
+ Ref<Curve2D> curve = memnew(Curve2D);
+
+ SUBCASE("Functions for adding/removing points should behave as expected") {
+ curve->set_point_count(2);
+ CHECK(curve->get_point_count() == 2);
+
+ curve->remove_point(0);
+ CHECK(curve->get_point_count() == 1);
+
+ curve->add_point(Vector2());
+ CHECK(curve->get_point_count() == 2);
+
+ curve->clear_points();
+ CHECK(curve->get_point_count() == 0);
+ }
+
+ SUBCASE("Functions for changing single point properties should behave as expected") {
+ Vector2 new_in = Vector2(1, 1);
+ Vector2 new_out = Vector2(1, 1);
+ Vector2 new_pos = Vector2(1, 1);
+
+ curve->add_point(Vector2());
+
+ CHECK(curve->get_point_in(0) != new_in);
+ curve->set_point_in(0, new_in);
+ CHECK(curve->get_point_in(0) == new_in);
+
+ CHECK(curve->get_point_out(0) != new_out);
+ curve->set_point_out(0, new_out);
+ CHECK(curve->get_point_out(0) == new_out);
+
+ CHECK(curve->get_point_position(0) != new_pos);
+ curve->set_point_position(0, new_pos);
+ CHECK(curve->get_point_position(0) == new_pos);
+ }
+}
+
+TEST_CASE("[Curve2D] Baked") {
+ Ref<Curve2D> curve = memnew(Curve2D);
+
+ SUBCASE("Single Point") {
+ curve->add_point(Vector2());
+
+ CHECK(curve->get_baked_length() == 0);
+ CHECK(curve->get_baked_points().size() == 1);
+ }
+
+ SUBCASE("Straight line") {
+ curve->add_point(Vector2());
+ curve->add_point(Vector2(0, 50));
+
+ CHECK(Math::is_equal_approx(curve->get_baked_length(), 50));
+ CHECK(curve->get_baked_points().size() == 15);
+ }
+
+ SUBCASE("Beziér Curve") {
+ add_sample_curve_points(curve);
+
+ real_t len = curve->get_baked_length();
+ real_t n_points = curve->get_baked_points().size();
+ // Curve length should be bigger than a straight between points
+ CHECK(len > 50);
+
+ SUBCASE("Increase bake interval") {
+ curve->set_bake_interval(10.0);
+ // Lower resolution should imply less points and smaller length
+ CHECK(curve->get_baked_length() < len);
+ CHECK(curve->get_baked_points().size() < n_points);
+ }
+ }
+}
+
+TEST_CASE("[Curve2D] Sampling") {
+ // Sampling over a simple straight line to make assertions simpler
+ Ref<Curve2D> curve = memnew(Curve2D);
+ curve->add_point(Vector2());
+ curve->add_point(Vector2(0, 50));
+
+ SUBCASE("sample") {
+ CHECK(curve->sample(0, 0) == Vector2(0, 0));
+ CHECK(curve->sample(0, 0.5) == Vector2(0, 25));
+ CHECK(curve->sample(0, 1) == Vector2(0, 50));
+ }
+
+ SUBCASE("samplef") {
+ CHECK(curve->samplef(0) == Vector2(0, 0));
+ CHECK(curve->samplef(0.5) == Vector2(0, 25));
+ CHECK(curve->samplef(1) == Vector2(0, 50));
+ }
+
+ SUBCASE("sample_baked") {
+ CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 0))) == Vector2(0, 0));
+ CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 25))) == Vector2(0, 25));
+ CHECK(curve->sample_baked(curve->get_closest_offset(Vector2(0, 50))) == Vector2(0, 50));
+ }
+
+ SUBCASE("sample_baked_with_rotation") {
+ const real_t pi = 3.14159;
+ Transform2D t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 0)));
+ CHECK(t.get_origin() == Vector2(0, 0));
+ CHECK(Math::is_equal_approx(t.get_rotation(), pi));
+
+ t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 25)));
+ CHECK(t.get_origin() == Vector2(0, 25));
+ CHECK(Math::is_equal_approx(t.get_rotation(), pi));
+
+ t = curve->sample_baked_with_rotation(curve->get_closest_offset(Vector2(0, 50)));
+ CHECK(t.get_origin() == Vector2(0, 50));
+ CHECK(Math::is_equal_approx(t.get_rotation(), pi));
+ }
+
+ SUBCASE("get_closest_point") {
+ CHECK(curve->get_closest_point(Vector2(0, 0)) == Vector2(0, 0));
+ CHECK(curve->get_closest_point(Vector2(0, 25)) == Vector2(0, 25));
+ CHECK(curve->get_closest_point(Vector2(50, 25)) == Vector2(0, 25));
+ CHECK(curve->get_closest_point(Vector2(0, 50)) == Vector2(0, 50));
+ CHECK(curve->get_closest_point(Vector2(50, 50)) == Vector2(0, 50));
+ CHECK(curve->get_closest_point(Vector2(0, 100)) == Vector2(0, 50));
+ }
+}
+
+TEST_CASE("[Curve2D] Tessellation") {
+ Ref<Curve2D> curve = memnew(Curve2D);
+ add_sample_curve_points(curve);
+
+ const int default_size = curve->tessellate().size();
+
+ SUBCASE("Increase to max stages should increase num of points") {
+ CHECK(curve->tessellate(6).size() > default_size);
+ }
+
+ SUBCASE("Decrease to max stages should decrease num of points") {
+ CHECK(curve->tessellate(4).size() < default_size);
+ }
+
+ SUBCASE("Increase to tolerance should decrease num of points") {
+ CHECK(curve->tessellate(5, 5).size() < default_size);
+ }
+
+ SUBCASE("Decrease to tolerance should increase num of points") {
+ CHECK(curve->tessellate(5, 3).size() > default_size);
+ }
+
+ SUBCASE("Adding a straight segment should only add the last point to tessellate return array") {
+ curve->add_point(Vector2(0, 100));
+ PackedVector2Array tes = curve->tessellate();
+ CHECK(tes.size() == default_size + 1);
+ CHECK(tes[tes.size() - 1] == Vector2(0, 100));
+ CHECK(tes[tes.size() - 2] == Vector2(0, 50));
+ }
+}
+
+TEST_CASE("[Curve2D] Even length tessellation") {
+ Ref<Curve2D> curve = memnew(Curve2D);
+ add_sample_curve_points(curve);
+
+ const int default_size = curve->tessellate_even_length().size();
+
+ // Default tessellate_even_length tolerance_length is 20.0, by adding a 100 units
+ // straight, we expect the total size to be increased by more than 5,
+ // that is, the algo will pick a length < 20.0 and will divide the straight as
+ // well as the curve as opposed to tessellate() which only adds the final point
+ curve->add_point(Vector2(0, 150));
+ CHECK(curve->tessellate_even_length().size() > default_size + 5);
+}
+
+} // namespace TestCurve2D
+
+#endif // TEST_CURVE_2D_H
diff --git a/tests/scene/test_node.h b/tests/scene/test_node.h
index 20c42d9fc2..0ddf027970 100644
--- a/tests/scene/test_node.h
+++ b/tests/scene/test_node.h
@@ -37,7 +37,7 @@
namespace TestNode {
-TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") {
+TEST_CASE("[SceneTree][Node] Testing node operations with a very simple scene tree") {
Node *node = memnew(Node);
// Check initial scene tree setup.
@@ -135,10 +135,30 @@ TEST_CASE("[SceneTree][Node] Simple Add/Remove/Move/Find") {
CHECK(node->is_inside_tree());
}
+ SUBCASE("Node should be possible to reparent") {
+ node->reparent(SceneTree::get_singleton()->get_root());
+
+ Node *child = SceneTree::get_singleton()->get_root()->get_child(0);
+ CHECK_EQ(child, node);
+ CHECK(node->is_inside_tree());
+ }
+
+ SUBCASE("Node should be possible to duplicate") {
+ node->set_name("MyName");
+
+ Node *duplicate = node->duplicate();
+
+ CHECK_FALSE(node == duplicate);
+ CHECK_FALSE(duplicate->is_inside_tree());
+ CHECK_EQ(duplicate->get_name(), node->get_name());
+
+ memdelete(duplicate);
+ }
+
memdelete(node);
}
-TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
+TEST_CASE("[SceneTree][Node] Testing node operations with a more complex simple scene tree") {
Node *node1 = memnew(Node);
Node *node2 = memnew(Node);
Node *node1_1 = memnew(Node);
@@ -209,7 +229,7 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
CHECK_EQ(child2, node1);
}
- SUBCASE("Nodes should be in the expected order when reparented") {
+ SUBCASE("Nodes should be in the expected order when reparented (remove/add)") {
CHECK_EQ(node2->get_child_count(), 0);
node1->remove_child(node1_1);
@@ -227,6 +247,22 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
}
+ SUBCASE("Nodes should be in the expected order when reparented") {
+ CHECK_EQ(node2->get_child_count(), 0);
+
+ node1_1->reparent(node2);
+
+ CHECK_EQ(node1->get_child_count(), 0);
+ CHECK_EQ(node2->get_child_count(), 1);
+ CHECK_EQ(node1_1->get_parent(), node2);
+
+ Node *child = node2->get_child(0);
+ CHECK_EQ(child, node1_1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 2);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
+ }
+
SUBCASE("Nodes should be possible to find") {
Node *child = SceneTree::get_singleton()->get_root()->find_child("NestedNode", true, false);
CHECK_EQ(child, nullptr);
@@ -315,6 +351,70 @@ TEST_CASE("[SceneTree][Node] Nested Add/Remove/Move/Find") {
CHECK_EQ(E->get(), node1_1);
}
+ SUBCASE("Nodes added as siblings of another node should be right next to it") {
+ node1->remove_child(node1_1);
+
+ node1->add_sibling(node1_1);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 3);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 4);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(0), node1);
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(1), node1_1);
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child(2), node2);
+ }
+
+ SUBCASE("Replaced nodes should be be removed and the replacing node added") {
+ SceneTree::get_singleton()->get_root()->remove_child(node2);
+
+ node1->replace_by(node2);
+
+ CHECK_EQ(SceneTree::get_singleton()->get_root()->get_child_count(), 1);
+ CHECK_EQ(SceneTree::get_singleton()->get_node_count(), 3);
+
+ CHECK_FALSE(node1->is_inside_tree());
+ CHECK(node2->is_inside_tree());
+
+ CHECK_EQ(node1->get_parent(), nullptr);
+ CHECK_EQ(node2->get_parent(), SceneTree::get_singleton()->get_root());
+ CHECK_EQ(node2->get_child_count(), 1);
+ CHECK_EQ(node2->get_child(0), node1_1);
+ }
+
+ SUBCASE("Replacing nodes should keep the groups of the replaced nodes") {
+ SceneTree::get_singleton()->get_root()->remove_child(node2);
+
+ node1->add_to_group("nodes");
+ node1->replace_by(node2, true);
+
+ List<Node *> nodes;
+ SceneTree::get_singleton()->get_nodes_in_group("nodes", &nodes);
+ CHECK_EQ(nodes.size(), 1);
+
+ List<Node *>::Element *E = nodes.front();
+ CHECK_EQ(E->get(), node2);
+ }
+
+ SUBCASE("Duplicating a node should also duplicate the children") {
+ node1->set_name("MyName1");
+ node1_1->set_name("MyName1_1");
+ Node *duplicate1 = node1->duplicate();
+
+ CHECK_EQ(duplicate1->get_child_count(), node1->get_child_count());
+ Node *duplicate1_1 = duplicate1->get_child(0);
+
+ CHECK_EQ(duplicate1_1->get_child_count(), node1_1->get_child_count());
+
+ CHECK_EQ(duplicate1->get_name(), node1->get_name());
+ CHECK_EQ(duplicate1_1->get_name(), node1_1->get_name());
+
+ CHECK_FALSE(duplicate1->is_inside_tree());
+ CHECK_FALSE(duplicate1_1->is_inside_tree());
+
+ memdelete(duplicate1_1);
+ memdelete(duplicate1);
+ }
+
memdelete(node1_1);
memdelete(node1);
memdelete(node2);
diff --git a/tests/scene/test_primitives.h b/tests/scene/test_primitives.h
index 6cdb5fb0a5..9232a3020d 100644
--- a/tests/scene/test_primitives.h
+++ b/tests/scene/test_primitives.h
@@ -734,7 +734,7 @@ TEST_CASE("[SceneTree][Primitive][Text] Text Primitive") {
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_FILE ||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_EMAIL ||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_LIST ||
- text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_NONE ||
+ text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_GDSCRIPT ||
text->get_structured_text_bidi_override() == TextServer::STRUCTURED_TEXT_CUSTOM));
CHECK(text->get_structured_text_bidi_override_options().size() >= 0);
CHECK(text->get_width() > 0);
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 85a271fc9c..8c563f94ac 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -91,6 +91,7 @@
#include "tests/scene/test_bit_map.h"
#include "tests/scene/test_code_edit.h"
#include "tests/scene/test_curve.h"
+#include "tests/scene/test_curve_2d.h"
#include "tests/scene/test_gradient.h"
#include "tests/scene/test_node.h"
#include "tests/scene/test_path_2d.h"
diff --git a/thirdparty/README.md b/thirdparty/README.md
index 33f835cbcd..38001b8782 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -17,6 +17,18 @@ Files extracted from upstream source:
- `license.txt`
+## astcenc
+
+- Upstream: https://github.com/ARM-software/astc-encoder
+- Version: 4.3.0 (ec83dda79fcefe07f69cdae7ed980d169bf2c4d4, 2023)
+- License: Apache 2.0
+
+Files extracted from upstream source:
+
+- `astcenc_*` and `astcenc.h` files from `Source`
+- `LICENSE.txt`
+
+
## basis_universal
- Upstream: https://github.com/BinomialLLC/basis_universal
diff --git a/thirdparty/astcenc/LICENSE.txt b/thirdparty/astcenc/LICENSE.txt
new file mode 100644
index 0000000000..b82735a310
--- /dev/null
+++ b/thirdparty/astcenc/LICENSE.txt
@@ -0,0 +1,175 @@
+
+ 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.
diff --git a/thirdparty/astcenc/astcenc.h b/thirdparty/astcenc/astcenc.h
new file mode 100644
index 0000000000..70ae783373
--- /dev/null
+++ b/thirdparty/astcenc/astcenc.h
@@ -0,0 +1,815 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2020-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief The core astcenc codec library interface.
+ *
+ * This interface is the entry point to the core astcenc codec. It aims to be easy to use for
+ * non-experts, but also to allow experts to have fine control over the compressor heuristics if
+ * needed. The core codec only handles compression and decompression, transferring all inputs and
+ * outputs via memory buffers. To catch obvious input/output buffer sizing issues, which can cause
+ * security and stability problems, all transfer buffers are explicitly sized.
+ *
+ * While the aim is that we keep this interface mostly stable, it should be viewed as a mutable
+ * interface tied to a specific source version. We are not trying to maintain backwards
+ * compatibility across codec versions.
+ *
+ * The API state management is based around an explicit context object, which is the context for all
+ * allocated memory resources needed to compress and decompress a single image. A context can be
+ * used to sequentially compress multiple images using the same configuration, allowing setup
+ * overheads to be amortized over multiple images, which is particularly important when images are
+ * small.
+ *
+ * Multi-threading can be used two ways.
+ *
+ * * An application wishing to process multiple images in parallel can allocate multiple
+ * contexts and assign each context to a thread.
+ * * An application wishing to process a single image in using multiple threads can configure
+ * contexts for multi-threaded use, and invoke astcenc_compress/decompress() once per thread
+ * for faster processing. The caller is responsible for creating the worker threads, and
+ * synchronizing between images.
+ *
+ * Threading
+ * =========
+ *
+ * In pseudo-code, the usage for manual user threading looks like this:
+ *
+ * // Configure the compressor run
+ * astcenc_config my_config;
+ * astcenc_config_init(..., &my_config);
+ *
+ * // Power users can tweak <my_config> settings here ...
+ *
+ * // Allocate working state given config and thread_count
+ * astcenc_context* my_context;
+ * astcenc_context_alloc(&my_config, thread_count, &my_context);
+ *
+ * // Compress each image using these config settings
+ * foreach image:
+ * // For each thread in the thread pool
+ * for i in range(0, thread_count):
+ * astcenc_compress_image(my_context, &my_input, my_output, i);
+ *
+ * astcenc_compress_reset(my_context);
+ *
+ * // Clean up
+ * astcenc_context_free(my_context);
+ *
+ * Images
+ * ======
+ *
+ * The codec supports compressing single images, which can be either 2D images or volumetric 3D
+ * images. Calling code is responsible for any handling of aggregate types, such as mipmap chains,
+ * texture arrays, or sliced 3D textures.
+ *
+ * Images are passed in as an astcenc_image structure. Inputs can be either 8-bit unorm, 16-bit
+ * half-float, or 32-bit float, as indicated by the data_type field.
+ *
+ * Images can be any dimension; there is no requirement to be a multiple of the ASTC block size.
+ *
+ * Data is always passed in as 4 color components, and accessed as an array of 2D image slices. Data
+ * within an image slice is always tightly packed without padding. Addressing looks like this:
+ *
+ * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 ] // Red
+ * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 1] // Green
+ * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 2] // Blue
+ * data[z_coord][y_coord * x_dim * 4 + x_coord * 4 + 3] // Alpha
+ *
+ * Common compressor usage
+ * =======================
+ *
+ * One of the most important things for coding image quality is to align the input data component
+ * count with the ASTC color endpoint mode. This avoids wasting bits encoding components you don't
+ * actually need in the endpoint colors.
+ *
+ * | Input data | Encoding swizzle | Sampling swizzle |
+ * | ------------ | ---------------- | ---------------- |
+ * | 1 component | RRR1 | .[rgb] |
+ * | 2 components | RRRG | .[rgb]a |
+ * | 3 components | RGB1 | .rgb |
+ * | 4 components | RGBA | .rgba |
+ *
+ * The 1 and 2 component modes recommend sampling from "g" to recover the luminance value as this
+ * provide best compatibility with other texture formats where the green component may be stored at
+ * higher precision than the others, such as RGB565. For ASTC any of the RGB components can be used;
+ * the luminance endpoint component will be returned for all three.
+ *
+ * When using the normal map compression mode ASTC will store normals as a two component X+Y map.
+ * Input images must contain unit-length normalized and should be passed in using a two component
+ * swizzle. The astcenc command line tool defaults to an RRRG swizzle, but some developers prefer
+ * to use GGGR for compatability with BC5n which will work just as well. The Z component can be
+ * recovered programmatically in shader code, using knowledge that the vector is unit length and
+ * that Z must be positive for a tangent-space normal map.
+ *
+ * Decompress-only usage
+ * =====================
+ *
+ * For some use cases it is useful to have a cut-down context and/or library which supports
+ * decompression but not compression.
+ *
+ * A context can be made decompress-only using the ASTCENC_FLG_DECOMPRESS_ONLY flag when the context
+ * is allocated. These contexts have lower dynamic memory footprint than a full context.
+ *
+ * The entire library can be made decompress-only by building the files with the define
+ * ASTCENC_DECOMPRESS_ONLY set. In this build the context will be smaller, and the library will
+ * exclude the functionality which is only needed for compression. This reduces the binary size by
+ * ~180KB. For these builds contexts must be created with the ASTCENC_FLG_DECOMPRESS_ONLY flag.
+ *
+ * Note that context structures returned by a library built as decompress-only are incompatible with
+ * a library built with compression included, and visa versa, as they have different sizes and
+ * memory layout.
+ *
+ * Self-decompress-only usage
+ * ==========================
+ *
+ * ASTC is a complex format with a large search space. The parts of this search space that are
+ * searched is determined by heuristics that are, in part, tied to the quality level used when
+ * creating the context.
+ *
+ * A normal context is capable of decompressing any ASTC texture, including those generated by other
+ * compressors with unknown heuristics. This is the most flexible implementation, but forces the
+ * data tables used by the codec to include entries that are not needed during compression. This
+ * can slow down context creation by a significant amount, especially for the faster compression
+ * modes where few data table entries are actually used. To optimize this use case the context can
+ * be created with the ASTCENC_FLG_SELF_DECOMPRESS_ONLY flag. This tells the compressor that it will
+ * only be asked to decompress images that it compressed itself, allowing the data tables to
+ * exclude entries that are not needed by the current compression configuration. This reduces the
+ * size of the context data tables in memory and improves context creation performance. Note that,
+ * as of the 3.6 release, this flag no longer affects compression performance.
+ *
+ * Using this flag while attempting to decompress an valid image which was created by another
+ * compressor, or even another astcenc compressor version or configuration, may result in blocks
+ * returning as solid magenta or NaN value error blocks.
+ */
+
+#ifndef ASTCENC_INCLUDED
+#define ASTCENC_INCLUDED
+
+#include <cstddef>
+#include <cstdint>
+
+#if defined(ASTCENC_DYNAMIC_LIBRARY)
+ #if defined(_MSC_VER)
+ #define ASTCENC_PUBLIC extern "C" __declspec(dllexport)
+ #else
+ #define ASTCENC_PUBLIC extern "C" __attribute__ ((visibility ("default")))
+ #endif
+#else
+ #define ASTCENC_PUBLIC
+#endif
+
+/* ============================================================================
+ Data declarations
+============================================================================ */
+
+/**
+ * @brief An opaque structure; see astcenc_internal.h for definition.
+ */
+struct astcenc_context;
+
+/**
+ * @brief A codec API error code.
+ */
+enum astcenc_error {
+ /** @brief The call was successful. */
+ ASTCENC_SUCCESS = 0,
+ /** @brief The call failed due to low memory, or undersized I/O buffers. */
+ ASTCENC_ERR_OUT_OF_MEM,
+ /** @brief The call failed due to the build using fast math. */
+ ASTCENC_ERR_BAD_CPU_FLOAT,
+ /** @brief The call failed due to the build using an unsupported ISA. */
+ ASTCENC_ERR_BAD_CPU_ISA,
+ /** @brief The call failed due to an out-of-spec parameter. */
+ ASTCENC_ERR_BAD_PARAM,
+ /** @brief The call failed due to an out-of-spec block size. */
+ ASTCENC_ERR_BAD_BLOCK_SIZE,
+ /** @brief The call failed due to an out-of-spec color profile. */
+ ASTCENC_ERR_BAD_PROFILE,
+ /** @brief The call failed due to an out-of-spec quality value. */
+ ASTCENC_ERR_BAD_QUALITY,
+ /** @brief The call failed due to an out-of-spec component swizzle. */
+ ASTCENC_ERR_BAD_SWIZZLE,
+ /** @brief The call failed due to an out-of-spec flag set. */
+ ASTCENC_ERR_BAD_FLAGS,
+ /** @brief The call failed due to the context not supporting the operation. */
+ ASTCENC_ERR_BAD_CONTEXT,
+ /** @brief The call failed due to unimplemented functionality. */
+ ASTCENC_ERR_NOT_IMPLEMENTED,
+#if defined(ASTCENC_DIAGNOSTICS)
+ /** @brief The call failed due to an issue with diagnostic tracing. */
+ ASTCENC_ERR_DTRACE_FAILURE,
+#endif
+};
+
+/**
+ * @brief A codec color profile.
+ */
+enum astcenc_profile {
+ /** @brief The LDR sRGB color profile. */
+ ASTCENC_PRF_LDR_SRGB = 0,
+ /** @brief The LDR linear color profile. */
+ ASTCENC_PRF_LDR,
+ /** @brief The HDR RGB with LDR alpha color profile. */
+ ASTCENC_PRF_HDR_RGB_LDR_A,
+ /** @brief The HDR RGBA color profile. */
+ ASTCENC_PRF_HDR
+};
+
+/** @brief The fastest, lowest quality, search preset. */
+static const float ASTCENC_PRE_FASTEST = 0.0f;
+
+/** @brief The fast search preset. */
+static const float ASTCENC_PRE_FAST = 10.0f;
+
+/** @brief The medium quality search preset. */
+static const float ASTCENC_PRE_MEDIUM = 60.0f;
+
+/** @brief The thorough quality search preset. */
+static const float ASTCENC_PRE_THOROUGH = 98.0f;
+
+/** @brief The thorough quality search preset. */
+static const float ASTCENC_PRE_VERYTHOROUGH = 99.0f;
+
+/** @brief The exhaustive, highest quality, search preset. */
+static const float ASTCENC_PRE_EXHAUSTIVE = 100.0f;
+
+/**
+ * @brief A codec component swizzle selector.
+ */
+enum astcenc_swz
+{
+ /** @brief Select the red component. */
+ ASTCENC_SWZ_R = 0,
+ /** @brief Select the green component. */
+ ASTCENC_SWZ_G = 1,
+ /** @brief Select the blue component. */
+ ASTCENC_SWZ_B = 2,
+ /** @brief Select the alpha component. */
+ ASTCENC_SWZ_A = 3,
+ /** @brief Use a constant zero component. */
+ ASTCENC_SWZ_0 = 4,
+ /** @brief Use a constant one component. */
+ ASTCENC_SWZ_1 = 5,
+ /** @brief Use a reconstructed normal vector Z component. */
+ ASTCENC_SWZ_Z = 6
+};
+
+/**
+ * @brief A texel component swizzle.
+ */
+struct astcenc_swizzle
+{
+ /** @brief The red component selector. */
+ astcenc_swz r;
+ /** @brief The green component selector. */
+ astcenc_swz g;
+ /** @brief The blue component selector. */
+ astcenc_swz b;
+ /** @brief The alpha component selector. */
+ astcenc_swz a;
+};
+
+/**
+ * @brief A texel component data format.
+ */
+enum astcenc_type
+{
+ /** @brief Unorm 8-bit data per component. */
+ ASTCENC_TYPE_U8 = 0,
+ /** @brief 16-bit float per component. */
+ ASTCENC_TYPE_F16 = 1,
+ /** @brief 32-bit float per component. */
+ ASTCENC_TYPE_F32 = 2
+};
+
+/**
+ * @brief Enable normal map compression.
+ *
+ * Input data will be treated a two component normal map, storing X and Y, and the codec will
+ * optimize for angular error rather than simple linear PSNR. In this mode the input swizzle should
+ * be e.g. rrrg (the default ordering for ASTC normals on the command line) or gggr (the ordering
+ * used by BC5n).
+ */
+static const unsigned int ASTCENC_FLG_MAP_NORMAL = 1 << 0;
+
+/**
+ * @brief Enable alpha weighting.
+ *
+ * The input alpha value is used for transparency, so errors in the RGB components are weighted by
+ * the transparency level. This allows the codec to more accurately encode the alpha value in areas
+ * where the color value is less significant.
+ */
+static const unsigned int ASTCENC_FLG_USE_ALPHA_WEIGHT = 1 << 2;
+
+/**
+ * @brief Enable perceptual error metrics.
+ *
+ * This mode enables perceptual compression mode, which will optimize for perceptual error rather
+ * than best PSNR. Only some input modes support perceptual error metrics.
+ */
+static const unsigned int ASTCENC_FLG_USE_PERCEPTUAL = 1 << 3;
+
+/**
+ * @brief Create a decompression-only context.
+ *
+ * This mode disables support for compression. This enables context allocation to skip some
+ * transient buffer allocation, resulting in lower memory usage.
+ */
+static const unsigned int ASTCENC_FLG_DECOMPRESS_ONLY = 1 << 4;
+
+/**
+ * @brief Create a self-decompression context.
+ *
+ * This mode configures the compressor so that it is only guaranteed to be able to decompress images
+ * that were actually created using the current context. This is the common case for compression use
+ * cases, and setting this flag enables additional optimizations, but does mean that the context
+ * cannot reliably decompress arbitrary ASTC images.
+ */
+static const unsigned int ASTCENC_FLG_SELF_DECOMPRESS_ONLY = 1 << 5;
+
+/**
+ * @brief Enable RGBM map compression.
+ *
+ * Input data will be treated as HDR data that has been stored in an LDR RGBM-encoded wrapper
+ * format. Data must be preprocessed by the user to be in LDR RGBM format before calling the
+ * compression function, this flag is only used to control the use of RGBM-specific heuristics and
+ * error metrics.
+ *
+ * IMPORTANT: The ASTC format is prone to bad failure modes with unconstrained RGBM data; very small
+ * M values can round to zero due to quantization and result in black or white pixels. It is highly
+ * recommended that the minimum value of M used in the encoding is kept above a lower threshold (try
+ * 16 or 32). Applying this threshold reduces the number of very dark colors that can be
+ * represented, but is still higher precision than 8-bit LDR.
+ *
+ * When this flag is set the value of @c rgbm_m_scale in the context must be set to the RGBM scale
+ * factor used during reconstruction. This defaults to 5 when in RGBM mode.
+ *
+ * It is recommended that the value of @c cw_a_weight is set to twice the value of the multiplier
+ * scale, ensuring that the M value is accurately encoded. This defaults to 10 when in RGBM mode,
+ * matching the default scale factor.
+ */
+static const unsigned int ASTCENC_FLG_MAP_RGBM = 1 << 6;
+
+/**
+ * @brief The bit mask of all valid flags.
+ */
+static const unsigned int ASTCENC_ALL_FLAGS =
+ ASTCENC_FLG_MAP_NORMAL |
+ ASTCENC_FLG_MAP_RGBM |
+ ASTCENC_FLG_USE_ALPHA_WEIGHT |
+ ASTCENC_FLG_USE_PERCEPTUAL |
+ ASTCENC_FLG_DECOMPRESS_ONLY |
+ ASTCENC_FLG_SELF_DECOMPRESS_ONLY;
+
+/**
+ * @brief The config structure.
+ *
+ * This structure will initially be populated by a call to astcenc_config_init, but power users may
+ * modify it before calling astcenc_context_alloc. See astcenccli_toplevel_help.cpp for full user
+ * documentation of the power-user settings.
+ *
+ * Note for any settings which are associated with a specific color component, the value in the
+ * config applies to the component that exists after any compression data swizzle is applied.
+ */
+struct astcenc_config
+{
+ /** @brief The color profile. */
+ astcenc_profile profile;
+
+ /** @brief The set of set flags. */
+ unsigned int flags;
+
+ /** @brief The ASTC block size X dimension. */
+ unsigned int block_x;
+
+ /** @brief The ASTC block size Y dimension. */
+ unsigned int block_y;
+
+ /** @brief The ASTC block size Z dimension. */
+ unsigned int block_z;
+
+ /** @brief The red component weight scale for error weighting (-cw). */
+ float cw_r_weight;
+
+ /** @brief The green component weight scale for error weighting (-cw). */
+ float cw_g_weight;
+
+ /** @brief The blue component weight scale for error weighting (-cw). */
+ float cw_b_weight;
+
+ /** @brief The alpha component weight scale for error weighting (-cw). */
+ float cw_a_weight;
+
+ /**
+ * @brief The radius for any alpha-weight scaling (-a).
+ *
+ * It is recommended that this is set to 1 when using FLG_USE_ALPHA_WEIGHT on a texture that
+ * will be sampled using linear texture filtering to minimize color bleed out of transparent
+ * texels that are adjacent to non-transparent texels.
+ */
+ unsigned int a_scale_radius;
+
+ /** @brief The RGBM scale factor for the shared multiplier (-rgbm). */
+ float rgbm_m_scale;
+
+ /**
+ * @brief The maximum number of partitions searched (-partitioncountlimit).
+ *
+ * Valid values are between 1 and 4.
+ */
+ unsigned int tune_partition_count_limit;
+
+ /**
+ * @brief The maximum number of partitions searched (-2partitionindexlimit).
+ *
+ * Valid values are between 1 and 1024.
+ */
+ unsigned int tune_2partition_index_limit;
+
+ /**
+ * @brief The maximum number of partitions searched (-3partitionindexlimit).
+ *
+ * Valid values are between 1 and 1024.
+ */
+ unsigned int tune_3partition_index_limit;
+
+ /**
+ * @brief The maximum number of partitions searched (-4partitionindexlimit).
+ *
+ * Valid values are between 1 and 1024.
+ */
+ unsigned int tune_4partition_index_limit;
+
+ /**
+ * @brief The maximum centile for block modes searched (-blockmodelimit).
+ *
+ * Valid values are between 1 and 100.
+ */
+ unsigned int tune_block_mode_limit;
+
+ /**
+ * @brief The maximum iterative refinements applied (-refinementlimit).
+ *
+ * Valid values are between 1 and N; there is no technical upper limit
+ * but little benefit is expected after N=4.
+ */
+ unsigned int tune_refinement_limit;
+
+ /**
+ * @brief The number of trial candidates per mode search (-candidatelimit).
+ *
+ * Valid values are between 1 and TUNE_MAX_TRIAL_CANDIDATES (default 4).
+ */
+ unsigned int tune_candidate_limit;
+
+ /**
+ * @brief The number of trial partitionings per search (-2partitioncandidatelimit).
+ *
+ * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES.
+ */
+ unsigned int tune_2partitioning_candidate_limit;
+
+ /**
+ * @brief The number of trial partitionings per search (-3partitioncandidatelimit).
+ *
+ * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES.
+ */
+ unsigned int tune_3partitioning_candidate_limit;
+
+ /**
+ * @brief The number of trial partitionings per search (-4partitioncandidatelimit).
+ *
+ * Valid values are between 1 and TUNE_MAX_PARTITIONING_CANDIDATES.
+ */
+ unsigned int tune_4partitioning_candidate_limit;
+
+ /**
+ * @brief The dB threshold for stopping block search (-dblimit).
+ *
+ * This option is ineffective for HDR textures.
+ */
+ float tune_db_limit;
+
+ /**
+ * @brief The amount of MSE overshoot needed to early-out trials.
+ *
+ * The first early-out is for 1 partition, 1 plane trials, where we try a minimal encode using
+ * the high probability block modes. This can short-cut compression for simple blocks.
+ *
+ * The second early-out is for refinement trials, where we can exit refinement once quality is
+ * reached.
+ */
+ float tune_mse_overshoot;
+
+ /**
+ * @brief The threshold for skipping 3.1/4.1 trials (-2partitionlimitfactor).
+ *
+ * This option is further scaled for normal maps, so it skips less often.
+ */
+ float tune_2_partition_early_out_limit_factor;
+
+ /**
+ * @brief The threshold for skipping 4.1 trials (-3partitionlimitfactor).
+ *
+ * This option is further scaled for normal maps, so it skips less often.
+ */
+ float tune_3_partition_early_out_limit_factor;
+
+ /**
+ * @brief The threshold for skipping two weight planes (-2planelimitcorrelation).
+ *
+ * This option is ineffective for normal maps.
+ */
+ float tune_2_plane_early_out_limit_correlation;
+
+#if defined(ASTCENC_DIAGNOSTICS)
+ /**
+ * @brief The path to save the diagnostic trace data to.
+ *
+ * This option is not part of the public API, and requires special builds
+ * of the library.
+ */
+ const char* trace_file_path;
+#endif
+};
+
+/**
+ * @brief An uncompressed 2D or 3D image.
+ *
+ * 3D image are passed in as an array of 2D slices. Each slice has identical
+ * size and color format.
+ */
+struct astcenc_image
+{
+ /** @brief The X dimension of the image, in texels. */
+ unsigned int dim_x;
+
+ /** @brief The Y dimension of the image, in texels. */
+ unsigned int dim_y;
+
+ /** @brief The Z dimension of the image, in texels. */
+ unsigned int dim_z;
+
+ /** @brief The data type per component. */
+ astcenc_type data_type;
+
+ /** @brief The array of 2D slices, of length @c dim_z. */
+ void** data;
+};
+
+/**
+ * @brief A block encoding metadata query result.
+ *
+ * If the block is an error block or a constant color block or an error block all fields other than
+ * the profile, block dimensions, and error/constant indicator will be zero.
+ */
+struct astcenc_block_info
+{
+ /** @brief The block encoding color profile. */
+ astcenc_profile profile;
+
+ /** @brief The number of texels in the X dimension. */
+ unsigned int block_x;
+
+ /** @brief The number of texels in the Y dimension. */
+ unsigned int block_y;
+
+ /** @brief The number of texel in the Z dimension. */
+ unsigned int block_z;
+
+ /** @brief The number of texels in the block. */
+ unsigned int texel_count;
+
+ /** @brief True if this block is an error block. */
+ bool is_error_block;
+
+ /** @brief True if this block is a constant color block. */
+ bool is_constant_block;
+
+ /** @brief True if this block is an HDR block. */
+ bool is_hdr_block;
+
+ /** @brief True if this block uses two weight planes. */
+ bool is_dual_plane_block;
+
+ /** @brief The number of partitions if not constant color. */
+ unsigned int partition_count;
+
+ /** @brief The partition index if 2 - 4 partitions used. */
+ unsigned int partition_index;
+
+ /** @brief The component index of the second plane if dual plane. */
+ unsigned int dual_plane_component;
+
+ /** @brief The color endpoint encoding mode for each partition. */
+ unsigned int color_endpoint_modes[4];
+
+ /** @brief The number of color endpoint quantization levels. */
+ unsigned int color_level_count;
+
+ /** @brief The number of weight quantization levels. */
+ unsigned int weight_level_count;
+
+ /** @brief The number of weights in the X dimension. */
+ unsigned int weight_x;
+
+ /** @brief The number of weights in the Y dimension. */
+ unsigned int weight_y;
+
+ /** @brief The number of weights in the Z dimension. */
+ unsigned int weight_z;
+
+ /** @brief The unpacked color endpoints for each partition. */
+ float color_endpoints[4][2][4];
+
+ /** @brief The per-texel interpolation weights for the block. */
+ float weight_values_plane1[216];
+
+ /** @brief The per-texel interpolation weights for the block. */
+ float weight_values_plane2[216];
+
+ /** @brief The per-texel partition assignments for the block. */
+ uint8_t partition_assignment[216];
+};
+
+/**
+ * Populate a codec config based on default settings.
+ *
+ * Power users can edit the returned config struct to fine tune before allocating the context.
+ *
+ * @param profile Color profile.
+ * @param block_x ASTC block size X dimension.
+ * @param block_y ASTC block size Y dimension.
+ * @param block_z ASTC block size Z dimension.
+ * @param quality Search quality preset / effort level. Either an
+ * @c ASTCENC_PRE_* value, or a effort level between 0
+ * and 100. Performance is not linear between 0 and 100.
+
+ * @param flags A valid set of @c ASTCENC_FLG_* flag bits.
+ * @param[out] config Output config struct to populate.
+ *
+ * @return @c ASTCENC_SUCCESS on success, or an error if the inputs are invalid
+ * either individually, or in combination.
+ */
+ASTCENC_PUBLIC astcenc_error astcenc_config_init(
+ astcenc_profile profile,
+ unsigned int block_x,
+ unsigned int block_y,
+ unsigned int block_z,
+ float quality,
+ unsigned int flags,
+ astcenc_config* config);
+
+/**
+ * @brief Allocate a new codec context based on a config.
+ *
+ * This function allocates all of the memory resources and threads needed by the codec. This can be
+ * slow, so it is recommended that contexts are reused to serially compress or decompress multiple
+ * images to amortize setup cost.
+ *
+ * Contexts can be allocated to support only decompression using the @c ASTCENC_FLG_DECOMPRESS_ONLY
+ * flag when creating the configuration. The compression functions will fail if invoked. For a
+ * decompress-only library build the @c ASTCENC_FLG_DECOMPRESS_ONLY flag must be set when creating
+ * any context.
+ *
+ * @param[in] config Codec config.
+ * @param thread_count Thread count to configure for.
+ * @param[out] context Location to store an opaque context pointer.
+ *
+ * @return @c ASTCENC_SUCCESS on success, or an error if context creation failed.
+ */
+ASTCENC_PUBLIC astcenc_error astcenc_context_alloc(
+ const astcenc_config* config,
+ unsigned int thread_count,
+ astcenc_context** context);
+
+/**
+ * @brief Compress an image.
+ *
+ * A single context can only compress or decompress a single image at a time.
+ *
+ * For a context configured for multi-threading, any set of the N threads can call this function.
+ * Work will be dynamically scheduled across the threads available. Each thread must have a unique
+ * @c thread_index.
+ *
+ * @param context Codec context.
+ * @param[in,out] image An input image, in 2D slices.
+ * @param swizzle Compression data swizzle, applied before compression.
+ * @param[out] data_out Pointer to output data array.
+ * @param data_len Length of the output data array.
+ * @param thread_index Thread index [0..N-1] of calling thread.
+ *
+ * @return @c ASTCENC_SUCCESS on success, or an error if compression failed.
+ */
+ASTCENC_PUBLIC astcenc_error astcenc_compress_image(
+ astcenc_context* context,
+ astcenc_image* image,
+ const astcenc_swizzle* swizzle,
+ uint8_t* data_out,
+ size_t data_len,
+ unsigned int thread_index);
+
+/**
+ * @brief Reset the codec state for a new compression.
+ *
+ * The caller is responsible for synchronizing threads in the worker thread pool. This function must
+ * only be called when all threads have exited the @c astcenc_compress_image() function for image N,
+ * but before any thread enters it for image N + 1.
+ *
+ * Calling this is not required (but won't hurt), if the context is created for single threaded use.
+ *
+ * @param context Codec context.
+ *
+ * @return @c ASTCENC_SUCCESS on success, or an error if reset failed.
+ */
+ASTCENC_PUBLIC astcenc_error astcenc_compress_reset(
+ astcenc_context* context);
+
+/**
+ * @brief Decompress an image.
+ *
+ * @param context Codec context.
+ * @param[in] data Pointer to compressed data.
+ * @param data_len Length of the compressed data, in bytes.
+ * @param[in,out] image_out Output image.
+ * @param swizzle Decompression data swizzle, applied after decompression.
+ * @param thread_index Thread index [0..N-1] of calling thread.
+ *
+ * @return @c ASTCENC_SUCCESS on success, or an error if decompression failed.
+ */
+ASTCENC_PUBLIC astcenc_error astcenc_decompress_image(
+ astcenc_context* context,
+ const uint8_t* data,
+ size_t data_len,
+ astcenc_image* image_out,
+ const astcenc_swizzle* swizzle,
+ unsigned int thread_index);
+
+/**
+ * @brief Reset the codec state for a new decompression.
+ *
+ * The caller is responsible for synchronizing threads in the worker thread pool. This function must
+ * only be called when all threads have exited the @c astcenc_decompress_image() function for image
+ * N, but before any thread enters it for image N + 1.
+ *
+ * Calling this is not required (but won't hurt), if the context is created for single threaded use.
+ *
+ * @param context Codec context.
+ *
+ * @return @c ASTCENC_SUCCESS on success, or an error if reset failed.
+ */
+ASTCENC_PUBLIC astcenc_error astcenc_decompress_reset(
+ astcenc_context* context);
+
+/**
+ * Free the compressor context.
+ *
+ * @param context The codec context.
+ */
+ASTCENC_PUBLIC void astcenc_context_free(
+ astcenc_context* context);
+
+/**
+ * @brief Provide a high level summary of a block's encoding.
+ *
+ * This feature is primarily useful for codec developers but may be useful for developers building
+ * advanced content packaging pipelines.
+ *
+ * @param context Codec context.
+ * @param data One block of compressed ASTC data.
+ * @param info The output info structure to populate.
+ *
+ * @return @c ASTCENC_SUCCESS if the block was decoded, or an error otherwise. Note that this
+ * function will return success even if the block itself was an error block encoding, as the
+ * decode was correctly handled.
+ */
+ASTCENC_PUBLIC astcenc_error astcenc_get_block_info(
+ astcenc_context* context,
+ const uint8_t data[16],
+ astcenc_block_info* info);
+
+/**
+ * @brief Get a printable string for specific status code.
+ *
+ * @param status The status value.
+ *
+ * @return A human readable nul-terminated string.
+ */
+ASTCENC_PUBLIC const char* astcenc_get_error_string(
+ astcenc_error status);
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_averages_and_directions.cpp b/thirdparty/astcenc/astcenc_averages_and_directions.cpp
new file mode 100644
index 0000000000..d1f003844a
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_averages_and_directions.cpp
@@ -0,0 +1,995 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for finding dominant direction of a set of colors.
+ */
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+#include "astcenc_internal.h"
+
+#include <cassert>
+
+/**
+ * @brief Compute the average RGB color of each partition.
+ *
+ * The algorithm here uses a vectorized sequential scan and per-partition
+ * color accumulators, using select() to mask texel lanes in other partitions.
+ *
+ * We only accumulate sums for N-1 partitions during the scan; the value for
+ * the last partition can be computed given that we know the block-wide average
+ * already.
+ *
+ * Because of this we could reduce the loop iteration count so it "just" spans
+ * the max texel index needed for the N-1 partitions, which could need fewer
+ * iterations than the full block texel count. However, this makes the loop
+ * count erratic and causes more branch mispredictions so is a net loss.
+ *
+ * @param pi The partitioning to use.
+ * @param blk The block data to process.
+ * @param[out] averages The output averages. Unused partition indices will
+ * not be initialized, and lane<3> will be zero.
+ */
+static void compute_partition_averages_rgb(
+ const partition_info& pi,
+ const image_block& blk,
+ vfloat4 averages[BLOCK_MAX_PARTITIONS]
+) {
+ unsigned int partition_count = pi.partition_count;
+ unsigned int texel_count = blk.texel_count;
+ promise(texel_count > 0);
+
+ // For 1 partition just use the precomputed mean
+ if (partition_count == 1)
+ {
+ averages[0] = blk.data_mean.swz<0, 1, 2>();
+ }
+ // For 2 partitions scan results for partition 0, compute partition 1
+ else if (partition_count == 2)
+ {
+ vfloatacc pp_avg_rgb[3] {};
+
+ vint lane_id = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint texel_partition(pi.partition_of_texel + i);
+
+ vmask lane_mask = lane_id < vint(texel_count);
+ lane_id += vint(ASTCENC_SIMD_WIDTH);
+
+ vmask p0_mask = lane_mask & (texel_partition == vint(0));
+
+ vfloat data_r = loada(blk.data_r + i);
+ haccumulate(pp_avg_rgb[0], data_r, p0_mask);
+
+ vfloat data_g = loada(blk.data_g + i);
+ haccumulate(pp_avg_rgb[1], data_g, p0_mask);
+
+ vfloat data_b = loada(blk.data_b + i);
+ haccumulate(pp_avg_rgb[2], data_b, p0_mask);
+ }
+
+ vfloat4 block_total = blk.data_mean.swz<0, 1, 2>() * static_cast<float>(blk.texel_count);
+
+ vfloat4 p0_total = vfloat3(hadd_s(pp_avg_rgb[0]),
+ hadd_s(pp_avg_rgb[1]),
+ hadd_s(pp_avg_rgb[2]));
+
+ vfloat4 p1_total = block_total - p0_total;
+
+ averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]);
+ averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]);
+ }
+ // For 3 partitions scan results for partition 0/1, compute partition 2
+ else if (partition_count == 3)
+ {
+ vfloatacc pp_avg_rgb[2][3] {};
+
+ vint lane_id = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint texel_partition(pi.partition_of_texel + i);
+
+ vmask lane_mask = lane_id < vint(texel_count);
+ lane_id += vint(ASTCENC_SIMD_WIDTH);
+
+ vmask p0_mask = lane_mask & (texel_partition == vint(0));
+ vmask p1_mask = lane_mask & (texel_partition == vint(1));
+
+ vfloat data_r = loada(blk.data_r + i);
+ haccumulate(pp_avg_rgb[0][0], data_r, p0_mask);
+ haccumulate(pp_avg_rgb[1][0], data_r, p1_mask);
+
+ vfloat data_g = loada(blk.data_g + i);
+ haccumulate(pp_avg_rgb[0][1], data_g, p0_mask);
+ haccumulate(pp_avg_rgb[1][1], data_g, p1_mask);
+
+ vfloat data_b = loada(blk.data_b + i);
+ haccumulate(pp_avg_rgb[0][2], data_b, p0_mask);
+ haccumulate(pp_avg_rgb[1][2], data_b, p1_mask);
+ }
+
+ vfloat4 block_total = blk.data_mean.swz<0, 1, 2>() * static_cast<float>(blk.texel_count);
+
+ vfloat4 p0_total = vfloat3(hadd_s(pp_avg_rgb[0][0]),
+ hadd_s(pp_avg_rgb[0][1]),
+ hadd_s(pp_avg_rgb[0][2]));
+
+ vfloat4 p1_total = vfloat3(hadd_s(pp_avg_rgb[1][0]),
+ hadd_s(pp_avg_rgb[1][1]),
+ hadd_s(pp_avg_rgb[1][2]));
+
+ vfloat4 p2_total = block_total - p0_total - p1_total;
+
+ averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]);
+ averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]);
+ averages[2] = p2_total / static_cast<float>(pi.partition_texel_count[2]);
+ }
+ else
+ {
+ // For 4 partitions scan results for partition 0/1/2, compute partition 3
+ vfloatacc pp_avg_rgb[3][3] {};
+
+ vint lane_id = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint texel_partition(pi.partition_of_texel + i);
+
+ vmask lane_mask = lane_id < vint(texel_count);
+ lane_id += vint(ASTCENC_SIMD_WIDTH);
+
+ vmask p0_mask = lane_mask & (texel_partition == vint(0));
+ vmask p1_mask = lane_mask & (texel_partition == vint(1));
+ vmask p2_mask = lane_mask & (texel_partition == vint(2));
+
+ vfloat data_r = loada(blk.data_r + i);
+ haccumulate(pp_avg_rgb[0][0], data_r, p0_mask);
+ haccumulate(pp_avg_rgb[1][0], data_r, p1_mask);
+ haccumulate(pp_avg_rgb[2][0], data_r, p2_mask);
+
+ vfloat data_g = loada(blk.data_g + i);
+ haccumulate(pp_avg_rgb[0][1], data_g, p0_mask);
+ haccumulate(pp_avg_rgb[1][1], data_g, p1_mask);
+ haccumulate(pp_avg_rgb[2][1], data_g, p2_mask);
+
+ vfloat data_b = loada(blk.data_b + i);
+ haccumulate(pp_avg_rgb[0][2], data_b, p0_mask);
+ haccumulate(pp_avg_rgb[1][2], data_b, p1_mask);
+ haccumulate(pp_avg_rgb[2][2], data_b, p2_mask);
+ }
+
+ vfloat4 block_total = blk.data_mean.swz<0, 1, 2>() * static_cast<float>(blk.texel_count);
+
+ vfloat4 p0_total = vfloat3(hadd_s(pp_avg_rgb[0][0]),
+ hadd_s(pp_avg_rgb[0][1]),
+ hadd_s(pp_avg_rgb[0][2]));
+
+ vfloat4 p1_total = vfloat3(hadd_s(pp_avg_rgb[1][0]),
+ hadd_s(pp_avg_rgb[1][1]),
+ hadd_s(pp_avg_rgb[1][2]));
+
+ vfloat4 p2_total = vfloat3(hadd_s(pp_avg_rgb[2][0]),
+ hadd_s(pp_avg_rgb[2][1]),
+ hadd_s(pp_avg_rgb[2][2]));
+
+ vfloat4 p3_total = block_total - p0_total - p1_total- p2_total;
+
+ averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]);
+ averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]);
+ averages[2] = p2_total / static_cast<float>(pi.partition_texel_count[2]);
+ averages[3] = p3_total / static_cast<float>(pi.partition_texel_count[3]);
+ }
+}
+
+/**
+ * @brief Compute the average RGBA color of each partition.
+ *
+ * The algorithm here uses a vectorized sequential scan and per-partition
+ * color accumulators, using select() to mask texel lanes in other partitions.
+ *
+ * We only accumulate sums for N-1 partitions during the scan; the value for
+ * the last partition can be computed given that we know the block-wide average
+ * already.
+ *
+ * Because of this we could reduce the loop iteration count so it "just" spans
+ * the max texel index needed for the N-1 partitions, which could need fewer
+ * iterations than the full block texel count. However, this makes the loop
+ * count erratic and causes more branch mispredictions so is a net loss.
+ *
+ * @param pi The partitioning to use.
+ * @param blk The block data to process.
+ * @param[out] averages The output averages. Unused partition indices will
+ * not be initialized.
+ */
+static void compute_partition_averages_rgba(
+ const partition_info& pi,
+ const image_block& blk,
+ vfloat4 averages[BLOCK_MAX_PARTITIONS]
+) {
+ unsigned int partition_count = pi.partition_count;
+ unsigned int texel_count = blk.texel_count;
+ promise(texel_count > 0);
+
+ // For 1 partition just use the precomputed mean
+ if (partition_count == 1)
+ {
+ averages[0] = blk.data_mean;
+ }
+ // For 2 partitions scan results for partition 0, compute partition 1
+ else if (partition_count == 2)
+ {
+ vfloat4 pp_avg_rgba[4] {};
+
+ vint lane_id = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint texel_partition(pi.partition_of_texel + i);
+
+ vmask lane_mask = lane_id < vint(texel_count);
+ lane_id += vint(ASTCENC_SIMD_WIDTH);
+
+ vmask p0_mask = lane_mask & (texel_partition == vint(0));
+
+ vfloat data_r = loada(blk.data_r + i);
+ haccumulate(pp_avg_rgba[0], data_r, p0_mask);
+
+ vfloat data_g = loada(blk.data_g + i);
+ haccumulate(pp_avg_rgba[1], data_g, p0_mask);
+
+ vfloat data_b = loada(blk.data_b + i);
+ haccumulate(pp_avg_rgba[2], data_b, p0_mask);
+
+ vfloat data_a = loada(blk.data_a + i);
+ haccumulate(pp_avg_rgba[3], data_a, p0_mask);
+ }
+
+ vfloat4 block_total = blk.data_mean * static_cast<float>(blk.texel_count);
+
+ vfloat4 p0_total = vfloat4(hadd_s(pp_avg_rgba[0]),
+ hadd_s(pp_avg_rgba[1]),
+ hadd_s(pp_avg_rgba[2]),
+ hadd_s(pp_avg_rgba[3]));
+
+ vfloat4 p1_total = block_total - p0_total;
+
+ averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]);
+ averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]);
+ }
+ // For 3 partitions scan results for partition 0/1, compute partition 2
+ else if (partition_count == 3)
+ {
+ vfloat4 pp_avg_rgba[2][4] {};
+
+ vint lane_id = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint texel_partition(pi.partition_of_texel + i);
+
+ vmask lane_mask = lane_id < vint(texel_count);
+ lane_id += vint(ASTCENC_SIMD_WIDTH);
+
+ vmask p0_mask = lane_mask & (texel_partition == vint(0));
+ vmask p1_mask = lane_mask & (texel_partition == vint(1));
+
+ vfloat data_r = loada(blk.data_r + i);
+ haccumulate(pp_avg_rgba[0][0], data_r, p0_mask);
+ haccumulate(pp_avg_rgba[1][0], data_r, p1_mask);
+
+ vfloat data_g = loada(blk.data_g + i);
+ haccumulate(pp_avg_rgba[0][1], data_g, p0_mask);
+ haccumulate(pp_avg_rgba[1][1], data_g, p1_mask);
+
+ vfloat data_b = loada(blk.data_b + i);
+ haccumulate(pp_avg_rgba[0][2], data_b, p0_mask);
+ haccumulate(pp_avg_rgba[1][2], data_b, p1_mask);
+
+ vfloat data_a = loada(blk.data_a + i);
+ haccumulate(pp_avg_rgba[0][3], data_a, p0_mask);
+ haccumulate(pp_avg_rgba[1][3], data_a, p1_mask);
+ }
+
+ vfloat4 block_total = blk.data_mean * static_cast<float>(blk.texel_count);
+
+ vfloat4 p0_total = vfloat4(hadd_s(pp_avg_rgba[0][0]),
+ hadd_s(pp_avg_rgba[0][1]),
+ hadd_s(pp_avg_rgba[0][2]),
+ hadd_s(pp_avg_rgba[0][3]));
+
+ vfloat4 p1_total = vfloat4(hadd_s(pp_avg_rgba[1][0]),
+ hadd_s(pp_avg_rgba[1][1]),
+ hadd_s(pp_avg_rgba[1][2]),
+ hadd_s(pp_avg_rgba[1][3]));
+
+ vfloat4 p2_total = block_total - p0_total - p1_total;
+
+ averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]);
+ averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]);
+ averages[2] = p2_total / static_cast<float>(pi.partition_texel_count[2]);
+ }
+ else
+ {
+ // For 4 partitions scan results for partition 0/1/2, compute partition 3
+ vfloat4 pp_avg_rgba[3][4] {};
+
+ vint lane_id = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint texel_partition(pi.partition_of_texel + i);
+
+ vmask lane_mask = lane_id < vint(texel_count);
+ lane_id += vint(ASTCENC_SIMD_WIDTH);
+
+ vmask p0_mask = lane_mask & (texel_partition == vint(0));
+ vmask p1_mask = lane_mask & (texel_partition == vint(1));
+ vmask p2_mask = lane_mask & (texel_partition == vint(2));
+
+ vfloat data_r = loada(blk.data_r + i);
+ haccumulate(pp_avg_rgba[0][0], data_r, p0_mask);
+ haccumulate(pp_avg_rgba[1][0], data_r, p1_mask);
+ haccumulate(pp_avg_rgba[2][0], data_r, p2_mask);
+
+ vfloat data_g = loada(blk.data_g + i);
+ haccumulate(pp_avg_rgba[0][1], data_g, p0_mask);
+ haccumulate(pp_avg_rgba[1][1], data_g, p1_mask);
+ haccumulate(pp_avg_rgba[2][1], data_g, p2_mask);
+
+ vfloat data_b = loada(blk.data_b + i);
+ haccumulate(pp_avg_rgba[0][2], data_b, p0_mask);
+ haccumulate(pp_avg_rgba[1][2], data_b, p1_mask);
+ haccumulate(pp_avg_rgba[2][2], data_b, p2_mask);
+
+ vfloat data_a = loada(blk.data_a + i);
+ haccumulate(pp_avg_rgba[0][3], data_a, p0_mask);
+ haccumulate(pp_avg_rgba[1][3], data_a, p1_mask);
+ haccumulate(pp_avg_rgba[2][3], data_a, p2_mask);
+ }
+
+ vfloat4 block_total = blk.data_mean * static_cast<float>(blk.texel_count);
+
+ vfloat4 p0_total = vfloat4(hadd_s(pp_avg_rgba[0][0]),
+ hadd_s(pp_avg_rgba[0][1]),
+ hadd_s(pp_avg_rgba[0][2]),
+ hadd_s(pp_avg_rgba[0][3]));
+
+ vfloat4 p1_total = vfloat4(hadd_s(pp_avg_rgba[1][0]),
+ hadd_s(pp_avg_rgba[1][1]),
+ hadd_s(pp_avg_rgba[1][2]),
+ hadd_s(pp_avg_rgba[1][3]));
+
+ vfloat4 p2_total = vfloat4(hadd_s(pp_avg_rgba[2][0]),
+ hadd_s(pp_avg_rgba[2][1]),
+ hadd_s(pp_avg_rgba[2][2]),
+ hadd_s(pp_avg_rgba[2][3]));
+
+ vfloat4 p3_total = block_total - p0_total - p1_total- p2_total;
+
+ averages[0] = p0_total / static_cast<float>(pi.partition_texel_count[0]);
+ averages[1] = p1_total / static_cast<float>(pi.partition_texel_count[1]);
+ averages[2] = p2_total / static_cast<float>(pi.partition_texel_count[2]);
+ averages[3] = p3_total / static_cast<float>(pi.partition_texel_count[3]);
+ }
+}
+
+/* See header for documentation. */
+void compute_avgs_and_dirs_4_comp(
+ const partition_info& pi,
+ const image_block& blk,
+ partition_metrics pm[BLOCK_MAX_PARTITIONS]
+) {
+ int partition_count = pi.partition_count;
+ promise(partition_count > 0);
+
+ // Pre-compute partition_averages
+ vfloat4 partition_averages[BLOCK_MAX_PARTITIONS];
+ compute_partition_averages_rgba(pi, blk, partition_averages);
+
+ for (int partition = 0; partition < partition_count; partition++)
+ {
+ const uint8_t *texel_indexes = pi.texels_of_partition[partition];
+ unsigned int texel_count = pi.partition_texel_count[partition];
+ promise(texel_count > 0);
+
+ vfloat4 average = partition_averages[partition];
+ pm[partition].avg = average;
+
+ vfloat4 sum_xp = vfloat4::zero();
+ vfloat4 sum_yp = vfloat4::zero();
+ vfloat4 sum_zp = vfloat4::zero();
+ vfloat4 sum_wp = vfloat4::zero();
+
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ unsigned int iwt = texel_indexes[i];
+ vfloat4 texel_datum = blk.texel(iwt);
+ texel_datum = texel_datum - average;
+
+ vfloat4 zero = vfloat4::zero();
+
+ vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero;
+ sum_xp += select(zero, texel_datum, tdm0);
+
+ vmask4 tdm1 = texel_datum.swz<1,1,1,1>() > zero;
+ sum_yp += select(zero, texel_datum, tdm1);
+
+ vmask4 tdm2 = texel_datum.swz<2,2,2,2>() > zero;
+ sum_zp += select(zero, texel_datum, tdm2);
+
+ vmask4 tdm3 = texel_datum.swz<3,3,3,3>() > zero;
+ sum_wp += select(zero, texel_datum, tdm3);
+ }
+
+ vfloat4 prod_xp = dot(sum_xp, sum_xp);
+ vfloat4 prod_yp = dot(sum_yp, sum_yp);
+ vfloat4 prod_zp = dot(sum_zp, sum_zp);
+ vfloat4 prod_wp = dot(sum_wp, sum_wp);
+
+ vfloat4 best_vector = sum_xp;
+ vfloat4 best_sum = prod_xp;
+
+ vmask4 mask = prod_yp > best_sum;
+ best_vector = select(best_vector, sum_yp, mask);
+ best_sum = select(best_sum, prod_yp, mask);
+
+ mask = prod_zp > best_sum;
+ best_vector = select(best_vector, sum_zp, mask);
+ best_sum = select(best_sum, prod_zp, mask);
+
+ mask = prod_wp > best_sum;
+ best_vector = select(best_vector, sum_wp, mask);
+
+ pm[partition].dir = best_vector;
+ }
+}
+
+/* See header for documentation. */
+void compute_avgs_and_dirs_3_comp(
+ const partition_info& pi,
+ const image_block& blk,
+ unsigned int omitted_component,
+ partition_metrics pm[BLOCK_MAX_PARTITIONS]
+) {
+ // Pre-compute partition_averages
+ vfloat4 partition_averages[BLOCK_MAX_PARTITIONS];
+ compute_partition_averages_rgba(pi, blk, partition_averages);
+
+ const float* data_vr = blk.data_r;
+ const float* data_vg = blk.data_g;
+ const float* data_vb = blk.data_b;
+
+ // TODO: Data-driven permute would be useful to avoid this ...
+ if (omitted_component == 0)
+ {
+ partition_averages[0] = partition_averages[0].swz<1, 2, 3>();
+ partition_averages[1] = partition_averages[1].swz<1, 2, 3>();
+ partition_averages[2] = partition_averages[2].swz<1, 2, 3>();
+ partition_averages[3] = partition_averages[3].swz<1, 2, 3>();
+
+ data_vr = blk.data_g;
+ data_vg = blk.data_b;
+ data_vb = blk.data_a;
+ }
+ else if (omitted_component == 1)
+ {
+ partition_averages[0] = partition_averages[0].swz<0, 2, 3>();
+ partition_averages[1] = partition_averages[1].swz<0, 2, 3>();
+ partition_averages[2] = partition_averages[2].swz<0, 2, 3>();
+ partition_averages[3] = partition_averages[3].swz<0, 2, 3>();
+
+ data_vg = blk.data_b;
+ data_vb = blk.data_a;
+ }
+ else if (omitted_component == 2)
+ {
+ partition_averages[0] = partition_averages[0].swz<0, 1, 3>();
+ partition_averages[1] = partition_averages[1].swz<0, 1, 3>();
+ partition_averages[2] = partition_averages[2].swz<0, 1, 3>();
+ partition_averages[3] = partition_averages[3].swz<0, 1, 3>();
+
+ data_vb = blk.data_a;
+ }
+ else
+ {
+ partition_averages[0] = partition_averages[0].swz<0, 1, 2>();
+ partition_averages[1] = partition_averages[1].swz<0, 1, 2>();
+ partition_averages[2] = partition_averages[2].swz<0, 1, 2>();
+ partition_averages[3] = partition_averages[3].swz<0, 1, 2>();
+ }
+
+ unsigned int partition_count = pi.partition_count;
+ promise(partition_count > 0);
+
+ for (unsigned int partition = 0; partition < partition_count; partition++)
+ {
+ const uint8_t *texel_indexes = pi.texels_of_partition[partition];
+ unsigned int texel_count = pi.partition_texel_count[partition];
+ promise(texel_count > 0);
+
+ vfloat4 average = partition_averages[partition];
+ pm[partition].avg = average;
+
+ vfloat4 sum_xp = vfloat4::zero();
+ vfloat4 sum_yp = vfloat4::zero();
+ vfloat4 sum_zp = vfloat4::zero();
+
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ unsigned int iwt = texel_indexes[i];
+
+ vfloat4 texel_datum = vfloat3(data_vr[iwt],
+ data_vg[iwt],
+ data_vb[iwt]);
+ texel_datum = texel_datum - average;
+
+ vfloat4 zero = vfloat4::zero();
+
+ vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero;
+ sum_xp += select(zero, texel_datum, tdm0);
+
+ vmask4 tdm1 = texel_datum.swz<1,1,1,1>() > zero;
+ sum_yp += select(zero, texel_datum, tdm1);
+
+ vmask4 tdm2 = texel_datum.swz<2,2,2,2>() > zero;
+ sum_zp += select(zero, texel_datum, tdm2);
+ }
+
+ vfloat4 prod_xp = dot(sum_xp, sum_xp);
+ vfloat4 prod_yp = dot(sum_yp, sum_yp);
+ vfloat4 prod_zp = dot(sum_zp, sum_zp);
+
+ vfloat4 best_vector = sum_xp;
+ vfloat4 best_sum = prod_xp;
+
+ vmask4 mask = prod_yp > best_sum;
+ best_vector = select(best_vector, sum_yp, mask);
+ best_sum = select(best_sum, prod_yp, mask);
+
+ mask = prod_zp > best_sum;
+ best_vector = select(best_vector, sum_zp, mask);
+
+ pm[partition].dir = best_vector;
+ }
+}
+
+/* See header for documentation. */
+void compute_avgs_and_dirs_3_comp_rgb(
+ const partition_info& pi,
+ const image_block& blk,
+ partition_metrics pm[BLOCK_MAX_PARTITIONS]
+) {
+ unsigned int partition_count = pi.partition_count;
+ promise(partition_count > 0);
+
+ // Pre-compute partition_averages
+ vfloat4 partition_averages[BLOCK_MAX_PARTITIONS];
+ compute_partition_averages_rgb(pi, blk, partition_averages);
+
+ for (unsigned int partition = 0; partition < partition_count; partition++)
+ {
+ const uint8_t *texel_indexes = pi.texels_of_partition[partition];
+ unsigned int texel_count = pi.partition_texel_count[partition];
+ promise(texel_count > 0);
+
+ vfloat4 average = partition_averages[partition];
+ pm[partition].avg = average;
+
+ vfloat4 sum_xp = vfloat4::zero();
+ vfloat4 sum_yp = vfloat4::zero();
+ vfloat4 sum_zp = vfloat4::zero();
+
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ unsigned int iwt = texel_indexes[i];
+
+ vfloat4 texel_datum = blk.texel3(iwt);
+ texel_datum = texel_datum - average;
+
+ vfloat4 zero = vfloat4::zero();
+
+ vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero;
+ sum_xp += select(zero, texel_datum, tdm0);
+
+ vmask4 tdm1 = texel_datum.swz<1,1,1,1>() > zero;
+ sum_yp += select(zero, texel_datum, tdm1);
+
+ vmask4 tdm2 = texel_datum.swz<2,2,2,2>() > zero;
+ sum_zp += select(zero, texel_datum, tdm2);
+ }
+
+ vfloat4 prod_xp = dot(sum_xp, sum_xp);
+ vfloat4 prod_yp = dot(sum_yp, sum_yp);
+ vfloat4 prod_zp = dot(sum_zp, sum_zp);
+
+ vfloat4 best_vector = sum_xp;
+ vfloat4 best_sum = prod_xp;
+
+ vmask4 mask = prod_yp > best_sum;
+ best_vector = select(best_vector, sum_yp, mask);
+ best_sum = select(best_sum, prod_yp, mask);
+
+ mask = prod_zp > best_sum;
+ best_vector = select(best_vector, sum_zp, mask);
+
+ pm[partition].dir = best_vector;
+ }
+}
+
+/* See header for documentation. */
+void compute_avgs_and_dirs_2_comp(
+ const partition_info& pt,
+ const image_block& blk,
+ unsigned int component1,
+ unsigned int component2,
+ partition_metrics pm[BLOCK_MAX_PARTITIONS]
+) {
+ vfloat4 average;
+
+ const float* data_vr = nullptr;
+ const float* data_vg = nullptr;
+
+ if (component1 == 0 && component2 == 1)
+ {
+ average = blk.data_mean.swz<0, 1>();
+
+ data_vr = blk.data_r;
+ data_vg = blk.data_g;
+ }
+ else if (component1 == 0 && component2 == 2)
+ {
+ average = blk.data_mean.swz<0, 2>();
+
+ data_vr = blk.data_r;
+ data_vg = blk.data_b;
+ }
+ else // (component1 == 1 && component2 == 2)
+ {
+ assert(component1 == 1 && component2 == 2);
+
+ average = blk.data_mean.swz<1, 2>();
+
+ data_vr = blk.data_g;
+ data_vg = blk.data_b;
+ }
+
+ unsigned int partition_count = pt.partition_count;
+ promise(partition_count > 0);
+
+ for (unsigned int partition = 0; partition < partition_count; partition++)
+ {
+ const uint8_t *texel_indexes = pt.texels_of_partition[partition];
+ unsigned int texel_count = pt.partition_texel_count[partition];
+ promise(texel_count > 0);
+
+ // Only compute a partition mean if more than one partition
+ if (partition_count > 1)
+ {
+ average = vfloat4::zero();
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ unsigned int iwt = texel_indexes[i];
+ average += vfloat2(data_vr[iwt], data_vg[iwt]);
+ }
+
+ average = average / static_cast<float>(texel_count);
+ }
+
+ pm[partition].avg = average;
+
+ vfloat4 sum_xp = vfloat4::zero();
+ vfloat4 sum_yp = vfloat4::zero();
+
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ unsigned int iwt = texel_indexes[i];
+ vfloat4 texel_datum = vfloat2(data_vr[iwt], data_vg[iwt]);
+ texel_datum = texel_datum - average;
+
+ vfloat4 zero = vfloat4::zero();
+
+ vmask4 tdm0 = texel_datum.swz<0,0,0,0>() > zero;
+ sum_xp += select(zero, texel_datum, tdm0);
+
+ vmask4 tdm1 = texel_datum.swz<1,1,1,1>() > zero;
+ sum_yp += select(zero, texel_datum, tdm1);
+ }
+
+ vfloat4 prod_xp = dot(sum_xp, sum_xp);
+ vfloat4 prod_yp = dot(sum_yp, sum_yp);
+
+ vfloat4 best_vector = sum_xp;
+ vfloat4 best_sum = prod_xp;
+
+ vmask4 mask = prod_yp > best_sum;
+ best_vector = select(best_vector, sum_yp, mask);
+
+ pm[partition].dir = best_vector;
+ }
+}
+
+/* See header for documentation. */
+void compute_error_squared_rgba(
+ const partition_info& pi,
+ const image_block& blk,
+ const processed_line4 uncor_plines[BLOCK_MAX_PARTITIONS],
+ const processed_line4 samec_plines[BLOCK_MAX_PARTITIONS],
+ float uncor_lengths[BLOCK_MAX_PARTITIONS],
+ float samec_lengths[BLOCK_MAX_PARTITIONS],
+ float& uncor_error,
+ float& samec_error
+) {
+ unsigned int partition_count = pi.partition_count;
+ promise(partition_count > 0);
+
+ vfloatacc uncor_errorsumv = vfloatacc::zero();
+ vfloatacc samec_errorsumv = vfloatacc::zero();
+
+ for (unsigned int partition = 0; partition < partition_count; partition++)
+ {
+ const uint8_t *texel_indexes = pi.texels_of_partition[partition];
+
+ float uncor_loparam = 1e10f;
+ float uncor_hiparam = -1e10f;
+
+ float samec_loparam = 1e10f;
+ float samec_hiparam = -1e10f;
+
+ processed_line4 l_uncor = uncor_plines[partition];
+ processed_line4 l_samec = samec_plines[partition];
+
+ unsigned int texel_count = pi.partition_texel_count[partition];
+ promise(texel_count > 0);
+
+ // Vectorize some useful scalar inputs
+ vfloat l_uncor_bs0(l_uncor.bs.lane<0>());
+ vfloat l_uncor_bs1(l_uncor.bs.lane<1>());
+ vfloat l_uncor_bs2(l_uncor.bs.lane<2>());
+ vfloat l_uncor_bs3(l_uncor.bs.lane<3>());
+
+ vfloat l_uncor_amod0(l_uncor.amod.lane<0>());
+ vfloat l_uncor_amod1(l_uncor.amod.lane<1>());
+ vfloat l_uncor_amod2(l_uncor.amod.lane<2>());
+ vfloat l_uncor_amod3(l_uncor.amod.lane<3>());
+
+ vfloat l_samec_bs0(l_samec.bs.lane<0>());
+ vfloat l_samec_bs1(l_samec.bs.lane<1>());
+ vfloat l_samec_bs2(l_samec.bs.lane<2>());
+ vfloat l_samec_bs3(l_samec.bs.lane<3>());
+
+ assert(all(l_samec.amod == vfloat4(0.0f)));
+
+ vfloat uncor_loparamv(1e10f);
+ vfloat uncor_hiparamv(-1e10f);
+
+ vfloat samec_loparamv(1e10f);
+ vfloat samec_hiparamv(-1e10f);
+
+ vfloat ew_r(blk.channel_weight.lane<0>());
+ vfloat ew_g(blk.channel_weight.lane<1>());
+ vfloat ew_b(blk.channel_weight.lane<2>());
+ vfloat ew_a(blk.channel_weight.lane<3>());
+
+ // This implementation over-shoots, but this is safe as we initialize the texel_indexes
+ // array to extend the last value. This means min/max are not impacted, but we need to mask
+ // out the dummy values when we compute the line weighting.
+ vint lane_ids = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vmask mask = lane_ids < vint(texel_count);
+ vint texel_idxs(texel_indexes + i);
+
+ vfloat data_r = gatherf(blk.data_r, texel_idxs);
+ vfloat data_g = gatherf(blk.data_g, texel_idxs);
+ vfloat data_b = gatherf(blk.data_b, texel_idxs);
+ vfloat data_a = gatherf(blk.data_a, texel_idxs);
+
+ vfloat uncor_param = (data_r * l_uncor_bs0)
+ + (data_g * l_uncor_bs1)
+ + (data_b * l_uncor_bs2)
+ + (data_a * l_uncor_bs3);
+
+ uncor_loparamv = min(uncor_param, uncor_loparamv);
+ uncor_hiparamv = max(uncor_param, uncor_hiparamv);
+
+ vfloat uncor_dist0 = (l_uncor_amod0 - data_r)
+ + (uncor_param * l_uncor_bs0);
+ vfloat uncor_dist1 = (l_uncor_amod1 - data_g)
+ + (uncor_param * l_uncor_bs1);
+ vfloat uncor_dist2 = (l_uncor_amod2 - data_b)
+ + (uncor_param * l_uncor_bs2);
+ vfloat uncor_dist3 = (l_uncor_amod3 - data_a)
+ + (uncor_param * l_uncor_bs3);
+
+ vfloat uncor_err = (ew_r * uncor_dist0 * uncor_dist0)
+ + (ew_g * uncor_dist1 * uncor_dist1)
+ + (ew_b * uncor_dist2 * uncor_dist2)
+ + (ew_a * uncor_dist3 * uncor_dist3);
+
+ haccumulate(uncor_errorsumv, uncor_err, mask);
+
+ // Process samechroma data
+ vfloat samec_param = (data_r * l_samec_bs0)
+ + (data_g * l_samec_bs1)
+ + (data_b * l_samec_bs2)
+ + (data_a * l_samec_bs3);
+
+ samec_loparamv = min(samec_param, samec_loparamv);
+ samec_hiparamv = max(samec_param, samec_hiparamv);
+
+ vfloat samec_dist0 = samec_param * l_samec_bs0 - data_r;
+ vfloat samec_dist1 = samec_param * l_samec_bs1 - data_g;
+ vfloat samec_dist2 = samec_param * l_samec_bs2 - data_b;
+ vfloat samec_dist3 = samec_param * l_samec_bs3 - data_a;
+
+ vfloat samec_err = (ew_r * samec_dist0 * samec_dist0)
+ + (ew_g * samec_dist1 * samec_dist1)
+ + (ew_b * samec_dist2 * samec_dist2)
+ + (ew_a * samec_dist3 * samec_dist3);
+
+ haccumulate(samec_errorsumv, samec_err, mask);
+
+ lane_ids += vint(ASTCENC_SIMD_WIDTH);
+ }
+
+ uncor_loparam = hmin_s(uncor_loparamv);
+ uncor_hiparam = hmax_s(uncor_hiparamv);
+
+ samec_loparam = hmin_s(samec_loparamv);
+ samec_hiparam = hmax_s(samec_hiparamv);
+
+ float uncor_linelen = uncor_hiparam - uncor_loparam;
+ float samec_linelen = samec_hiparam - samec_loparam;
+
+ // Turn very small numbers and NaNs into a small number
+ uncor_lengths[partition] = astc::max(uncor_linelen, 1e-7f);
+ samec_lengths[partition] = astc::max(samec_linelen, 1e-7f);
+ }
+
+ uncor_error = hadd_s(uncor_errorsumv);
+ samec_error = hadd_s(samec_errorsumv);
+}
+
+/* See header for documentation. */
+void compute_error_squared_rgb(
+ const partition_info& pi,
+ const image_block& blk,
+ partition_lines3 plines[BLOCK_MAX_PARTITIONS],
+ float& uncor_error,
+ float& samec_error
+) {
+ unsigned int partition_count = pi.partition_count;
+ promise(partition_count > 0);
+
+ vfloatacc uncor_errorsumv = vfloatacc::zero();
+ vfloatacc samec_errorsumv = vfloatacc::zero();
+
+ for (unsigned int partition = 0; partition < partition_count; partition++)
+ {
+ partition_lines3& pl = plines[partition];
+ const uint8_t *texel_indexes = pi.texels_of_partition[partition];
+ unsigned int texel_count = pi.partition_texel_count[partition];
+ promise(texel_count > 0);
+
+ float uncor_loparam = 1e10f;
+ float uncor_hiparam = -1e10f;
+
+ float samec_loparam = 1e10f;
+ float samec_hiparam = -1e10f;
+
+ processed_line3 l_uncor = pl.uncor_pline;
+ processed_line3 l_samec = pl.samec_pline;
+
+ // This implementation is an example vectorization of this function.
+ // It works for - the codec is a 2-4% faster than not vectorizing - but
+ // the benefit is limited by the use of gathers and register pressure
+
+ // Vectorize some useful scalar inputs
+ vfloat l_uncor_bs0(l_uncor.bs.lane<0>());
+ vfloat l_uncor_bs1(l_uncor.bs.lane<1>());
+ vfloat l_uncor_bs2(l_uncor.bs.lane<2>());
+
+ vfloat l_uncor_amod0(l_uncor.amod.lane<0>());
+ vfloat l_uncor_amod1(l_uncor.amod.lane<1>());
+ vfloat l_uncor_amod2(l_uncor.amod.lane<2>());
+
+ vfloat l_samec_bs0(l_samec.bs.lane<0>());
+ vfloat l_samec_bs1(l_samec.bs.lane<1>());
+ vfloat l_samec_bs2(l_samec.bs.lane<2>());
+
+ assert(all(l_samec.amod == vfloat4(0.0f)));
+
+ vfloat uncor_loparamv(1e10f);
+ vfloat uncor_hiparamv(-1e10f);
+
+ vfloat samec_loparamv(1e10f);
+ vfloat samec_hiparamv(-1e10f);
+
+ vfloat ew_r(blk.channel_weight.lane<0>());
+ vfloat ew_g(blk.channel_weight.lane<1>());
+ vfloat ew_b(blk.channel_weight.lane<2>());
+
+ // This implementation over-shoots, but this is safe as we initialize the weights array
+ // to extend the last value. This means min/max are not impacted, but we need to mask
+ // out the dummy values when we compute the line weighting.
+ vint lane_ids = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vmask mask = lane_ids < vint(texel_count);
+ vint texel_idxs(texel_indexes + i);
+
+ vfloat data_r = gatherf(blk.data_r, texel_idxs);
+ vfloat data_g = gatherf(blk.data_g, texel_idxs);
+ vfloat data_b = gatherf(blk.data_b, texel_idxs);
+
+ vfloat uncor_param = (data_r * l_uncor_bs0)
+ + (data_g * l_uncor_bs1)
+ + (data_b * l_uncor_bs2);
+
+ uncor_loparamv = min(uncor_param, uncor_loparamv);
+ uncor_hiparamv = max(uncor_param, uncor_hiparamv);
+
+ vfloat uncor_dist0 = (l_uncor_amod0 - data_r)
+ + (uncor_param * l_uncor_bs0);
+ vfloat uncor_dist1 = (l_uncor_amod1 - data_g)
+ + (uncor_param * l_uncor_bs1);
+ vfloat uncor_dist2 = (l_uncor_amod2 - data_b)
+ + (uncor_param * l_uncor_bs2);
+
+ vfloat uncor_err = (ew_r * uncor_dist0 * uncor_dist0)
+ + (ew_g * uncor_dist1 * uncor_dist1)
+ + (ew_b * uncor_dist2 * uncor_dist2);
+
+ haccumulate(uncor_errorsumv, uncor_err, mask);
+
+ // Process samechroma data
+ vfloat samec_param = (data_r * l_samec_bs0)
+ + (data_g * l_samec_bs1)
+ + (data_b * l_samec_bs2);
+
+ samec_loparamv = min(samec_param, samec_loparamv);
+ samec_hiparamv = max(samec_param, samec_hiparamv);
+
+ vfloat samec_dist0 = samec_param * l_samec_bs0 - data_r;
+ vfloat samec_dist1 = samec_param * l_samec_bs1 - data_g;
+ vfloat samec_dist2 = samec_param * l_samec_bs2 - data_b;
+
+ vfloat samec_err = (ew_r * samec_dist0 * samec_dist0)
+ + (ew_g * samec_dist1 * samec_dist1)
+ + (ew_b * samec_dist2 * samec_dist2);
+
+ haccumulate(samec_errorsumv, samec_err, mask);
+
+ lane_ids += vint(ASTCENC_SIMD_WIDTH);
+ }
+
+ uncor_loparam = hmin_s(uncor_loparamv);
+ uncor_hiparam = hmax_s(uncor_hiparamv);
+
+ samec_loparam = hmin_s(samec_loparamv);
+ samec_hiparam = hmax_s(samec_hiparamv);
+
+ float uncor_linelen = uncor_hiparam - uncor_loparam;
+ float samec_linelen = samec_hiparam - samec_loparam;
+
+ // Turn very small numbers and NaNs into a small number
+ pl.uncor_line_len = astc::max(uncor_linelen, 1e-7f);
+ pl.samec_line_len = astc::max(samec_linelen, 1e-7f);
+ }
+
+ uncor_error = hadd_s(uncor_errorsumv);
+ samec_error = hadd_s(samec_errorsumv);
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_block_sizes.cpp b/thirdparty/astcenc/astcenc_block_sizes.cpp
new file mode 100644
index 0000000000..1c22d06a5c
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_block_sizes.cpp
@@ -0,0 +1,1184 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions to generate block size descriptor and decimation tables.
+ */
+
+#include "astcenc_internal.h"
+
+/**
+ * @brief Decode the properties of an encoded 2D block mode.
+ *
+ * @param block_mode The encoded block mode.
+ * @param[out] x_weights The number of weights in the X dimension.
+ * @param[out] y_weights The number of weights in the Y dimension.
+ * @param[out] is_dual_plane True if this block mode has two weight planes.
+ * @param[out] quant_mode The quantization level for the weights.
+ * @param[out] weight_bits The storage bit count for the weights.
+ *
+ * @return Returns true if a valid mode, false otherwise.
+ */
+static bool decode_block_mode_2d(
+ unsigned int block_mode,
+ unsigned int& x_weights,
+ unsigned int& y_weights,
+ bool& is_dual_plane,
+ unsigned int& quant_mode,
+ unsigned int& weight_bits
+) {
+ unsigned int base_quant_mode = (block_mode >> 4) & 1;
+ unsigned int H = (block_mode >> 9) & 1;
+ unsigned int D = (block_mode >> 10) & 1;
+ unsigned int A = (block_mode >> 5) & 0x3;
+
+ x_weights = 0;
+ y_weights = 0;
+
+ if ((block_mode & 3) != 0)
+ {
+ base_quant_mode |= (block_mode & 3) << 1;
+ unsigned int B = (block_mode >> 7) & 3;
+ switch ((block_mode >> 2) & 3)
+ {
+ case 0:
+ x_weights = B + 4;
+ y_weights = A + 2;
+ break;
+ case 1:
+ x_weights = B + 8;
+ y_weights = A + 2;
+ break;
+ case 2:
+ x_weights = A + 2;
+ y_weights = B + 8;
+ break;
+ case 3:
+ B &= 1;
+ if (block_mode & 0x100)
+ {
+ x_weights = B + 2;
+ y_weights = A + 2;
+ }
+ else
+ {
+ x_weights = A + 2;
+ y_weights = B + 6;
+ }
+ break;
+ }
+ }
+ else
+ {
+ base_quant_mode |= ((block_mode >> 2) & 3) << 1;
+ if (((block_mode >> 2) & 3) == 0)
+ {
+ return false;
+ }
+
+ unsigned int B = (block_mode >> 9) & 3;
+ switch ((block_mode >> 7) & 3)
+ {
+ case 0:
+ x_weights = 12;
+ y_weights = A + 2;
+ break;
+ case 1:
+ x_weights = A + 2;
+ y_weights = 12;
+ break;
+ case 2:
+ x_weights = A + 6;
+ y_weights = B + 6;
+ D = 0;
+ H = 0;
+ break;
+ case 3:
+ switch ((block_mode >> 5) & 3)
+ {
+ case 0:
+ x_weights = 6;
+ y_weights = 10;
+ break;
+ case 1:
+ x_weights = 10;
+ y_weights = 6;
+ break;
+ case 2:
+ case 3:
+ return false;
+ }
+ break;
+ }
+ }
+
+ unsigned int weight_count = x_weights * y_weights * (D + 1);
+ quant_mode = (base_quant_mode - 2) + 6 * H;
+ is_dual_plane = D != 0;
+
+ weight_bits = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(quant_mode));
+ return (weight_count <= BLOCK_MAX_WEIGHTS &&
+ weight_bits >= BLOCK_MIN_WEIGHT_BITS &&
+ weight_bits <= BLOCK_MAX_WEIGHT_BITS);
+}
+
+/**
+ * @brief Decode the properties of an encoded 3D block mode.
+ *
+ * @param block_mode The encoded block mode.
+ * @param[out] x_weights The number of weights in the X dimension.
+ * @param[out] y_weights The number of weights in the Y dimension.
+ * @param[out] z_weights The number of weights in the Z dimension.
+ * @param[out] is_dual_plane True if this block mode has two weight planes.
+ * @param[out] quant_mode The quantization level for the weights.
+ * @param[out] weight_bits The storage bit count for the weights.
+ *
+ * @return Returns true if a valid mode, false otherwise.
+ */
+static bool decode_block_mode_3d(
+ unsigned int block_mode,
+ unsigned int& x_weights,
+ unsigned int& y_weights,
+ unsigned int& z_weights,
+ bool& is_dual_plane,
+ unsigned int& quant_mode,
+ unsigned int& weight_bits
+) {
+ unsigned int base_quant_mode = (block_mode >> 4) & 1;
+ unsigned int H = (block_mode >> 9) & 1;
+ unsigned int D = (block_mode >> 10) & 1;
+ unsigned int A = (block_mode >> 5) & 0x3;
+
+ x_weights = 0;
+ y_weights = 0;
+ z_weights = 0;
+
+ if ((block_mode & 3) != 0)
+ {
+ base_quant_mode |= (block_mode & 3) << 1;
+ unsigned int B = (block_mode >> 7) & 3;
+ unsigned int C = (block_mode >> 2) & 0x3;
+ x_weights = A + 2;
+ y_weights = B + 2;
+ z_weights = C + 2;
+ }
+ else
+ {
+ base_quant_mode |= ((block_mode >> 2) & 3) << 1;
+ if (((block_mode >> 2) & 3) == 0)
+ {
+ return false;
+ }
+
+ int B = (block_mode >> 9) & 3;
+ if (((block_mode >> 7) & 3) != 3)
+ {
+ D = 0;
+ H = 0;
+ }
+ switch ((block_mode >> 7) & 3)
+ {
+ case 0:
+ x_weights = 6;
+ y_weights = B + 2;
+ z_weights = A + 2;
+ break;
+ case 1:
+ x_weights = A + 2;
+ y_weights = 6;
+ z_weights = B + 2;
+ break;
+ case 2:
+ x_weights = A + 2;
+ y_weights = B + 2;
+ z_weights = 6;
+ break;
+ case 3:
+ x_weights = 2;
+ y_weights = 2;
+ z_weights = 2;
+ switch ((block_mode >> 5) & 3)
+ {
+ case 0:
+ x_weights = 6;
+ break;
+ case 1:
+ y_weights = 6;
+ break;
+ case 2:
+ z_weights = 6;
+ break;
+ case 3:
+ return false;
+ }
+ break;
+ }
+ }
+
+ unsigned int weight_count = x_weights * y_weights * z_weights * (D + 1);
+ quant_mode = (base_quant_mode - 2) + 6 * H;
+ is_dual_plane = D != 0;
+
+ weight_bits = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(quant_mode));
+ return (weight_count <= BLOCK_MAX_WEIGHTS &&
+ weight_bits >= BLOCK_MIN_WEIGHT_BITS &&
+ weight_bits <= BLOCK_MAX_WEIGHT_BITS);
+}
+
+/**
+ * @brief Create a 2D decimation entry for a block-size and weight-decimation pair.
+ *
+ * @param x_texels The number of texels in the X dimension.
+ * @param y_texels The number of texels in the Y dimension.
+ * @param x_weights The number of weights in the X dimension.
+ * @param y_weights The number of weights in the Y dimension.
+ * @param[out] di The decimation info structure to populate.
+ * @param[out] wb The decimation table init scratch working buffers.
+ */
+static void init_decimation_info_2d(
+ unsigned int x_texels,
+ unsigned int y_texels,
+ unsigned int x_weights,
+ unsigned int y_weights,
+ decimation_info& di,
+ dt_init_working_buffers& wb
+) {
+ unsigned int texels_per_block = x_texels * y_texels;
+ unsigned int weights_per_block = x_weights * y_weights;
+
+ uint8_t max_texel_count_of_weight = 0;
+
+ promise(weights_per_block > 0);
+ promise(texels_per_block > 0);
+ promise(x_texels > 0);
+ promise(y_texels > 0);
+
+ for (unsigned int i = 0; i < weights_per_block; i++)
+ {
+ wb.texel_count_of_weight[i] = 0;
+ }
+
+ for (unsigned int i = 0; i < texels_per_block; i++)
+ {
+ wb.weight_count_of_texel[i] = 0;
+ }
+
+ for (unsigned int y = 0; y < y_texels; y++)
+ {
+ for (unsigned int x = 0; x < x_texels; x++)
+ {
+ unsigned int texel = y * x_texels + x;
+
+ unsigned int x_weight = (((1024 + x_texels / 2) / (x_texels - 1)) * x * (x_weights - 1) + 32) >> 6;
+ unsigned int y_weight = (((1024 + y_texels / 2) / (y_texels - 1)) * y * (y_weights - 1) + 32) >> 6;
+
+ unsigned int x_weight_frac = x_weight & 0xF;
+ unsigned int y_weight_frac = y_weight & 0xF;
+ unsigned int x_weight_int = x_weight >> 4;
+ unsigned int y_weight_int = y_weight >> 4;
+
+ unsigned int qweight[4];
+ qweight[0] = x_weight_int + y_weight_int * x_weights;
+ qweight[1] = qweight[0] + 1;
+ qweight[2] = qweight[0] + x_weights;
+ qweight[3] = qweight[2] + 1;
+
+ // Truncated-precision bilinear interpolation
+ unsigned int prod = x_weight_frac * y_weight_frac;
+
+ unsigned int weight[4];
+ weight[3] = (prod + 8) >> 4;
+ weight[1] = x_weight_frac - weight[3];
+ weight[2] = y_weight_frac - weight[3];
+ weight[0] = 16 - x_weight_frac - y_weight_frac + weight[3];
+
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ if (weight[i] != 0)
+ {
+ wb.grid_weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(qweight[i]);
+ wb.weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(weight[i]);
+ wb.weight_count_of_texel[texel]++;
+ wb.texels_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(texel);
+ wb.texel_weights_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(weight[i]);
+ wb.texel_count_of_weight[qweight[i]]++;
+ max_texel_count_of_weight = astc::max(max_texel_count_of_weight, wb.texel_count_of_weight[qweight[i]]);
+ }
+ }
+ }
+ }
+
+ uint8_t max_texel_weight_count = 0;
+ for (unsigned int i = 0; i < texels_per_block; i++)
+ {
+ di.texel_weight_count[i] = wb.weight_count_of_texel[i];
+ max_texel_weight_count = astc::max(max_texel_weight_count, di.texel_weight_count[i]);
+
+ for (unsigned int j = 0; j < wb.weight_count_of_texel[i]; j++)
+ {
+ di.texel_weight_contribs_int_tr[j][i] = wb.weights_of_texel[i][j];
+ di.texel_weight_contribs_float_tr[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM);
+ di.texel_weights_tr[j][i] = wb.grid_weights_of_texel[i][j];
+ }
+
+ // Init all 4 entries so we can rely on zeros for vectorization
+ for (unsigned int j = wb.weight_count_of_texel[i]; j < 4; j++)
+ {
+ di.texel_weight_contribs_int_tr[j][i] = 0;
+ di.texel_weight_contribs_float_tr[j][i] = 0.0f;
+ di.texel_weights_tr[j][i] = 0;
+ }
+ }
+
+ di.max_texel_weight_count = max_texel_weight_count;
+
+ for (unsigned int i = 0; i < weights_per_block; i++)
+ {
+ unsigned int texel_count_wt = wb.texel_count_of_weight[i];
+ di.weight_texel_count[i] = static_cast<uint8_t>(texel_count_wt);
+
+ for (unsigned int j = 0; j < texel_count_wt; j++)
+ {
+ uint8_t texel = wb.texels_of_weight[i][j];
+
+ // Create transposed versions of these for better vectorization
+ di.weight_texels_tr[j][i] = texel;
+ di.weights_texel_contribs_tr[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]);
+
+ // Store the per-texel contribution of this weight for each texel it contributes to
+ di.texel_contrib_for_weight[j][i] = 0.0f;
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ uint8_t dttw = di.texel_weights_tr[k][texel];
+ float dttwf = di.texel_weight_contribs_float_tr[k][texel];
+ if (dttw == i && dttwf != 0.0f)
+ {
+ di.texel_contrib_for_weight[j][i] = di.texel_weight_contribs_float_tr[k][texel];
+ break;
+ }
+ }
+ }
+
+ // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
+ // Match last texel in active lane in SIMD group, for better gathers
+ uint8_t last_texel = di.weight_texels_tr[texel_count_wt - 1][i];
+ for (unsigned int j = texel_count_wt; j < max_texel_count_of_weight; j++)
+ {
+ di.weight_texels_tr[j][i] = last_texel;
+ di.weights_texel_contribs_tr[j][i] = 0.0f;
+ }
+ }
+
+ // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
+ unsigned int texels_per_block_simd = round_up_to_simd_multiple_vla(texels_per_block);
+ for (unsigned int i = texels_per_block; i < texels_per_block_simd; i++)
+ {
+ di.texel_weight_count[i] = 0;
+
+ for (unsigned int j = 0; j < 4; j++)
+ {
+ di.texel_weight_contribs_float_tr[j][i] = 0;
+ di.texel_weights_tr[j][i] = 0;
+ di.texel_weight_contribs_int_tr[j][i] = 0;
+ }
+ }
+
+ // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
+ // Match last texel in active lane in SIMD group, for better gathers
+ unsigned int last_texel_count_wt = wb.texel_count_of_weight[weights_per_block - 1];
+ uint8_t last_texel = di.weight_texels_tr[last_texel_count_wt - 1][weights_per_block - 1];
+
+ unsigned int weights_per_block_simd = round_up_to_simd_multiple_vla(weights_per_block);
+ for (unsigned int i = weights_per_block; i < weights_per_block_simd; i++)
+ {
+ di.weight_texel_count[i] = 0;
+
+ for (unsigned int j = 0; j < max_texel_count_of_weight; j++)
+ {
+ di.weight_texels_tr[j][i] = last_texel;
+ di.weights_texel_contribs_tr[j][i] = 0.0f;
+ }
+ }
+
+ di.texel_count = static_cast<uint8_t>(texels_per_block);
+ di.weight_count = static_cast<uint8_t>(weights_per_block);
+ di.weight_x = static_cast<uint8_t>(x_weights);
+ di.weight_y = static_cast<uint8_t>(y_weights);
+ di.weight_z = 1;
+}
+
+/**
+ * @brief Create a 3D decimation entry for a block-size and weight-decimation pair.
+ *
+ * @param x_texels The number of texels in the X dimension.
+ * @param y_texels The number of texels in the Y dimension.
+ * @param z_texels The number of texels in the Z dimension.
+ * @param x_weights The number of weights in the X dimension.
+ * @param y_weights The number of weights in the Y dimension.
+ * @param z_weights The number of weights in the Z dimension.
+ * @param[out] di The decimation info structure to populate.
+ @param[out] wb The decimation table init scratch working buffers.
+ */
+static void init_decimation_info_3d(
+ unsigned int x_texels,
+ unsigned int y_texels,
+ unsigned int z_texels,
+ unsigned int x_weights,
+ unsigned int y_weights,
+ unsigned int z_weights,
+ decimation_info& di,
+ dt_init_working_buffers& wb
+) {
+ unsigned int texels_per_block = x_texels * y_texels * z_texels;
+ unsigned int weights_per_block = x_weights * y_weights * z_weights;
+
+ uint8_t max_texel_count_of_weight = 0;
+
+ promise(weights_per_block > 0);
+ promise(texels_per_block > 0);
+
+ for (unsigned int i = 0; i < weights_per_block; i++)
+ {
+ wb.texel_count_of_weight[i] = 0;
+ }
+
+ for (unsigned int i = 0; i < texels_per_block; i++)
+ {
+ wb.weight_count_of_texel[i] = 0;
+ }
+
+ for (unsigned int z = 0; z < z_texels; z++)
+ {
+ for (unsigned int y = 0; y < y_texels; y++)
+ {
+ for (unsigned int x = 0; x < x_texels; x++)
+ {
+ int texel = (z * y_texels + y) * x_texels + x;
+
+ int x_weight = (((1024 + x_texels / 2) / (x_texels - 1)) * x * (x_weights - 1) + 32) >> 6;
+ int y_weight = (((1024 + y_texels / 2) / (y_texels - 1)) * y * (y_weights - 1) + 32) >> 6;
+ int z_weight = (((1024 + z_texels / 2) / (z_texels - 1)) * z * (z_weights - 1) + 32) >> 6;
+
+ int x_weight_frac = x_weight & 0xF;
+ int y_weight_frac = y_weight & 0xF;
+ int z_weight_frac = z_weight & 0xF;
+ int x_weight_int = x_weight >> 4;
+ int y_weight_int = y_weight >> 4;
+ int z_weight_int = z_weight >> 4;
+ int qweight[4];
+ int weight[4];
+ qweight[0] = (z_weight_int * y_weights + y_weight_int) * x_weights + x_weight_int;
+ qweight[3] = ((z_weight_int + 1) * y_weights + (y_weight_int + 1)) * x_weights + (x_weight_int + 1);
+
+ // simplex interpolation
+ int fs = x_weight_frac;
+ int ft = y_weight_frac;
+ int fp = z_weight_frac;
+
+ int cas = ((fs > ft) << 2) + ((ft > fp) << 1) + ((fs > fp));
+ int N = x_weights;
+ int NM = x_weights * y_weights;
+
+ int s1, s2, w0, w1, w2, w3;
+ switch (cas)
+ {
+ case 7:
+ s1 = 1;
+ s2 = N;
+ w0 = 16 - fs;
+ w1 = fs - ft;
+ w2 = ft - fp;
+ w3 = fp;
+ break;
+ case 3:
+ s1 = N;
+ s2 = 1;
+ w0 = 16 - ft;
+ w1 = ft - fs;
+ w2 = fs - fp;
+ w3 = fp;
+ break;
+ case 5:
+ s1 = 1;
+ s2 = NM;
+ w0 = 16 - fs;
+ w1 = fs - fp;
+ w2 = fp - ft;
+ w3 = ft;
+ break;
+ case 4:
+ s1 = NM;
+ s2 = 1;
+ w0 = 16 - fp;
+ w1 = fp - fs;
+ w2 = fs - ft;
+ w3 = ft;
+ break;
+ case 2:
+ s1 = N;
+ s2 = NM;
+ w0 = 16 - ft;
+ w1 = ft - fp;
+ w2 = fp - fs;
+ w3 = fs;
+ break;
+ case 0:
+ s1 = NM;
+ s2 = N;
+ w0 = 16 - fp;
+ w1 = fp - ft;
+ w2 = ft - fs;
+ w3 = fs;
+ break;
+ default:
+ s1 = NM;
+ s2 = N;
+ w0 = 16 - fp;
+ w1 = fp - ft;
+ w2 = ft - fs;
+ w3 = fs;
+ break;
+ }
+
+ qweight[1] = qweight[0] + s1;
+ qweight[2] = qweight[1] + s2;
+ weight[0] = w0;
+ weight[1] = w1;
+ weight[2] = w2;
+ weight[3] = w3;
+
+ for (unsigned int i = 0; i < 4; i++)
+ {
+ if (weight[i] != 0)
+ {
+ wb.grid_weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(qweight[i]);
+ wb.weights_of_texel[texel][wb.weight_count_of_texel[texel]] = static_cast<uint8_t>(weight[i]);
+ wb.weight_count_of_texel[texel]++;
+ wb.texels_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(texel);
+ wb.texel_weights_of_weight[qweight[i]][wb.texel_count_of_weight[qweight[i]]] = static_cast<uint8_t>(weight[i]);
+ wb.texel_count_of_weight[qweight[i]]++;
+ max_texel_count_of_weight = astc::max(max_texel_count_of_weight, wb.texel_count_of_weight[qweight[i]]);
+ }
+ }
+ }
+ }
+ }
+
+ uint8_t max_texel_weight_count = 0;
+ for (unsigned int i = 0; i < texels_per_block; i++)
+ {
+ di.texel_weight_count[i] = wb.weight_count_of_texel[i];
+ max_texel_weight_count = astc::max(max_texel_weight_count, di.texel_weight_count[i]);
+
+ // Init all 4 entries so we can rely on zeros for vectorization
+ for (unsigned int j = 0; j < 4; j++)
+ {
+ di.texel_weight_contribs_int_tr[j][i] = 0;
+ di.texel_weight_contribs_float_tr[j][i] = 0.0f;
+ di.texel_weights_tr[j][i] = 0;
+ }
+
+ for (unsigned int j = 0; j < wb.weight_count_of_texel[i]; j++)
+ {
+ di.texel_weight_contribs_int_tr[j][i] = wb.weights_of_texel[i][j];
+ di.texel_weight_contribs_float_tr[j][i] = static_cast<float>(wb.weights_of_texel[i][j]) * (1.0f / WEIGHTS_TEXEL_SUM);
+ di.texel_weights_tr[j][i] = wb.grid_weights_of_texel[i][j];
+ }
+ }
+
+ di.max_texel_weight_count = max_texel_weight_count;
+
+ for (unsigned int i = 0; i < weights_per_block; i++)
+ {
+ unsigned int texel_count_wt = wb.texel_count_of_weight[i];
+ di.weight_texel_count[i] = static_cast<uint8_t>(texel_count_wt);
+
+ for (unsigned int j = 0; j < texel_count_wt; j++)
+ {
+ unsigned int texel = wb.texels_of_weight[i][j];
+
+ // Create transposed versions of these for better vectorization
+ di.weight_texels_tr[j][i] = static_cast<uint8_t>(texel);
+ di.weights_texel_contribs_tr[j][i] = static_cast<float>(wb.texel_weights_of_weight[i][j]);
+
+ // Store the per-texel contribution of this weight for each texel it contributes to
+ di.texel_contrib_for_weight[j][i] = 0.0f;
+ for (unsigned int k = 0; k < 4; k++)
+ {
+ uint8_t dttw = di.texel_weights_tr[k][texel];
+ float dttwf = di.texel_weight_contribs_float_tr[k][texel];
+ if (dttw == i && dttwf != 0.0f)
+ {
+ di.texel_contrib_for_weight[j][i] = di.texel_weight_contribs_float_tr[k][texel];
+ break;
+ }
+ }
+ }
+
+ // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
+ // Match last texel in active lane in SIMD group, for better gathers
+ uint8_t last_texel = di.weight_texels_tr[texel_count_wt - 1][i];
+ for (unsigned int j = texel_count_wt; j < max_texel_count_of_weight; j++)
+ {
+ di.weight_texels_tr[j][i] = last_texel;
+ di.weights_texel_contribs_tr[j][i] = 0.0f;
+ }
+ }
+
+ // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
+ unsigned int texels_per_block_simd = round_up_to_simd_multiple_vla(texels_per_block);
+ for (unsigned int i = texels_per_block; i < texels_per_block_simd; i++)
+ {
+ di.texel_weight_count[i] = 0;
+
+ for (unsigned int j = 0; j < 4; j++)
+ {
+ di.texel_weight_contribs_float_tr[j][i] = 0;
+ di.texel_weights_tr[j][i] = 0;
+ di.texel_weight_contribs_int_tr[j][i] = 0;
+ }
+ }
+
+ // Initialize array tail so we can over-fetch with SIMD later to avoid loop tails
+ // Match last texel in active lane in SIMD group, for better gathers
+ int last_texel_count_wt = wb.texel_count_of_weight[weights_per_block - 1];
+ uint8_t last_texel = di.weight_texels_tr[last_texel_count_wt - 1][weights_per_block - 1];
+
+ unsigned int weights_per_block_simd = round_up_to_simd_multiple_vla(weights_per_block);
+ for (unsigned int i = weights_per_block; i < weights_per_block_simd; i++)
+ {
+ di.weight_texel_count[i] = 0;
+
+ for (int j = 0; j < max_texel_count_of_weight; j++)
+ {
+ di.weight_texels_tr[j][i] = last_texel;
+ di.weights_texel_contribs_tr[j][i] = 0.0f;
+ }
+ }
+
+ di.texel_count = static_cast<uint8_t>(texels_per_block);
+ di.weight_count = static_cast<uint8_t>(weights_per_block);
+ di.weight_x = static_cast<uint8_t>(x_weights);
+ di.weight_y = static_cast<uint8_t>(y_weights);
+ di.weight_z = static_cast<uint8_t>(z_weights);
+}
+
+/**
+ * @brief Assign the texels to use for kmeans clustering.
+ *
+ * The max limit is @c BLOCK_MAX_KMEANS_TEXELS; above this a random selection is used.
+ * The @c bsd.texel_count is an input and must be populated beforehand.
+ *
+ * @param[in,out] bsd The block size descriptor to populate.
+ */
+static void assign_kmeans_texels(
+ block_size_descriptor& bsd
+) {
+ // Use all texels for kmeans on a small block
+ if (bsd.texel_count <= BLOCK_MAX_KMEANS_TEXELS)
+ {
+ for (uint8_t i = 0; i < bsd.texel_count; i++)
+ {
+ bsd.kmeans_texels[i] = i;
+ }
+
+ return;
+ }
+
+ // Select a random subset of BLOCK_MAX_KMEANS_TEXELS for kmeans on a large block
+ uint64_t rng_state[2];
+ astc::rand_init(rng_state);
+
+ // Initialize array used for tracking used indices
+ bool seen[BLOCK_MAX_TEXELS];
+ for (uint8_t i = 0; i < bsd.texel_count; i++)
+ {
+ seen[i] = false;
+ }
+
+ // Assign 64 random indices, retrying if we see repeats
+ unsigned int arr_elements_set = 0;
+ while (arr_elements_set < BLOCK_MAX_KMEANS_TEXELS)
+ {
+ uint8_t texel = static_cast<uint8_t>(astc::rand(rng_state));
+ texel = texel % bsd.texel_count;
+ if (!seen[texel])
+ {
+ bsd.kmeans_texels[arr_elements_set++] = texel;
+ seen[texel] = true;
+ }
+ }
+}
+
+/**
+ * @brief Allocate a single 2D decimation table entry.
+ *
+ * @param x_texels The number of texels in the X dimension.
+ * @param y_texels The number of texels in the Y dimension.
+ * @param x_weights The number of weights in the X dimension.
+ * @param y_weights The number of weights in the Y dimension.
+ * @param bsd The block size descriptor we are populating.
+ * @param wb The decimation table init scratch working buffers.
+ * @param index The packed array index to populate.
+ */
+static void construct_dt_entry_2d(
+ unsigned int x_texels,
+ unsigned int y_texels,
+ unsigned int x_weights,
+ unsigned int y_weights,
+ block_size_descriptor& bsd,
+ dt_init_working_buffers& wb,
+ unsigned int index
+) {
+ unsigned int weight_count = x_weights * y_weights;
+ assert(weight_count <= BLOCK_MAX_WEIGHTS);
+
+ bool try_2planes = (2 * weight_count) <= BLOCK_MAX_WEIGHTS;
+
+ decimation_info& di = bsd.decimation_tables[index];
+ init_decimation_info_2d(x_texels, y_texels, x_weights, y_weights, di, wb);
+
+ int maxprec_1plane = -1;
+ int maxprec_2planes = -1;
+ for (int i = 0; i < 12; i++)
+ {
+ unsigned int bits_1plane = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(i));
+ if (bits_1plane >= BLOCK_MIN_WEIGHT_BITS && bits_1plane <= BLOCK_MAX_WEIGHT_BITS)
+ {
+ maxprec_1plane = i;
+ }
+
+ if (try_2planes)
+ {
+ unsigned int bits_2planes = get_ise_sequence_bitcount(2 * weight_count, static_cast<quant_method>(i));
+ if (bits_2planes >= BLOCK_MIN_WEIGHT_BITS && bits_2planes <= BLOCK_MAX_WEIGHT_BITS)
+ {
+ maxprec_2planes = i;
+ }
+ }
+ }
+
+ // At least one of the two should be valid ...
+ assert(maxprec_1plane >= 0 || maxprec_2planes >= 0);
+ bsd.decimation_modes[index].maxprec_1plane = static_cast<int8_t>(maxprec_1plane);
+ bsd.decimation_modes[index].maxprec_2planes = static_cast<int8_t>(maxprec_2planes);
+ bsd.decimation_modes[index].refprec_1_plane = 0;
+ bsd.decimation_modes[index].refprec_2_planes = 0;
+}
+
+/**
+ * @brief Allocate block modes and decimation tables for a single 2D block size.
+ *
+ * @param x_texels The number of texels in the X dimension.
+ * @param y_texels The number of texels in the Y dimension.
+ * @param can_omit_modes Can we discard modes that astcenc won't use, even if legal?
+ * @param mode_cutoff Percentile cutoff in range [0,1]. Low values more likely to be used.
+ * @param[out] bsd The block size descriptor to populate.
+ */
+static void construct_block_size_descriptor_2d(
+ unsigned int x_texels,
+ unsigned int y_texels,
+ bool can_omit_modes,
+ float mode_cutoff,
+ block_size_descriptor& bsd
+) {
+ // Store a remap table for storing packed decimation modes.
+ // Indexing uses [Y * 16 + X] and max size for each axis is 12.
+ static const unsigned int MAX_DMI = 12 * 16 + 12;
+ int decimation_mode_index[MAX_DMI];
+
+ dt_init_working_buffers* wb = new dt_init_working_buffers;
+
+ bsd.xdim = static_cast<uint8_t>(x_texels);
+ bsd.ydim = static_cast<uint8_t>(y_texels);
+ bsd.zdim = 1;
+ bsd.texel_count = static_cast<uint8_t>(x_texels * y_texels);
+
+ for (unsigned int i = 0; i < MAX_DMI; i++)
+ {
+ decimation_mode_index[i] = -1;
+ }
+
+ // Gather all the decimation grids that can be used with the current block
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+ const float *percentiles = get_2d_percentile_table(x_texels, y_texels);
+ float always_cutoff = 0.0f;
+#else
+ // Unused in decompress-only builds
+ (void)can_omit_modes;
+ (void)mode_cutoff;
+#endif
+
+ // Construct the list of block formats referencing the decimation tables
+ unsigned int packed_bm_idx = 0;
+ unsigned int packed_dm_idx = 0;
+
+ // Trackers
+ unsigned int bm_counts[4] { 0 };
+ unsigned int dm_counts[4] { 0 };
+
+ // Clear the list to a known-bad value
+ for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++)
+ {
+ bsd.block_mode_packed_index[i] = BLOCK_BAD_BLOCK_MODE;
+ }
+
+ // Iterate four times to build a usefully ordered list:
+ // - Pass 0 - keep selected single plane "always" block modes
+ // - Pass 1 - keep selected single plane "non-always" block modes
+ // - Pass 2 - keep select dual plane block modes
+ // - Pass 3 - keep everything else that's legal
+ unsigned int limit = can_omit_modes ? 3 : 4;
+ for (unsigned int j = 0; j < limit; j ++)
+ {
+ for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++)
+ {
+ // Skip modes we've already included in a previous pass
+ if (bsd.block_mode_packed_index[i] != BLOCK_BAD_BLOCK_MODE)
+ {
+ continue;
+ }
+
+ // Decode parameters
+ unsigned int x_weights;
+ unsigned int y_weights;
+ bool is_dual_plane;
+ unsigned int quant_mode;
+ unsigned int weight_bits;
+ bool valid = decode_block_mode_2d(i, x_weights, y_weights, is_dual_plane, quant_mode, weight_bits);
+
+ // Always skip invalid encodings for the current block size
+ if (!valid || (x_weights > x_texels) || (y_weights > y_texels))
+ {
+ continue;
+ }
+
+ // Selectively skip dual plane encodings
+ if (((j <= 1) && is_dual_plane) || (j == 2 && !is_dual_plane))
+ {
+ continue;
+ }
+
+ // Always skip encodings we can't physically encode based on
+ // generic encoding bit availability
+ if (is_dual_plane)
+ {
+ // This is the only check we need as only support 1 partition
+ if ((109 - weight_bits) <= 0)
+ {
+ continue;
+ }
+ }
+ else
+ {
+ // This is conservative - fewer bits may be available for > 1 partition
+ if ((111 - weight_bits) <= 0)
+ {
+ continue;
+ }
+ }
+
+ // Selectively skip encodings based on percentile
+ bool percentile_hit = false;
+ #if !defined(ASTCENC_DECOMPRESS_ONLY)
+ if (j == 0)
+ {
+ percentile_hit = percentiles[i] <= always_cutoff;
+ }
+ else
+ {
+ percentile_hit = percentiles[i] <= mode_cutoff;
+ }
+ #endif
+
+ if (j != 3 && !percentile_hit)
+ {
+ continue;
+ }
+
+ // Allocate and initialize the decimation table entry if we've not used it yet
+ int decimation_mode = decimation_mode_index[y_weights * 16 + x_weights];
+ if (decimation_mode < 0)
+ {
+ construct_dt_entry_2d(x_texels, y_texels, x_weights, y_weights, bsd, *wb, packed_dm_idx);
+ decimation_mode_index[y_weights * 16 + x_weights] = packed_dm_idx;
+ decimation_mode = packed_dm_idx;
+
+ dm_counts[j]++;
+ packed_dm_idx++;
+ }
+
+ auto& bm = bsd.block_modes[packed_bm_idx];
+
+ bm.decimation_mode = static_cast<uint8_t>(decimation_mode);
+ bm.quant_mode = static_cast<uint8_t>(quant_mode);
+ bm.is_dual_plane = static_cast<uint8_t>(is_dual_plane);
+ bm.weight_bits = static_cast<uint8_t>(weight_bits);
+ bm.mode_index = static_cast<uint16_t>(i);
+
+ auto& dm = bsd.decimation_modes[decimation_mode];
+
+ if (is_dual_plane)
+ {
+ dm.set_ref_2_plane(bm.get_weight_quant_mode());
+ }
+ else
+ {
+ dm.set_ref_1_plane(bm.get_weight_quant_mode());
+ }
+
+ bsd.block_mode_packed_index[i] = static_cast<uint16_t>(packed_bm_idx);
+
+ packed_bm_idx++;
+ bm_counts[j]++;
+ }
+ }
+
+ bsd.block_mode_count_1plane_always = bm_counts[0];
+ bsd.block_mode_count_1plane_selected = bm_counts[0] + bm_counts[1];
+ bsd.block_mode_count_1plane_2plane_selected = bm_counts[0] + bm_counts[1] + bm_counts[2];
+ bsd.block_mode_count_all = bm_counts[0] + bm_counts[1] + bm_counts[2] + bm_counts[3];
+
+ bsd.decimation_mode_count_always = dm_counts[0];
+ bsd.decimation_mode_count_selected = dm_counts[0] + dm_counts[1] + dm_counts[2];
+ bsd.decimation_mode_count_all = dm_counts[0] + dm_counts[1] + dm_counts[2] + dm_counts[3];
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+ assert(bsd.block_mode_count_1plane_always > 0);
+ assert(bsd.decimation_mode_count_always > 0);
+
+ delete[] percentiles;
+#endif
+
+ // Ensure the end of the array contains valid data (should never get read)
+ for (unsigned int i = bsd.decimation_mode_count_all; i < WEIGHTS_MAX_DECIMATION_MODES; i++)
+ {
+ bsd.decimation_modes[i].maxprec_1plane = -1;
+ bsd.decimation_modes[i].maxprec_2planes = -1;
+ bsd.decimation_modes[i].refprec_1_plane = 0;
+ bsd.decimation_modes[i].refprec_2_planes = 0;
+ }
+
+ // Determine the texels to use for kmeans clustering.
+ assign_kmeans_texels(bsd);
+
+ delete wb;
+}
+
+/**
+ * @brief Allocate block modes and decimation tables for a single 3D block size.
+ *
+ * TODO: This function doesn't include all of the heuristics that we use for 2D block sizes such as
+ * the percentile mode cutoffs. If 3D becomes more widely used we should look at this.
+ *
+ * @param x_texels The number of texels in the X dimension.
+ * @param y_texels The number of texels in the Y dimension.
+ * @param z_texels The number of texels in the Z dimension.
+ * @param[out] bsd The block size descriptor to populate.
+ */
+static void construct_block_size_descriptor_3d(
+ unsigned int x_texels,
+ unsigned int y_texels,
+ unsigned int z_texels,
+ block_size_descriptor& bsd
+) {
+ // Store a remap table for storing packed decimation modes.
+ // Indexing uses [Z * 64 + Y * 8 + X] and max size for each axis is 6.
+ static constexpr unsigned int MAX_DMI = 6 * 64 + 6 * 8 + 6;
+ int decimation_mode_index[MAX_DMI];
+ unsigned int decimation_mode_count = 0;
+
+ dt_init_working_buffers* wb = new dt_init_working_buffers;
+
+ bsd.xdim = static_cast<uint8_t>(x_texels);
+ bsd.ydim = static_cast<uint8_t>(y_texels);
+ bsd.zdim = static_cast<uint8_t>(z_texels);
+ bsd.texel_count = static_cast<uint8_t>(x_texels * y_texels * z_texels);
+
+ for (unsigned int i = 0; i < MAX_DMI; i++)
+ {
+ decimation_mode_index[i] = -1;
+ }
+
+ // gather all the infill-modes that can be used with the current block size
+ for (unsigned int x_weights = 2; x_weights <= x_texels; x_weights++)
+ {
+ for (unsigned int y_weights = 2; y_weights <= y_texels; y_weights++)
+ {
+ for (unsigned int z_weights = 2; z_weights <= z_texels; z_weights++)
+ {
+ unsigned int weight_count = x_weights * y_weights * z_weights;
+ if (weight_count > BLOCK_MAX_WEIGHTS)
+ {
+ continue;
+ }
+
+ decimation_info& di = bsd.decimation_tables[decimation_mode_count];
+ decimation_mode_index[z_weights * 64 + y_weights * 8 + x_weights] = decimation_mode_count;
+ init_decimation_info_3d(x_texels, y_texels, z_texels, x_weights, y_weights, z_weights, di, *wb);
+
+ int maxprec_1plane = -1;
+ int maxprec_2planes = -1;
+ for (unsigned int i = 0; i < 12; i++)
+ {
+ unsigned int bits_1plane = get_ise_sequence_bitcount(weight_count, static_cast<quant_method>(i));
+ if (bits_1plane >= BLOCK_MIN_WEIGHT_BITS && bits_1plane <= BLOCK_MAX_WEIGHT_BITS)
+ {
+ maxprec_1plane = i;
+ }
+
+ unsigned int bits_2planes = get_ise_sequence_bitcount(2 * weight_count, static_cast<quant_method>(i));
+ if (bits_2planes >= BLOCK_MIN_WEIGHT_BITS && bits_2planes <= BLOCK_MAX_WEIGHT_BITS)
+ {
+ maxprec_2planes = i;
+ }
+ }
+
+ if ((2 * weight_count) > BLOCK_MAX_WEIGHTS)
+ {
+ maxprec_2planes = -1;
+ }
+
+ bsd.decimation_modes[decimation_mode_count].maxprec_1plane = static_cast<int8_t>(maxprec_1plane);
+ bsd.decimation_modes[decimation_mode_count].maxprec_2planes = static_cast<int8_t>(maxprec_2planes);
+ bsd.decimation_modes[decimation_mode_count].refprec_1_plane = maxprec_1plane == -1 ? 0 : 0xFFFF;
+ bsd.decimation_modes[decimation_mode_count].refprec_2_planes = maxprec_2planes == -1 ? 0 : 0xFFFF;
+ decimation_mode_count++;
+ }
+ }
+ }
+
+ // Ensure the end of the array contains valid data (should never get read)
+ for (unsigned int i = decimation_mode_count; i < WEIGHTS_MAX_DECIMATION_MODES; i++)
+ {
+ bsd.decimation_modes[i].maxprec_1plane = -1;
+ bsd.decimation_modes[i].maxprec_2planes = -1;
+ bsd.decimation_modes[i].refprec_1_plane = 0;
+ bsd.decimation_modes[i].refprec_2_planes = 0;
+ }
+
+ bsd.decimation_mode_count_always = 0; // Skipped for 3D modes
+ bsd.decimation_mode_count_selected = decimation_mode_count;
+ bsd.decimation_mode_count_all = decimation_mode_count;
+
+ // Construct the list of block formats referencing the decimation tables
+
+ // Clear the list to a known-bad value
+ for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++)
+ {
+ bsd.block_mode_packed_index[i] = BLOCK_BAD_BLOCK_MODE;
+ }
+
+ unsigned int packed_idx = 0;
+ unsigned int bm_counts[2] { 0 };
+
+ // Iterate two times to build a usefully ordered list:
+ // - Pass 0 - keep valid single plane block modes
+ // - Pass 1 - keep valid dual plane block modes
+ for (unsigned int j = 0; j < 2; j++)
+ {
+ for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++)
+ {
+ // Skip modes we've already included in a previous pass
+ if (bsd.block_mode_packed_index[i] != BLOCK_BAD_BLOCK_MODE)
+ {
+ continue;
+ }
+
+ unsigned int x_weights;
+ unsigned int y_weights;
+ unsigned int z_weights;
+ bool is_dual_plane;
+ unsigned int quant_mode;
+ unsigned int weight_bits;
+
+ bool valid = decode_block_mode_3d(i, x_weights, y_weights, z_weights, is_dual_plane, quant_mode, weight_bits);
+ // Skip invalid encodings
+ if (!valid || x_weights > x_texels || y_weights > y_texels || z_weights > z_texels)
+ {
+ continue;
+ }
+
+ // Skip encodings in the wrong iteration
+ if ((j == 0 && is_dual_plane) || (j == 1 && !is_dual_plane))
+ {
+ continue;
+ }
+
+ // Always skip encodings we can't physically encode based on bit availability
+ if (is_dual_plane)
+ {
+ // This is the only check we need as only support 1 partition
+ if ((109 - weight_bits) <= 0)
+ {
+ continue;
+ }
+ }
+ else
+ {
+ // This is conservative - fewer bits may be available for > 1 partition
+ if ((111 - weight_bits) <= 0)
+ {
+ continue;
+ }
+ }
+
+ int decimation_mode = decimation_mode_index[z_weights * 64 + y_weights * 8 + x_weights];
+ bsd.block_modes[packed_idx].decimation_mode = static_cast<uint8_t>(decimation_mode);
+ bsd.block_modes[packed_idx].quant_mode = static_cast<uint8_t>(quant_mode);
+ bsd.block_modes[packed_idx].weight_bits = static_cast<uint8_t>(weight_bits);
+ bsd.block_modes[packed_idx].is_dual_plane = static_cast<uint8_t>(is_dual_plane);
+ bsd.block_modes[packed_idx].mode_index = static_cast<uint16_t>(i);
+
+ bsd.block_mode_packed_index[i] = static_cast<uint16_t>(packed_idx);
+ bm_counts[j]++;
+ packed_idx++;
+ }
+ }
+
+ bsd.block_mode_count_1plane_always = 0; // Skipped for 3D modes
+ bsd.block_mode_count_1plane_selected = bm_counts[0];
+ bsd.block_mode_count_1plane_2plane_selected = bm_counts[0] + bm_counts[1];
+ bsd.block_mode_count_all = bm_counts[0] + bm_counts[1];
+
+ // Determine the texels to use for kmeans clustering.
+ assign_kmeans_texels(bsd);
+
+ delete wb;
+}
+
+/* See header for documentation. */
+void init_block_size_descriptor(
+ unsigned int x_texels,
+ unsigned int y_texels,
+ unsigned int z_texels,
+ bool can_omit_modes,
+ unsigned int partition_count_cutoff,
+ float mode_cutoff,
+ block_size_descriptor& bsd
+) {
+ if (z_texels > 1)
+ {
+ construct_block_size_descriptor_3d(x_texels, y_texels, z_texels, bsd);
+ }
+ else
+ {
+ construct_block_size_descriptor_2d(x_texels, y_texels, can_omit_modes, mode_cutoff, bsd);
+ }
+
+ init_partition_tables(bsd, can_omit_modes, partition_count_cutoff);
+}
diff --git a/thirdparty/astcenc/astcenc_color_quantize.cpp b/thirdparty/astcenc/astcenc_color_quantize.cpp
new file mode 100644
index 0000000000..edcfe4f853
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_color_quantize.cpp
@@ -0,0 +1,2071 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Functions for color quantization.
+ *
+ * The design of the color quantization functionality requires the caller to use higher level error
+ * analysis to determine the base encoding that should be used. This earlier analysis will select
+ * the basic type of the endpoint that should be used:
+ *
+ * * Mode: LDR or HDR
+ * * Quantization level
+ * * Channel count: L, LA, RGB, or RGBA
+ * * Endpoint 2 type: Direct color endcode, or scaled from endpoint 1.
+ *
+ * However, this leaves a number of decisions about exactly how to pack the endpoints open. In
+ * particular we need to determine if blue contraction can be used, or/and if delta encoding can be
+ * used. If they can be applied these will allow us to maintain higher precision in the endpoints
+ * without needing additional storage.
+ */
+
+#include <stdio.h>
+#include <assert.h>
+
+#include "astcenc_internal.h"
+
+/**
+ * @brief Determine the quantized value given a quantization level.
+ *
+ * @param quant_level The quantization level to use.
+ * @param value The value to convert. This may be outside of the 0-255 range and will be
+ * clamped before the value is looked up.
+ *
+ * @return The encoded quantized value. These are not necessarily in order; the compressor
+ * scrambles the values slightly to make hardware implementation easier.
+ */
+static inline uint8_t quant_color(
+ quant_method quant_level,
+ int value
+) {
+ return color_unquant_to_uquant_tables[quant_level - QUANT_6][value];
+}
+
+/**
+ * @brief Quantize an LDR RGB color.
+ *
+ * Since this is a fall-back encoding, we cannot actually fail but must produce a sensible result.
+ * For this encoding @c color0 cannot be larger than @c color1. If @c color0 is actually larger
+ * than @c color1, @c color0 is reduced and @c color1 is increased until the constraint is met.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (r0, r1, g0, g1, b0, b1).
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_rgb(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[6],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float r0 = astc::clamp255f(color0.lane<0>() * scale);
+ float g0 = astc::clamp255f(color0.lane<1>() * scale);
+ float b0 = astc::clamp255f(color0.lane<2>() * scale);
+
+ float r1 = astc::clamp255f(color1.lane<0>() * scale);
+ float g1 = astc::clamp255f(color1.lane<1>() * scale);
+ float b1 = astc::clamp255f(color1.lane<2>() * scale);
+
+ int ri0, gi0, bi0, ri1, gi1, bi1;
+ float rgb0_addon = 0.5f;
+ float rgb1_addon = 0.5f;
+ do
+ {
+ ri0 = quant_color(quant_level, astc::max(astc::flt2int_rd(r0 + rgb0_addon), 0));
+ gi0 = quant_color(quant_level, astc::max(astc::flt2int_rd(g0 + rgb0_addon), 0));
+ bi0 = quant_color(quant_level, astc::max(astc::flt2int_rd(b0 + rgb0_addon), 0));
+ ri1 = quant_color(quant_level, astc::min(astc::flt2int_rd(r1 + rgb1_addon), 255));
+ gi1 = quant_color(quant_level, astc::min(astc::flt2int_rd(g1 + rgb1_addon), 255));
+ bi1 = quant_color(quant_level, astc::min(astc::flt2int_rd(b1 + rgb1_addon), 255));
+
+ rgb0_addon -= 0.2f;
+ rgb1_addon += 0.2f;
+ } while (ri0 + gi0 + bi0 > ri1 + gi1 + bi1);
+
+ output[0] = static_cast<uint8_t>(ri0);
+ output[1] = static_cast<uint8_t>(ri1);
+ output[2] = static_cast<uint8_t>(gi0);
+ output[3] = static_cast<uint8_t>(gi1);
+ output[4] = static_cast<uint8_t>(bi0);
+ output[5] = static_cast<uint8_t>(bi1);
+}
+
+/**
+ * @brief Quantize an LDR RGBA color.
+ *
+ * Since this is a fall-back encoding, we cannot actually fail but must produce a sensible result.
+ * For this encoding @c color0.rgb cannot be larger than @c color1.rgb (this indicates blue
+ * contraction). If @c color0.rgb is actually larger than @c color1.rgb, @c color0.rgb is reduced
+ * and @c color1.rgb is increased until the constraint is met.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (r0, r1, g0, g1, b0, b1, a0, a1).
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_rgba(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[8],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float a0 = astc::clamp255f(color0.lane<3>() * scale);
+ float a1 = astc::clamp255f(color1.lane<3>() * scale);
+
+ output[6] = quant_color(quant_level, astc::flt2int_rtn(a0));
+ output[7] = quant_color(quant_level, astc::flt2int_rtn(a1));
+
+ quantize_rgb(color0, color1, output, quant_level);
+}
+
+/**
+ * @brief Try to quantize an LDR RGB color using blue-contraction.
+ *
+ * Blue-contraction is only usable if encoded color 1 is larger than color 0.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (r1, r0, g1, g0, b1, b0).
+ * @param quant_level The quantization level to use.
+ *
+ * @return Returns @c false on failure, @c true on success.
+ */
+static bool try_quantize_rgb_blue_contract(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[6],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float r0 = color0.lane<0>() * scale;
+ float g0 = color0.lane<1>() * scale;
+ float b0 = color0.lane<2>() * scale;
+
+ float r1 = color1.lane<0>() * scale;
+ float g1 = color1.lane<1>() * scale;
+ float b1 = color1.lane<2>() * scale;
+
+ // Apply inverse blue-contraction. This can produce an overflow; which means BC cannot be used.
+ r0 += (r0 - b0);
+ g0 += (g0 - b0);
+ r1 += (r1 - b1);
+ g1 += (g1 - b1);
+
+ if (r0 < 0.0f || r0 > 255.0f || g0 < 0.0f || g0 > 255.0f || b0 < 0.0f || b0 > 255.0f ||
+ r1 < 0.0f || r1 > 255.0f || g1 < 0.0f || g1 > 255.0f || b1 < 0.0f || b1 > 255.0f)
+ {
+ return false;
+ }
+
+ // Quantize the inverse-blue-contracted color
+ int ri0 = quant_color(quant_level, astc::flt2int_rtn(r0));
+ int gi0 = quant_color(quant_level, astc::flt2int_rtn(g0));
+ int bi0 = quant_color(quant_level, astc::flt2int_rtn(b0));
+
+ int ri1 = quant_color(quant_level, astc::flt2int_rtn(r1));
+ int gi1 = quant_color(quant_level, astc::flt2int_rtn(g1));
+ int bi1 = quant_color(quant_level, astc::flt2int_rtn(b1));
+
+ // If color #1 is not larger than color #0 then blue-contraction cannot be used. Note that
+ // blue-contraction and quantization change this order, which is why we must test afterwards.
+ if (ri1 + gi1 + bi1 <= ri0 + gi0 + bi0)
+ {
+ return false;
+ }
+
+ output[0] = static_cast<uint8_t>(ri1);
+ output[1] = static_cast<uint8_t>(ri0);
+ output[2] = static_cast<uint8_t>(gi1);
+ output[3] = static_cast<uint8_t>(gi0);
+ output[4] = static_cast<uint8_t>(bi1);
+ output[5] = static_cast<uint8_t>(bi0);
+
+ return true;
+}
+
+/**
+ * @brief Try to quantize an LDR RGBA color using blue-contraction.
+ *
+ * Blue-contraction is only usable if encoded color 1 RGB is larger than color 0 RGB.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (r1, r0, g1, g0, b1, b0, a1, a0).
+ * @param quant_level The quantization level to use.
+ *
+ * @return Returns @c false on failure, @c true on success.
+ */
+static int try_quantize_rgba_blue_contract(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[8],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float a0 = astc::clamp255f(color0.lane<3>() * scale);
+ float a1 = astc::clamp255f(color1.lane<3>() * scale);
+
+ output[6] = quant_color(quant_level, astc::flt2int_rtn(a1));
+ output[7] = quant_color(quant_level, astc::flt2int_rtn(a0));
+
+ return try_quantize_rgb_blue_contract(color0, color1, output, quant_level);
+}
+
+/**
+ * @brief Try to quantize an LDR RGB color using delta encoding.
+ *
+ * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
+ * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
+ * non-negative, then we encode a regular delta.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (r0, r1, g0, g1, b0, b1).
+ * @param quant_level The quantization level to use.
+ *
+ * @return Returns @c false on failure, @c true on success.
+ */
+static bool try_quantize_rgb_delta(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[6],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float r0 = astc::clamp255f(color0.lane<0>() * scale);
+ float g0 = astc::clamp255f(color0.lane<1>() * scale);
+ float b0 = astc::clamp255f(color0.lane<2>() * scale);
+
+ float r1 = astc::clamp255f(color1.lane<0>() * scale);
+ float g1 = astc::clamp255f(color1.lane<1>() * scale);
+ float b1 = astc::clamp255f(color1.lane<2>() * scale);
+
+ // Transform r0 to unorm9
+ int r0a = astc::flt2int_rtn(r0);
+ int g0a = astc::flt2int_rtn(g0);
+ int b0a = astc::flt2int_rtn(b0);
+
+ r0a <<= 1;
+ g0a <<= 1;
+ b0a <<= 1;
+
+ // Mask off the top bit
+ int r0b = r0a & 0xFF;
+ int g0b = g0a & 0xFF;
+ int b0b = b0a & 0xFF;
+
+ // Quantize then unquantize in order to get a value that we take differences against
+ int r0be = quant_color(quant_level, r0b);
+ int g0be = quant_color(quant_level, g0b);
+ int b0be = quant_color(quant_level, b0b);
+
+ r0b = r0be | (r0a & 0x100);
+ g0b = g0be | (g0a & 0x100);
+ b0b = b0be | (b0a & 0x100);
+
+ // Get hold of the second value
+ int r1d = astc::flt2int_rtn(r1);
+ int g1d = astc::flt2int_rtn(g1);
+ int b1d = astc::flt2int_rtn(b1);
+
+ r1d <<= 1;
+ g1d <<= 1;
+ b1d <<= 1;
+
+ // ... and take differences
+ r1d -= r0b;
+ g1d -= g0b;
+ b1d -= b0b;
+
+ // Check if the difference is too large to be encodable
+ if (r1d > 63 || g1d > 63 || b1d > 63 || r1d < -64 || g1d < -64 || b1d < -64)
+ {
+ return false;
+ }
+
+ // Insert top bit of the base into the offset
+ r1d &= 0x7F;
+ g1d &= 0x7F;
+ b1d &= 0x7F;
+
+ r1d |= (r0b & 0x100) >> 1;
+ g1d |= (g0b & 0x100) >> 1;
+ b1d |= (b0b & 0x100) >> 1;
+
+ // Then quantize and unquantize; if this causes either top two bits to flip, then encoding fails
+ // since we have then corrupted either the top bit of the base or the sign bit of the offset
+ int r1de = quant_color(quant_level, r1d);
+ int g1de = quant_color(quant_level, g1d);
+ int b1de = quant_color(quant_level, b1d);
+
+ if (((r1d ^ r1de) | (g1d ^ g1de) | (b1d ^ b1de)) & 0xC0)
+ {
+ return false;
+ }
+
+ // If the sum of offsets triggers blue-contraction then encoding fails
+ vint4 ep0(r0be, g0be, b0be, 0);
+ vint4 ep1(r1de, g1de, b1de, 0);
+ bit_transfer_signed(ep1, ep0);
+ if (hadd_rgb_s(ep1) < 0)
+ {
+ return false;
+ }
+
+ // Check that the offsets produce legitimate sums as well
+ ep0 = ep0 + ep1;
+ if (any((ep0 < vint4(0)) | (ep0 > vint4(0xFF))))
+ {
+ return false;
+ }
+
+ output[0] = static_cast<uint8_t>(r0be);
+ output[1] = static_cast<uint8_t>(r1de);
+ output[2] = static_cast<uint8_t>(g0be);
+ output[3] = static_cast<uint8_t>(g1de);
+ output[4] = static_cast<uint8_t>(b0be);
+ output[5] = static_cast<uint8_t>(b1de);
+
+ return true;
+}
+
+static bool try_quantize_rgb_delta_blue_contract(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[6],
+ quant_method quant_level
+) {
+ // Note: Switch around endpoint colors already at start
+ float scale = 1.0f / 257.0f;
+
+ float r1 = color0.lane<0>() * scale;
+ float g1 = color0.lane<1>() * scale;
+ float b1 = color0.lane<2>() * scale;
+
+ float r0 = color1.lane<0>() * scale;
+ float g0 = color1.lane<1>() * scale;
+ float b0 = color1.lane<2>() * scale;
+
+ // Apply inverse blue-contraction. This can produce an overflow; which means BC cannot be used.
+ r0 += (r0 - b0);
+ g0 += (g0 - b0);
+ r1 += (r1 - b1);
+ g1 += (g1 - b1);
+
+ if (r0 < 0.0f || r0 > 255.0f || g0 < 0.0f || g0 > 255.0f || b0 < 0.0f || b0 > 255.0f ||
+ r1 < 0.0f || r1 > 255.0f || g1 < 0.0f || g1 > 255.0f || b1 < 0.0f || b1 > 255.0f)
+ {
+ return false;
+ }
+
+ // Transform r0 to unorm9
+ int r0a = astc::flt2int_rtn(r0);
+ int g0a = astc::flt2int_rtn(g0);
+ int b0a = astc::flt2int_rtn(b0);
+ r0a <<= 1;
+ g0a <<= 1;
+ b0a <<= 1;
+
+ // Mask off the top bit
+ int r0b = r0a & 0xFF;
+ int g0b = g0a & 0xFF;
+ int b0b = b0a & 0xFF;
+
+ // Quantize, then unquantize in order to get a value that we take differences against.
+ int r0be = quant_color(quant_level, r0b);
+ int g0be = quant_color(quant_level, g0b);
+ int b0be = quant_color(quant_level, b0b);
+
+ r0b = r0be | (r0a & 0x100);
+ g0b = g0be | (g0a & 0x100);
+ b0b = b0be | (b0a & 0x100);
+
+ // Get hold of the second value
+ int r1d = astc::flt2int_rtn(r1);
+ int g1d = astc::flt2int_rtn(g1);
+ int b1d = astc::flt2int_rtn(b1);
+
+ r1d <<= 1;
+ g1d <<= 1;
+ b1d <<= 1;
+
+ // .. and take differences!
+ r1d -= r0b;
+ g1d -= g0b;
+ b1d -= b0b;
+
+ // Check if the difference is too large to be encodable
+ if (r1d > 63 || g1d > 63 || b1d > 63 || r1d < -64 || g1d < -64 || b1d < -64)
+ {
+ return false;
+ }
+
+ // Insert top bit of the base into the offset
+ r1d &= 0x7F;
+ g1d &= 0x7F;
+ b1d &= 0x7F;
+
+ r1d |= (r0b & 0x100) >> 1;
+ g1d |= (g0b & 0x100) >> 1;
+ b1d |= (b0b & 0x100) >> 1;
+
+ // Then quantize and unquantize; if this causes any of the top two bits to flip,
+ // then encoding fails, since we have then corrupted either the top bit of the base
+ // or the sign bit of the offset.
+ int r1de = quant_color(quant_level, r1d);
+ int g1de = quant_color(quant_level, g1d);
+ int b1de = quant_color(quant_level, b1d);
+
+ if (((r1d ^ r1de) | (g1d ^ g1de) | (b1d ^ b1de)) & 0xC0)
+ {
+ return false;
+ }
+
+ // If the sum of offsets does not trigger blue-contraction then encoding fails
+ vint4 ep0(r0be, g0be, b0be, 0);
+ vint4 ep1(r1de, g1de, b1de, 0);
+ bit_transfer_signed(ep1, ep0);
+ if (hadd_rgb_s(ep1) >= 0)
+ {
+ return false;
+ }
+
+ // Check that the offsets produce legitimate sums as well
+ ep0 = ep0 + ep1;
+ if (any((ep0 < vint4(0)) | (ep0 > vint4(0xFF))))
+ {
+ return false;
+ }
+
+ output[0] = static_cast<uint8_t>(r0be);
+ output[1] = static_cast<uint8_t>(r1de);
+ output[2] = static_cast<uint8_t>(g0be);
+ output[3] = static_cast<uint8_t>(g1de);
+ output[4] = static_cast<uint8_t>(b0be);
+ output[5] = static_cast<uint8_t>(b1de);
+
+ return true;
+}
+
+/**
+ * @brief Try to quantize an LDR A color using delta encoding.
+ *
+ * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
+ * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
+ * non-negative, then we encode a regular delta.
+ *
+ * This function only compressed the alpha - the other elements in the output array are not touched.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (x, x, x, x, x, x, a0, a1).
+ * @param quant_level The quantization level to use.
+ *
+ * @return Returns @c false on failure, @c true on success.
+ */
+static bool try_quantize_alpha_delta(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[8],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float a0 = astc::clamp255f(color0.lane<3>() * scale);
+ float a1 = astc::clamp255f(color1.lane<3>() * scale);
+
+ int a0a = astc::flt2int_rtn(a0);
+ a0a <<= 1;
+ int a0b = a0a & 0xFF;
+ int a0be = quant_color(quant_level, a0b);
+ a0b = a0be;
+ a0b |= a0a & 0x100;
+ int a1d = astc::flt2int_rtn(a1);
+ a1d <<= 1;
+ a1d -= a0b;
+
+ if (a1d > 63 || a1d < -64)
+ {
+ return false;
+ }
+
+ a1d &= 0x7F;
+ a1d |= (a0b & 0x100) >> 1;
+
+ int a1de = quant_color(quant_level, a1d);
+ int a1du = a1de;
+ if ((a1d ^ a1du) & 0xC0)
+ {
+ return false;
+ }
+
+ a1du &= 0x7F;
+ if (a1du & 0x40)
+ {
+ a1du -= 0x80;
+ }
+
+ a1du += a0b;
+ if (a1du < 0 || a1du > 0x1FF)
+ {
+ return false;
+ }
+
+ output[6] = static_cast<uint8_t>(a0be);
+ output[7] = static_cast<uint8_t>(a1de);
+
+ return true;
+}
+
+/**
+ * @brief Try to quantize an LDR LA color using delta encoding.
+ *
+ * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
+ * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
+ * non-negative, then we encode a regular delta.
+ *
+ * This function only compressed the alpha - the other elements in the output array are not touched.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (l0, l1, a0, a1).
+ * @param quant_level The quantization level to use.
+ *
+ * @return Returns @c false on failure, @c true on success.
+ */
+static bool try_quantize_luminance_alpha_delta(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[4],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float l0 = astc::clamp255f(hadd_rgb_s(color0) * ((1.0f / 3.0f) * scale));
+ float l1 = astc::clamp255f(hadd_rgb_s(color1) * ((1.0f / 3.0f) * scale));
+
+ float a0 = astc::clamp255f(color0.lane<3>() * scale);
+ float a1 = astc::clamp255f(color1.lane<3>() * scale);
+
+ int l0a = astc::flt2int_rtn(l0);
+ int a0a = astc::flt2int_rtn(a0);
+ l0a <<= 1;
+ a0a <<= 1;
+
+ int l0b = l0a & 0xFF;
+ int a0b = a0a & 0xFF;
+ int l0be = quant_color(quant_level, l0b);
+ int a0be = quant_color(quant_level, a0b);
+ l0b = l0be;
+ a0b = a0be;
+ l0b |= l0a & 0x100;
+ a0b |= a0a & 0x100;
+
+ int l1d = astc::flt2int_rtn(l1);
+ int a1d = astc::flt2int_rtn(a1);
+ l1d <<= 1;
+ a1d <<= 1;
+ l1d -= l0b;
+ a1d -= a0b;
+
+ if (l1d > 63 || l1d < -64)
+ {
+ return false;
+ }
+
+ if (a1d > 63 || a1d < -64)
+ {
+ return false;
+ }
+
+ l1d &= 0x7F;
+ a1d &= 0x7F;
+ l1d |= (l0b & 0x100) >> 1;
+ a1d |= (a0b & 0x100) >> 1;
+
+ int l1de = quant_color(quant_level, l1d);
+ int a1de = quant_color(quant_level, a1d);
+ int l1du = l1de;
+ int a1du = a1de;
+
+ if ((l1d ^ l1du) & 0xC0)
+ {
+ return false;
+ }
+
+ if ((a1d ^ a1du) & 0xC0)
+ {
+ return false;
+ }
+
+ l1du &= 0x7F;
+ a1du &= 0x7F;
+
+ if (l1du & 0x40)
+ {
+ l1du -= 0x80;
+ }
+
+ if (a1du & 0x40)
+ {
+ a1du -= 0x80;
+ }
+
+ l1du += l0b;
+ a1du += a0b;
+
+ if (l1du < 0 || l1du > 0x1FF)
+ {
+ return false;
+ }
+
+ if (a1du < 0 || a1du > 0x1FF)
+ {
+ return false;
+ }
+
+ output[0] = static_cast<uint8_t>(l0be);
+ output[1] = static_cast<uint8_t>(l1de);
+ output[2] = static_cast<uint8_t>(a0be);
+ output[3] = static_cast<uint8_t>(a1de);
+
+ return true;
+}
+
+/**
+ * @brief Try to quantize an LDR RGBA color using delta encoding.
+ *
+ * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
+ * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
+ * non-negative, then we encode a regular delta.
+ *
+ * This function only compressed the alpha - the other elements in the output array are not touched.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (r0, r1, b0, b1, g0, g1, a0, a1).
+ * @param quant_level The quantization level to use.
+ *
+ * @return Returns @c false on failure, @c true on success.
+ */
+static bool try_quantize_rgba_delta(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[8],
+ quant_method quant_level
+) {
+ return try_quantize_rgb_delta(color0, color1, output, quant_level) &&
+ try_quantize_alpha_delta(color0, color1, output, quant_level);
+}
+
+
+/**
+ * @brief Try to quantize an LDR RGBA color using delta and blue contract encoding.
+ *
+ * At decode time we move one bit from the offset to the base and seize another bit as a sign bit;
+ * we then unquantize both values as if they contain one extra bit. If the sum of the offsets is
+ * non-negative, then we encode a regular delta.
+ *
+ * This function only compressed the alpha - the other elements in the output array are not touched.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (r0, r1, b0, b1, g0, g1, a0, a1).
+ * @param quant_level The quantization level to use.
+ *
+ * @return Returns @c false on failure, @c true on success.
+ */
+static bool try_quantize_rgba_delta_blue_contract(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[8],
+ quant_method quant_level
+) {
+ // Note that we swap the color0 and color1 ordering for alpha to match RGB blue-contract
+ return try_quantize_rgb_delta_blue_contract(color0, color1, output, quant_level) &&
+ try_quantize_alpha_delta(color1, color0, output, quant_level);
+}
+
+/**
+ * @brief Quantize an LDR RGB color using scale encoding.
+ *
+ * @param color The input unquantized color endpoint and scale factor.
+ * @param[out] output The output endpoints, returned as (r0, g0, b0, s).
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_rgbs(
+ vfloat4 color,
+ uint8_t output[4],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float r = astc::clamp255f(color.lane<0>() * scale);
+ float g = astc::clamp255f(color.lane<1>() * scale);
+ float b = astc::clamp255f(color.lane<2>() * scale);
+
+ int ri = quant_color(quant_level, astc::flt2int_rtn(r));
+ int gi = quant_color(quant_level, astc::flt2int_rtn(g));
+ int bi = quant_color(quant_level, astc::flt2int_rtn(b));
+
+ float oldcolorsum = hadd_rgb_s(color) * scale;
+ float newcolorsum = static_cast<float>(ri + gi + bi);
+
+ float scalea = astc::clamp1f(color.lane<3>() * (oldcolorsum + 1e-10f) / (newcolorsum + 1e-10f));
+ int scale_idx = astc::flt2int_rtn(scalea * 256.0f);
+ scale_idx = astc::clamp(scale_idx, 0, 255);
+
+ output[0] = static_cast<uint8_t>(ri);
+ output[1] = static_cast<uint8_t>(gi);
+ output[2] = static_cast<uint8_t>(bi);
+ output[3] = quant_color(quant_level, scale_idx);
+}
+
+/**
+ * @brief Quantize an LDR RGBA color using scale encoding.
+ *
+ * @param color The input unquantized color endpoint and scale factor.
+ * @param[out] output The output endpoints, returned as (r0, g0, b0, s, a0, a1).
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_rgbs_alpha(
+ vfloat4 color0,
+ vfloat4 color1,
+ vfloat4 color,
+ uint8_t output[6],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float a0 = astc::clamp255f(color0.lane<3>() * scale);
+ float a1 = astc::clamp255f(color1.lane<3>() * scale);
+
+ output[4] = quant_color(quant_level, astc::flt2int_rtn(a0));
+ output[5] = quant_color(quant_level, astc::flt2int_rtn(a1));
+
+ quantize_rgbs(color, output, quant_level);
+}
+
+/**
+ * @brief Quantize a LDR L color.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (l0, l1).
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_luminance(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[2],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ color0 = color0 * scale;
+ color1 = color1 * scale;
+
+ float lum0 = astc::clamp255f(hadd_rgb_s(color0) * (1.0f / 3.0f));
+ float lum1 = astc::clamp255f(hadd_rgb_s(color1) * (1.0f / 3.0f));
+
+ if (lum0 > lum1)
+ {
+ float avg = (lum0 + lum1) * 0.5f;
+ lum0 = avg;
+ lum1 = avg;
+ }
+
+ output[0] = quant_color(quant_level, astc::flt2int_rtn(lum0));
+ output[1] = quant_color(quant_level, astc::flt2int_rtn(lum1));
+}
+
+/**
+ * @brief Quantize a LDR LA color.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as (l0, l1, a0, a1).
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_luminance_alpha(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[4],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ color0 = color0 * scale;
+ color1 = color1 * scale;
+
+ float lum0 = astc::clamp255f(hadd_rgb_s(color0) * (1.0f / 3.0f));
+ float lum1 = astc::clamp255f(hadd_rgb_s(color1) * (1.0f / 3.0f));
+
+ float a0 = astc::clamp255f(color0.lane<3>());
+ float a1 = astc::clamp255f(color1.lane<3>());
+
+ // If endpoints are close then pull apart slightly; this gives > 8 bit normal map precision.
+ if (quant_level > 18)
+ {
+ if (fabsf(lum0 - lum1) < 3.0f)
+ {
+ if (lum0 < lum1)
+ {
+ lum0 -= 0.5f;
+ lum1 += 0.5f;
+ }
+ else
+ {
+ lum0 += 0.5f;
+ lum1 -= 0.5f;
+ }
+
+ lum0 = astc::clamp255f(lum0);
+ lum1 = astc::clamp255f(lum1);
+ }
+
+ if (fabsf(a0 - a1) < 3.0f)
+ {
+ if (a0 < a1)
+ {
+ a0 -= 0.5f;
+ a1 += 0.5f;
+ }
+ else
+ {
+ a0 += 0.5f;
+ a1 -= 0.5f;
+ }
+
+ a0 = astc::clamp255f(a0);
+ a1 = astc::clamp255f(a1);
+ }
+ }
+
+ output[0] = quant_color(quant_level, astc::flt2int_rtn(lum0));
+ output[1] = quant_color(quant_level, astc::flt2int_rtn(lum1));
+ output[2] = quant_color(quant_level, astc::flt2int_rtn(a0));
+ output[3] = quant_color(quant_level, astc::flt2int_rtn(a1));
+}
+
+/**
+ * @brief Quantize and unquantize a value ensuring top two bits are the same.
+ *
+ * @param quant_level The quantization level to use.
+ * @param value The input unquantized value.
+ * @param[out] quant_value The quantized value.
+ */
+static inline void quantize_and_unquantize_retain_top_two_bits(
+ quant_method quant_level,
+ uint8_t value,
+ uint8_t& quant_value
+) {
+ int perform_loop;
+ uint8_t quantval;
+
+ do
+ {
+ quantval = quant_color(quant_level, value);
+
+ // Perform looping if the top two bits were modified by quant/unquant
+ perform_loop = (value & 0xC0) != (quantval & 0xC0);
+
+ if ((quantval & 0xC0) > (value & 0xC0))
+ {
+ // Quant/unquant rounded UP so that the top two bits changed;
+ // decrement the input in hopes that this will avoid rounding up.
+ value--;
+ }
+ else if ((quantval & 0xC0) < (value & 0xC0))
+ {
+ // Quant/unquant rounded DOWN so that the top two bits changed;
+ // decrement the input in hopes that this will avoid rounding down.
+ value--;
+ }
+ } while (perform_loop);
+
+ quant_value = quantval;
+}
+
+/**
+ * @brief Quantize and unquantize a value ensuring top four bits are the same.
+ *
+ * @param quant_level The quantization level to use.
+ * @param value The input unquantized value.
+ * @param[out] quant_value The quantized value in 0-255 range.
+ */
+static inline void quantize_and_unquantize_retain_top_four_bits(
+ quant_method quant_level,
+ uint8_t value,
+ uint8_t& quant_value
+) {
+ uint8_t perform_loop;
+ uint8_t quantval;
+
+ do
+ {
+ quantval = quant_color(quant_level, value);
+ // Perform looping if the top four bits were modified by quant/unquant
+ perform_loop = (value & 0xF0) != (quantval & 0xF0);
+
+ if ((quantval & 0xF0) > (value & 0xF0))
+ {
+ // Quant/unquant rounded UP so that the top four bits changed;
+ // decrement the input value in hopes that this will avoid rounding up.
+ value--;
+ }
+ else if ((quantval & 0xF0) < (value & 0xF0))
+ {
+ // Quant/unquant rounded DOWN so that the top four bits changed;
+ // decrement the input value in hopes that this will avoid rounding down.
+ value--;
+ }
+ } while (perform_loop);
+
+ quant_value = quantval;
+}
+
+/**
+ * @brief Quantize a HDR RGB color using RGB + offset.
+ *
+ * @param color The input unquantized color endpoint and offset.
+ * @param[out] output The output endpoints, returned as packed RGBS with some mode bits.
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_hdr_rgbo(
+ vfloat4 color,
+ uint8_t output[4],
+ quant_method quant_level
+) {
+ color.set_lane<0>(color.lane<0>() + color.lane<3>());
+ color.set_lane<1>(color.lane<1>() + color.lane<3>());
+ color.set_lane<2>(color.lane<2>() + color.lane<3>());
+
+ color = clamp(0.0f, 65535.0f, color);
+
+ vfloat4 color_bak = color;
+
+ int majcomp;
+ if (color.lane<0>() > color.lane<1>() && color.lane<0>() > color.lane<2>())
+ {
+ majcomp = 0; // red is largest component
+ }
+ else if (color.lane<1>() > color.lane<2>())
+ {
+ majcomp = 1; // green is largest component
+ }
+ else
+ {
+ majcomp = 2; // blue is largest component
+ }
+
+ // swap around the red component and the largest component.
+ switch (majcomp)
+ {
+ case 1:
+ color = color.swz<1, 0, 2, 3>();
+ break;
+ case 2:
+ color = color.swz<2, 1, 0, 3>();
+ break;
+ default:
+ break;
+ }
+
+ static const int mode_bits[5][3] {
+ {11, 5, 7},
+ {11, 6, 5},
+ {10, 5, 8},
+ {9, 6, 7},
+ {8, 7, 6}
+ };
+
+ static const float mode_cutoffs[5][2] {
+ {1024, 4096},
+ {2048, 1024},
+ {2048, 16384},
+ {8192, 16384},
+ {32768, 16384}
+ };
+
+ static const float mode_rscales[5] {
+ 32.0f,
+ 32.0f,
+ 64.0f,
+ 128.0f,
+ 256.0f,
+ };
+
+ static const float mode_scales[5] {
+ 1.0f / 32.0f,
+ 1.0f / 32.0f,
+ 1.0f / 64.0f,
+ 1.0f / 128.0f,
+ 1.0f / 256.0f,
+ };
+
+ float r_base = color.lane<0>();
+ float g_base = color.lane<0>() - color.lane<1>() ;
+ float b_base = color.lane<0>() - color.lane<2>() ;
+ float s_base = color.lane<3>() ;
+
+ for (int mode = 0; mode < 5; mode++)
+ {
+ if (g_base > mode_cutoffs[mode][0] || b_base > mode_cutoffs[mode][0] || s_base > mode_cutoffs[mode][1])
+ {
+ continue;
+ }
+
+ // Encode the mode into a 4-bit vector
+ int mode_enc = mode < 4 ? (mode | (majcomp << 2)) : (majcomp | 0xC);
+
+ float mode_scale = mode_scales[mode];
+ float mode_rscale = mode_rscales[mode];
+
+ int gb_intcutoff = 1 << mode_bits[mode][1];
+ int s_intcutoff = 1 << mode_bits[mode][2];
+
+ // Quantize and unquantize R
+ int r_intval = astc::flt2int_rtn(r_base * mode_scale);
+
+ int r_lowbits = r_intval & 0x3f;
+
+ r_lowbits |= (mode_enc & 3) << 6;
+
+ uint8_t r_quantval;
+ quantize_and_unquantize_retain_top_two_bits(
+ quant_level, static_cast<uint8_t>(r_lowbits), r_quantval);
+
+ r_intval = (r_intval & ~0x3f) | (r_quantval & 0x3f);
+ float r_fval = static_cast<float>(r_intval) * mode_rscale;
+
+ // Recompute G and B, then quantize and unquantize them
+ float g_fval = r_fval - color.lane<1>() ;
+ float b_fval = r_fval - color.lane<2>() ;
+
+ g_fval = astc::clamp(g_fval, 0.0f, 65535.0f);
+ b_fval = astc::clamp(b_fval, 0.0f, 65535.0f);
+
+ int g_intval = astc::flt2int_rtn(g_fval * mode_scale);
+ int b_intval = astc::flt2int_rtn(b_fval * mode_scale);
+
+ if (g_intval >= gb_intcutoff || b_intval >= gb_intcutoff)
+ {
+ continue;
+ }
+
+ int g_lowbits = g_intval & 0x1f;
+ int b_lowbits = b_intval & 0x1f;
+
+ int bit0 = 0;
+ int bit1 = 0;
+ int bit2 = 0;
+ int bit3 = 0;
+
+ switch (mode)
+ {
+ case 0:
+ case 2:
+ bit0 = (r_intval >> 9) & 1;
+ break;
+ case 1:
+ case 3:
+ bit0 = (r_intval >> 8) & 1;
+ break;
+ case 4:
+ case 5:
+ bit0 = (g_intval >> 6) & 1;
+ break;
+ }
+
+ switch (mode)
+ {
+ case 0:
+ case 1:
+ case 2:
+ case 3:
+ bit2 = (r_intval >> 7) & 1;
+ break;
+ case 4:
+ case 5:
+ bit2 = (b_intval >> 6) & 1;
+ break;
+ }
+
+ switch (mode)
+ {
+ case 0:
+ case 2:
+ bit1 = (r_intval >> 8) & 1;
+ break;
+ case 1:
+ case 3:
+ case 4:
+ case 5:
+ bit1 = (g_intval >> 5) & 1;
+ break;
+ }
+
+ switch (mode)
+ {
+ case 0:
+ bit3 = (r_intval >> 10) & 1;
+ break;
+ case 2:
+ bit3 = (r_intval >> 6) & 1;
+ break;
+ case 1:
+ case 3:
+ case 4:
+ case 5:
+ bit3 = (b_intval >> 5) & 1;
+ break;
+ }
+
+ g_lowbits |= (mode_enc & 0x4) << 5;
+ b_lowbits |= (mode_enc & 0x8) << 4;
+
+ g_lowbits |= bit0 << 6;
+ g_lowbits |= bit1 << 5;
+ b_lowbits |= bit2 << 6;
+ b_lowbits |= bit3 << 5;
+
+ uint8_t g_quantval;
+ uint8_t b_quantval;
+
+ quantize_and_unquantize_retain_top_four_bits(
+ quant_level, static_cast<uint8_t>(g_lowbits), g_quantval);
+ quantize_and_unquantize_retain_top_four_bits(
+ quant_level, static_cast<uint8_t>(b_lowbits), b_quantval);
+
+ g_intval = (g_intval & ~0x1f) | (g_quantval & 0x1f);
+ b_intval = (b_intval & ~0x1f) | (b_quantval & 0x1f);
+
+ g_fval = static_cast<float>(g_intval) * mode_rscale;
+ b_fval = static_cast<float>(b_intval) * mode_rscale;
+
+ // Recompute the scale value, based on the errors introduced to red, green and blue
+
+ // If the error is positive, then the R,G,B errors combined have raised the color
+ // value overall; as such, the scale value needs to be increased.
+ float rgb_errorsum = (r_fval - color.lane<0>() ) + (r_fval - g_fval - color.lane<1>() ) + (r_fval - b_fval - color.lane<2>() );
+
+ float s_fval = s_base + rgb_errorsum * (1.0f / 3.0f);
+ s_fval = astc::clamp(s_fval, 0.0f, 1e9f);
+
+ int s_intval = astc::flt2int_rtn(s_fval * mode_scale);
+
+ if (s_intval >= s_intcutoff)
+ {
+ continue;
+ }
+
+ int s_lowbits = s_intval & 0x1f;
+
+ int bit4;
+ int bit5;
+ int bit6;
+ switch (mode)
+ {
+ case 1:
+ bit6 = (r_intval >> 9) & 1;
+ break;
+ default:
+ bit6 = (s_intval >> 5) & 1;
+ break;
+ }
+
+ switch (mode)
+ {
+ case 4:
+ bit5 = (r_intval >> 7) & 1;
+ break;
+ case 1:
+ bit5 = (r_intval >> 10) & 1;
+ break;
+ default:
+ bit5 = (s_intval >> 6) & 1;
+ break;
+ }
+
+ switch (mode)
+ {
+ case 2:
+ bit4 = (s_intval >> 7) & 1;
+ break;
+ default:
+ bit4 = (r_intval >> 6) & 1;
+ break;
+ }
+
+ s_lowbits |= bit6 << 5;
+ s_lowbits |= bit5 << 6;
+ s_lowbits |= bit4 << 7;
+
+ uint8_t s_quantval;
+
+ quantize_and_unquantize_retain_top_four_bits(
+ quant_level, static_cast<uint8_t>(s_lowbits), s_quantval);
+
+ output[0] = r_quantval;
+ output[1] = g_quantval;
+ output[2] = b_quantval;
+ output[3] = s_quantval;
+ return;
+ }
+
+ // Failed to encode any of the modes above? In that case encode using mode #5
+ float vals[4];
+ vals[0] = color_bak.lane<0>();
+ vals[1] = color_bak.lane<1>();
+ vals[2] = color_bak.lane<2>();
+ vals[3] = color_bak.lane<3>();
+
+ int ivals[4];
+ float cvals[3];
+
+ for (int i = 0; i < 3; i++)
+ {
+ vals[i] = astc::clamp(vals[i], 0.0f, 65020.0f);
+ ivals[i] = astc::flt2int_rtn(vals[i] * (1.0f / 512.0f));
+ cvals[i] = static_cast<float>(ivals[i]) * 512.0f;
+ }
+
+ float rgb_errorsum = (cvals[0] - vals[0]) + (cvals[1] - vals[1]) + (cvals[2] - vals[2]);
+ vals[3] += rgb_errorsum * (1.0f / 3.0f);
+
+ vals[3] = astc::clamp(vals[3], 0.0f, 65020.0f);
+ ivals[3] = astc::flt2int_rtn(vals[3] * (1.0f / 512.0f));
+
+ int encvals[4];
+ encvals[0] = (ivals[0] & 0x3f) | 0xC0;
+ encvals[1] = (ivals[1] & 0x7f) | 0x80;
+ encvals[2] = (ivals[2] & 0x7f) | 0x80;
+ encvals[3] = (ivals[3] & 0x7f) | ((ivals[0] & 0x40) << 1);
+
+ for (uint8_t i = 0; i < 4; i++)
+ {
+ quantize_and_unquantize_retain_top_four_bits(
+ quant_level, static_cast<uint8_t>(encvals[i]), output[i]);
+ }
+
+ return;
+}
+
+/**
+ * @brief Quantize a HDR RGB color using direct RGB encoding.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as packed RGB+RGB pairs with mode bits.
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_hdr_rgb(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[6],
+ quant_method quant_level
+) {
+ // Note: color*.lane<3> is not used so we can ignore it
+ color0 = clamp(0.0f, 65535.0f, color0);
+ color1 = clamp(0.0f, 65535.0f, color1);
+
+ vfloat4 color0_bak = color0;
+ vfloat4 color1_bak = color1;
+
+ int majcomp;
+ if (color1.lane<0>() > color1.lane<1>() && color1.lane<0>() > color1.lane<2>())
+ {
+ majcomp = 0;
+ }
+ else if (color1.lane<1>() > color1.lane<2>())
+ {
+ majcomp = 1;
+ }
+ else
+ {
+ majcomp = 2;
+ }
+
+ // Swizzle the components
+ switch (majcomp)
+ {
+ case 1: // red-green swap
+ color0 = color0.swz<1, 0, 2, 3>();
+ color1 = color1.swz<1, 0, 2, 3>();
+ break;
+ case 2: // red-blue swap
+ color0 = color0.swz<2, 1, 0, 3>();
+ color1 = color1.swz<2, 1, 0, 3>();
+ break;
+ default:
+ break;
+ }
+
+ float a_base = color1.lane<0>();
+ a_base = astc::clamp(a_base, 0.0f, 65535.0f);
+
+ float b0_base = a_base - color1.lane<1>();
+ float b1_base = a_base - color1.lane<2>();
+ float c_base = a_base - color0.lane<0>();
+ float d0_base = a_base - b0_base - c_base - color0.lane<1>();
+ float d1_base = a_base - b1_base - c_base - color0.lane<2>();
+
+ // Number of bits in the various fields in the various modes
+ static const int mode_bits[8][4] {
+ {9, 7, 6, 7},
+ {9, 8, 6, 6},
+ {10, 6, 7, 7},
+ {10, 7, 7, 6},
+ {11, 8, 6, 5},
+ {11, 6, 8, 6},
+ {12, 7, 7, 5},
+ {12, 6, 7, 6}
+ };
+
+ // Cutoffs to use for the computed values of a,b,c,d, assuming the
+ // range 0..65535 are LNS values corresponding to fp16.
+ static const float mode_cutoffs[8][4] {
+ {16384, 8192, 8192, 8}, // mode 0: 9,7,6,7
+ {32768, 8192, 4096, 8}, // mode 1: 9,8,6,6
+ {4096, 8192, 4096, 4}, // mode 2: 10,6,7,7
+ {8192, 8192, 2048, 4}, // mode 3: 10,7,7,6
+ {8192, 2048, 512, 2}, // mode 4: 11,8,6,5
+ {2048, 8192, 1024, 2}, // mode 5: 11,6,8,6
+ {2048, 2048, 256, 1}, // mode 6: 12,7,7,5
+ {1024, 2048, 512, 1}, // mode 7: 12,6,7,6
+ };
+
+ static const float mode_scales[8] {
+ 1.0f / 128.0f,
+ 1.0f / 128.0f,
+ 1.0f / 64.0f,
+ 1.0f / 64.0f,
+ 1.0f / 32.0f,
+ 1.0f / 32.0f,
+ 1.0f / 16.0f,
+ 1.0f / 16.0f,
+ };
+
+ // Scaling factors when going from what was encoded in the mode to 16 bits.
+ static const float mode_rscales[8] {
+ 128.0f,
+ 128.0f,
+ 64.0f,
+ 64.0f,
+ 32.0f,
+ 32.0f,
+ 16.0f,
+ 16.0f
+ };
+
+ // Try modes one by one, with the highest-precision mode first.
+ for (int mode = 7; mode >= 0; mode--)
+ {
+ // For each mode, test if we can in fact accommodate the computed b, c, and d values.
+ // If we clearly can't, then we skip to the next mode.
+
+ float b_cutoff = mode_cutoffs[mode][0];
+ float c_cutoff = mode_cutoffs[mode][1];
+ float d_cutoff = mode_cutoffs[mode][2];
+
+ if (b0_base > b_cutoff || b1_base > b_cutoff || c_base > c_cutoff || fabsf(d0_base) > d_cutoff || fabsf(d1_base) > d_cutoff)
+ {
+ continue;
+ }
+
+ float mode_scale = mode_scales[mode];
+ float mode_rscale = mode_rscales[mode];
+
+ int b_intcutoff = 1 << mode_bits[mode][1];
+ int c_intcutoff = 1 << mode_bits[mode][2];
+ int d_intcutoff = 1 << (mode_bits[mode][3] - 1);
+
+ // Quantize and unquantize A, with the assumption that its high bits can be handled safely.
+ int a_intval = astc::flt2int_rtn(a_base * mode_scale);
+ int a_lowbits = a_intval & 0xFF;
+
+ int a_quantval = quant_color(quant_level, a_lowbits);
+ int a_uquantval = a_quantval;
+ a_intval = (a_intval & ~0xFF) | a_uquantval;
+ float a_fval = static_cast<float>(a_intval) * mode_rscale;
+
+ // Recompute C, then quantize and unquantize it
+ float c_fval = a_fval - color0.lane<0>();
+ c_fval = astc::clamp(c_fval, 0.0f, 65535.0f);
+
+ int c_intval = astc::flt2int_rtn(c_fval * mode_scale);
+
+ if (c_intval >= c_intcutoff)
+ {
+ continue;
+ }
+
+ int c_lowbits = c_intval & 0x3f;
+
+ c_lowbits |= (mode & 1) << 7;
+ c_lowbits |= (a_intval & 0x100) >> 2;
+
+ uint8_t c_quantval;
+
+ quantize_and_unquantize_retain_top_two_bits(
+ quant_level, static_cast<uint8_t>(c_lowbits), c_quantval);
+
+ c_intval = (c_intval & ~0x3F) | (c_quantval & 0x3F);
+ c_fval = static_cast<float>(c_intval) * mode_rscale;
+
+ // Recompute B0 and B1, then quantize and unquantize them
+ float b0_fval = a_fval - color1.lane<1>();
+ float b1_fval = a_fval - color1.lane<2>();
+
+ b0_fval = astc::clamp(b0_fval, 0.0f, 65535.0f);
+ b1_fval = astc::clamp(b1_fval, 0.0f, 65535.0f);
+ int b0_intval = astc::flt2int_rtn(b0_fval * mode_scale);
+ int b1_intval = astc::flt2int_rtn(b1_fval * mode_scale);
+
+ if (b0_intval >= b_intcutoff || b1_intval >= b_intcutoff)
+ {
+ continue;
+ }
+
+ int b0_lowbits = b0_intval & 0x3f;
+ int b1_lowbits = b1_intval & 0x3f;
+
+ int bit0 = 0;
+ int bit1 = 0;
+ switch (mode)
+ {
+ case 0:
+ case 1:
+ case 3:
+ case 4:
+ case 6:
+ bit0 = (b0_intval >> 6) & 1;
+ break;
+ case 2:
+ case 5:
+ case 7:
+ bit0 = (a_intval >> 9) & 1;
+ break;
+ }
+
+ switch (mode)
+ {
+ case 0:
+ case 1:
+ case 3:
+ case 4:
+ case 6:
+ bit1 = (b1_intval >> 6) & 1;
+ break;
+ case 2:
+ bit1 = (c_intval >> 6) & 1;
+ break;
+ case 5:
+ case 7:
+ bit1 = (a_intval >> 10) & 1;
+ break;
+ }
+
+ b0_lowbits |= bit0 << 6;
+ b1_lowbits |= bit1 << 6;
+
+ b0_lowbits |= ((mode >> 1) & 1) << 7;
+ b1_lowbits |= ((mode >> 2) & 1) << 7;
+
+ uint8_t b0_quantval;
+ uint8_t b1_quantval;
+
+ quantize_and_unquantize_retain_top_two_bits(
+ quant_level, static_cast<uint8_t>(b0_lowbits), b0_quantval);
+ quantize_and_unquantize_retain_top_two_bits(
+ quant_level, static_cast<uint8_t>(b1_lowbits), b1_quantval);
+
+ b0_intval = (b0_intval & ~0x3f) | (b0_quantval & 0x3f);
+ b1_intval = (b1_intval & ~0x3f) | (b1_quantval & 0x3f);
+ b0_fval = static_cast<float>(b0_intval) * mode_rscale;
+ b1_fval = static_cast<float>(b1_intval) * mode_rscale;
+
+ // Recompute D0 and D1, then quantize and unquantize them
+ float d0_fval = a_fval - b0_fval - c_fval - color0.lane<1>();
+ float d1_fval = a_fval - b1_fval - c_fval - color0.lane<2>();
+
+ d0_fval = astc::clamp(d0_fval, -65535.0f, 65535.0f);
+ d1_fval = astc::clamp(d1_fval, -65535.0f, 65535.0f);
+
+ int d0_intval = astc::flt2int_rtn(d0_fval * mode_scale);
+ int d1_intval = astc::flt2int_rtn(d1_fval * mode_scale);
+
+ if (abs(d0_intval) >= d_intcutoff || abs(d1_intval) >= d_intcutoff)
+ {
+ continue;
+ }
+
+ int d0_lowbits = d0_intval & 0x1f;
+ int d1_lowbits = d1_intval & 0x1f;
+
+ int bit2 = 0;
+ int bit3 = 0;
+ int bit4;
+ int bit5;
+ switch (mode)
+ {
+ case 0:
+ case 2:
+ bit2 = (d0_intval >> 6) & 1;
+ break;
+ case 1:
+ case 4:
+ bit2 = (b0_intval >> 7) & 1;
+ break;
+ case 3:
+ bit2 = (a_intval >> 9) & 1;
+ break;
+ case 5:
+ bit2 = (c_intval >> 7) & 1;
+ break;
+ case 6:
+ case 7:
+ bit2 = (a_intval >> 11) & 1;
+ break;
+ }
+ switch (mode)
+ {
+ case 0:
+ case 2:
+ bit3 = (d1_intval >> 6) & 1;
+ break;
+ case 1:
+ case 4:
+ bit3 = (b1_intval >> 7) & 1;
+ break;
+ case 3:
+ case 5:
+ case 6:
+ case 7:
+ bit3 = (c_intval >> 6) & 1;
+ break;
+ }
+
+ switch (mode)
+ {
+ case 4:
+ case 6:
+ bit4 = (a_intval >> 9) & 1;
+ bit5 = (a_intval >> 10) & 1;
+ break;
+ default:
+ bit4 = (d0_intval >> 5) & 1;
+ bit5 = (d1_intval >> 5) & 1;
+ break;
+ }
+
+ d0_lowbits |= bit2 << 6;
+ d1_lowbits |= bit3 << 6;
+ d0_lowbits |= bit4 << 5;
+ d1_lowbits |= bit5 << 5;
+
+ d0_lowbits |= (majcomp & 1) << 7;
+ d1_lowbits |= ((majcomp >> 1) & 1) << 7;
+
+ uint8_t d0_quantval;
+ uint8_t d1_quantval;
+
+ quantize_and_unquantize_retain_top_four_bits(
+ quant_level, static_cast<uint8_t>(d0_lowbits), d0_quantval);
+ quantize_and_unquantize_retain_top_four_bits(
+ quant_level, static_cast<uint8_t>(d1_lowbits), d1_quantval);
+
+ output[0] = static_cast<uint8_t>(a_quantval);
+ output[1] = c_quantval;
+ output[2] = b0_quantval;
+ output[3] = b1_quantval;
+ output[4] = d0_quantval;
+ output[5] = d1_quantval;
+ return;
+ }
+
+ // If neither of the modes fit we will use a flat representation for storing data, using 8 bits
+ // for red and green, and 7 bits for blue. This gives color accuracy roughly similar to LDR
+ // 4:4:3 which is not at all great but usable. This representation is used if the light color is
+ // more than 4x the color value of the dark color.
+ float vals[6];
+ vals[0] = color0_bak.lane<0>();
+ vals[1] = color1_bak.lane<0>();
+ vals[2] = color0_bak.lane<1>();
+ vals[3] = color1_bak.lane<1>();
+ vals[4] = color0_bak.lane<2>();
+ vals[5] = color1_bak.lane<2>();
+
+ for (int i = 0; i < 6; i++)
+ {
+ vals[i] = astc::clamp(vals[i], 0.0f, 65020.0f);
+ }
+
+ for (int i = 0; i < 4; i++)
+ {
+ int idx = astc::flt2int_rtn(vals[i] * 1.0f / 256.0f);
+ output[i] = quant_color(quant_level, idx);
+ }
+
+ for (int i = 4; i < 6; i++)
+ {
+ int idx = astc::flt2int_rtn(vals[i] * 1.0f / 512.0f) + 128;
+ quantize_and_unquantize_retain_top_two_bits(
+ quant_level, static_cast<uint8_t>(idx), output[i]);
+ }
+
+ return;
+}
+
+/**
+ * @brief Quantize a HDR RGB + LDR A color using direct RGBA encoding.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits.
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_hdr_rgb_ldr_alpha(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[8],
+ quant_method quant_level
+) {
+ float scale = 1.0f / 257.0f;
+
+ float a0 = astc::clamp255f(color0.lane<3>() * scale);
+ float a1 = astc::clamp255f(color1.lane<3>() * scale);
+
+ output[6] = quant_color(quant_level, astc::flt2int_rtn(a0));
+ output[7] = quant_color(quant_level, astc::flt2int_rtn(a1));
+
+ quantize_hdr_rgb(color0, color1, output, quant_level);
+}
+
+/**
+ * @brief Quantize a HDR L color using the large range encoding.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as packed (l0, l1).
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_hdr_luminance_large_range(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[2],
+ quant_method quant_level
+) {
+ float lum0 = hadd_rgb_s(color0) * (1.0f / 3.0f);
+ float lum1 = hadd_rgb_s(color1) * (1.0f / 3.0f);
+
+ if (lum1 < lum0)
+ {
+ float avg = (lum0 + lum1) * 0.5f;
+ lum0 = avg;
+ lum1 = avg;
+ }
+
+ int ilum1 = astc::flt2int_rtn(lum1);
+ int ilum0 = astc::flt2int_rtn(lum0);
+
+ // Find the closest encodable point in the upper half of the code-point space
+ int upper_v0 = (ilum0 + 128) >> 8;
+ int upper_v1 = (ilum1 + 128) >> 8;
+
+ upper_v0 = astc::clamp(upper_v0, 0, 255);
+ upper_v1 = astc::clamp(upper_v1, 0, 255);
+
+ // Find the closest encodable point in the lower half of the code-point space
+ int lower_v0 = (ilum1 + 256) >> 8;
+ int lower_v1 = ilum0 >> 8;
+
+ lower_v0 = astc::clamp(lower_v0, 0, 255);
+ lower_v1 = astc::clamp(lower_v1, 0, 255);
+
+ // Determine the distance between the point in code-point space and the input value
+ int upper0_dec = upper_v0 << 8;
+ int upper1_dec = upper_v1 << 8;
+ int lower0_dec = (lower_v1 << 8) + 128;
+ int lower1_dec = (lower_v0 << 8) - 128;
+
+ int upper0_diff = upper0_dec - ilum0;
+ int upper1_diff = upper1_dec - ilum1;
+ int lower0_diff = lower0_dec - ilum0;
+ int lower1_diff = lower1_dec - ilum1;
+
+ int upper_error = (upper0_diff * upper0_diff) + (upper1_diff * upper1_diff);
+ int lower_error = (lower0_diff * lower0_diff) + (lower1_diff * lower1_diff);
+
+ int v0, v1;
+ if (upper_error < lower_error)
+ {
+ v0 = upper_v0;
+ v1 = upper_v1;
+ }
+ else
+ {
+ v0 = lower_v0;
+ v1 = lower_v1;
+ }
+
+ // OK; encode
+ output[0] = quant_color(quant_level, v0);
+ output[1] = quant_color(quant_level, v1);
+}
+
+/**
+ * @brief Quantize a HDR L color using the small range encoding.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as packed (l0, l1) with mode bits.
+ * @param quant_level The quantization level to use.
+ *
+ * @return Returns @c false on failure, @c true on success.
+ */
+static bool try_quantize_hdr_luminance_small_range(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[2],
+ quant_method quant_level
+) {
+ float lum0 = hadd_rgb_s(color0) * (1.0f / 3.0f);
+ float lum1 = hadd_rgb_s(color1) * (1.0f / 3.0f);
+
+ if (lum1 < lum0)
+ {
+ float avg = (lum0 + lum1) * 0.5f;
+ lum0 = avg;
+ lum1 = avg;
+ }
+
+ int ilum1 = astc::flt2int_rtn(lum1);
+ int ilum0 = astc::flt2int_rtn(lum0);
+
+ // Difference of more than a factor-of-2 results in immediate failure
+ if (ilum1 - ilum0 > 2048)
+ {
+ return false;
+ }
+
+ int lowval, highval, diffval;
+ int v0, v1;
+ int v0e, v1e;
+ int v0d, v1d;
+
+ // Try to encode the high-precision submode
+ lowval = (ilum0 + 16) >> 5;
+ highval = (ilum1 + 16) >> 5;
+
+ lowval = astc::clamp(lowval, 0, 2047);
+ highval = astc::clamp(highval, 0, 2047);
+
+ v0 = lowval & 0x7F;
+ v0e = quant_color(quant_level, v0);
+ v0d = v0e;
+
+ if (v0d < 0x80)
+ {
+ lowval = (lowval & ~0x7F) | v0d;
+ diffval = highval - lowval;
+ if (diffval >= 0 && diffval <= 15)
+ {
+ v1 = ((lowval >> 3) & 0xF0) | diffval;
+ v1e = quant_color(quant_level, v1);
+ v1d = v1e;
+ if ((v1d & 0xF0) == (v1 & 0xF0))
+ {
+ output[0] = static_cast<uint8_t>(v0e);
+ output[1] = static_cast<uint8_t>(v1e);
+ return true;
+ }
+ }
+ }
+
+ // Try to encode the low-precision submode
+ lowval = (ilum0 + 32) >> 6;
+ highval = (ilum1 + 32) >> 6;
+
+ lowval = astc::clamp(lowval, 0, 1023);
+ highval = astc::clamp(highval, 0, 1023);
+
+ v0 = (lowval & 0x7F) | 0x80;
+ v0e = quant_color(quant_level, v0);
+ v0d = v0e;
+ if ((v0d & 0x80) == 0)
+ {
+ return false;
+ }
+
+ lowval = (lowval & ~0x7F) | (v0d & 0x7F);
+ diffval = highval - lowval;
+ if (diffval < 0 || diffval > 31)
+ {
+ return false;
+ }
+
+ v1 = ((lowval >> 2) & 0xE0) | diffval;
+ v1e = quant_color(quant_level, v1);
+ v1d = v1e;
+ if ((v1d & 0xE0) != (v1 & 0xE0))
+ {
+ return false;
+ }
+
+ output[0] = static_cast<uint8_t>(v0e);
+ output[1] = static_cast<uint8_t>(v1e);
+ return true;
+}
+
+/**
+ * @brief Quantize a HDR A color using either delta or direct RGBA encoding.
+ *
+ * @param alpha0 The input unquantized color0 endpoint.
+ * @param alpha1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits.
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_hdr_alpha(
+ float alpha0,
+ float alpha1,
+ uint8_t output[2],
+ quant_method quant_level
+) {
+ alpha0 = astc::clamp(alpha0, 0.0f, 65280.0f);
+ alpha1 = astc::clamp(alpha1, 0.0f, 65280.0f);
+
+ int ialpha0 = astc::flt2int_rtn(alpha0);
+ int ialpha1 = astc::flt2int_rtn(alpha1);
+
+ int val0, val1, diffval;
+ int v6, v7;
+ int v6e, v7e;
+ int v6d, v7d;
+
+ // Try to encode one of the delta submodes, in decreasing-precision order
+ for (int i = 2; i >= 0; i--)
+ {
+ val0 = (ialpha0 + (128 >> i)) >> (8 - i);
+ val1 = (ialpha1 + (128 >> i)) >> (8 - i);
+
+ v6 = (val0 & 0x7F) | ((i & 1) << 7);
+ v6e = quant_color(quant_level, v6);
+ v6d = v6e;
+
+ if ((v6 ^ v6d) & 0x80)
+ {
+ continue;
+ }
+
+ val0 = (val0 & ~0x7f) | (v6d & 0x7f);
+ diffval = val1 - val0;
+ int cutoff = 32 >> i;
+ int mask = 2 * cutoff - 1;
+
+ if (diffval < -cutoff || diffval >= cutoff)
+ {
+ continue;
+ }
+
+ v7 = ((i & 2) << 6) | ((val0 >> 7) << (6 - i)) | (diffval & mask);
+ v7e = quant_color(quant_level, v7);
+ v7d = v7e;
+
+ static const int testbits[3] { 0xE0, 0xF0, 0xF8 };
+
+ if ((v7 ^ v7d) & testbits[i])
+ {
+ continue;
+ }
+
+ output[0] = static_cast<uint8_t>(v6e);
+ output[1] = static_cast<uint8_t>(v7e);
+ return;
+ }
+
+ // Could not encode any of the delta modes; instead encode a flat value
+ val0 = (ialpha0 + 256) >> 9;
+ val1 = (ialpha1 + 256) >> 9;
+ v6 = val0 | 0x80;
+ v7 = val1 | 0x80;
+
+ output[0] = quant_color(quant_level, v6);
+ output[1] = quant_color(quant_level, v7);
+
+ return;
+}
+
+/**
+ * @brief Quantize a HDR RGBA color using either delta or direct RGBA encoding.
+ *
+ * @param color0 The input unquantized color0 endpoint.
+ * @param color1 The input unquantized color1 endpoint.
+ * @param[out] output The output endpoints, returned as packed RGBA+RGBA pairs with mode bits.
+ * @param quant_level The quantization level to use.
+ */
+static void quantize_hdr_rgb_alpha(
+ vfloat4 color0,
+ vfloat4 color1,
+ uint8_t output[8],
+ quant_method quant_level
+) {
+ quantize_hdr_rgb(color0, color1, output, quant_level);
+ quantize_hdr_alpha(color0.lane<3>(), color1.lane<3>(), output + 6, quant_level);
+}
+
+/* See header for documentation. */
+uint8_t pack_color_endpoints(
+ vfloat4 color0,
+ vfloat4 color1,
+ vfloat4 rgbs_color,
+ vfloat4 rgbo_color,
+ int format,
+ uint8_t* output,
+ quant_method quant_level
+) {
+ assert(QUANT_6 <= quant_level && quant_level <= QUANT_256);
+
+ // We do not support negative colors
+ color0 = max(color0, 0.0f);
+ color1 = max(color1, 0.0f);
+
+ uint8_t retval = 0;
+
+ switch (format)
+ {
+ case FMT_RGB:
+ if (quant_level <= QUANT_160)
+ {
+ if (try_quantize_rgb_delta_blue_contract(color0, color1, output, quant_level))
+ {
+ retval = FMT_RGB_DELTA;
+ break;
+ }
+ if (try_quantize_rgb_delta(color0, color1, output, quant_level))
+ {
+ retval = FMT_RGB_DELTA;
+ break;
+ }
+ }
+ if (quant_level < QUANT_256 && try_quantize_rgb_blue_contract(color0, color1, output, quant_level))
+ {
+ retval = FMT_RGB;
+ break;
+ }
+ quantize_rgb(color0, color1, output, quant_level);
+ retval = FMT_RGB;
+ break;
+
+ case FMT_RGBA:
+ if (quant_level <= QUANT_160)
+ {
+ if (try_quantize_rgba_delta_blue_contract(color0, color1, output, quant_level))
+ {
+ retval = FMT_RGBA_DELTA;
+ break;
+ }
+ if (try_quantize_rgba_delta(color0, color1, output, quant_level))
+ {
+ retval = FMT_RGBA_DELTA;
+ break;
+ }
+ }
+ if (quant_level < QUANT_256 && try_quantize_rgba_blue_contract(color0, color1, output, quant_level))
+ {
+ retval = FMT_RGBA;
+ break;
+ }
+ quantize_rgba(color0, color1, output, quant_level);
+ retval = FMT_RGBA;
+ break;
+
+ case FMT_RGB_SCALE:
+ quantize_rgbs(rgbs_color, output, quant_level);
+ retval = FMT_RGB_SCALE;
+ break;
+
+ case FMT_HDR_RGB_SCALE:
+ quantize_hdr_rgbo(rgbo_color, output, quant_level);
+ retval = FMT_HDR_RGB_SCALE;
+ break;
+
+ case FMT_HDR_RGB:
+ quantize_hdr_rgb(color0, color1, output, quant_level);
+ retval = FMT_HDR_RGB;
+ break;
+
+ case FMT_RGB_SCALE_ALPHA:
+ quantize_rgbs_alpha(color0, color1, rgbs_color, output, quant_level);
+ retval = FMT_RGB_SCALE_ALPHA;
+ break;
+
+ case FMT_HDR_LUMINANCE_SMALL_RANGE:
+ case FMT_HDR_LUMINANCE_LARGE_RANGE:
+ if (try_quantize_hdr_luminance_small_range(color0, color1, output, quant_level))
+ {
+ retval = FMT_HDR_LUMINANCE_SMALL_RANGE;
+ break;
+ }
+ quantize_hdr_luminance_large_range(color0, color1, output, quant_level);
+ retval = FMT_HDR_LUMINANCE_LARGE_RANGE;
+ break;
+
+ case FMT_LUMINANCE:
+ quantize_luminance(color0, color1, output, quant_level);
+ retval = FMT_LUMINANCE;
+ break;
+
+ case FMT_LUMINANCE_ALPHA:
+ if (quant_level <= 18)
+ {
+ if (try_quantize_luminance_alpha_delta(color0, color1, output, quant_level))
+ {
+ retval = FMT_LUMINANCE_ALPHA_DELTA;
+ break;
+ }
+ }
+ quantize_luminance_alpha(color0, color1, output, quant_level);
+ retval = FMT_LUMINANCE_ALPHA;
+ break;
+
+ case FMT_HDR_RGB_LDR_ALPHA:
+ quantize_hdr_rgb_ldr_alpha(color0, color1, output, quant_level);
+ retval = FMT_HDR_RGB_LDR_ALPHA;
+ break;
+
+ case FMT_HDR_RGBA:
+ quantize_hdr_rgb_alpha(color0, color1, output, quant_level);
+ retval = FMT_HDR_RGBA;
+ break;
+ }
+
+ return retval;
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_color_unquantize.cpp b/thirdparty/astcenc/astcenc_color_unquantize.cpp
new file mode 100644
index 0000000000..d31895a627
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_color_unquantize.cpp
@@ -0,0 +1,941 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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 <utility>
+
+/**
+ * @brief Functions for color unquantization.
+ */
+
+#include "astcenc_internal.h"
+
+/**
+ * @brief Un-blue-contract a color.
+ *
+ * This function reverses any applied blue contraction.
+ *
+ * @param input The input color that has been blue-contracted.
+ *
+ * @return The uncontracted color.
+ */
+static ASTCENC_SIMD_INLINE vint4 uncontract_color(
+ vint4 input
+) {
+ vmask4 mask(true, true, false, false);
+ vint4 bc0 = asr<1>(input + input.lane<2>());
+ return select(input, bc0, mask);
+}
+
+/**
+ * @brief Unpack an LDR RGBA color that uses delta encoding.
+ *
+ * @param input0 The packed endpoint 0 color.
+ * @param input1 The packed endpoint 1 color deltas.
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void rgba_delta_unpack(
+ vint4 input0,
+ vint4 input1,
+ vint4& output0,
+ vint4& output1
+) {
+ // Apply bit transfer
+ bit_transfer_signed(input1, input0);
+
+ // Apply blue-uncontraction if needed
+ int rgb_sum = hadd_rgb_s(input1);
+ input1 = input1 + input0;
+ if (rgb_sum < 0)
+ {
+ input0 = uncontract_color(input0);
+ input1 = uncontract_color(input1);
+ std::swap(input0, input1);
+ }
+
+ output0 = clamp(0, 255, input0);
+ output1 = clamp(0, 255, input1);
+}
+
+/**
+ * @brief Unpack an LDR RGB color that uses delta encoding.
+ *
+ * Output alpha set to 255.
+ *
+ * @param input0 The packed endpoint 0 color.
+ * @param input1 The packed endpoint 1 color deltas.
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void rgb_delta_unpack(
+ vint4 input0,
+ vint4 input1,
+ vint4& output0,
+ vint4& output1
+) {
+ rgba_delta_unpack(input0, input1, output0, output1);
+ output0.set_lane<3>(255);
+ output1.set_lane<3>(255);
+}
+
+/**
+ * @brief Unpack an LDR RGBA color that uses direct encoding.
+ *
+ * @param input0 The packed endpoint 0 color.
+ * @param input1 The packed endpoint 1 color.
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void rgba_unpack(
+ vint4 input0,
+ vint4 input1,
+ vint4& output0,
+ vint4& output1
+) {
+ // Apply blue-uncontraction if needed
+ if (hadd_rgb_s(input0) > hadd_rgb_s(input1))
+ {
+ input0 = uncontract_color(input0);
+ input1 = uncontract_color(input1);
+ std::swap(input0, input1);
+ }
+
+ output0 = input0;
+ output1 = input1;
+}
+
+/**
+ * @brief Unpack an LDR RGB color that uses direct encoding.
+ *
+ * Output alpha set to 255.
+ *
+ * @param input0 The packed endpoint 0 color.
+ * @param input1 The packed endpoint 1 color.
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void rgb_unpack(
+ vint4 input0,
+ vint4 input1,
+ vint4& output0,
+ vint4& output1
+) {
+ rgba_unpack(input0, input1, output0, output1);
+ output0.set_lane<3>(255);
+ output1.set_lane<3>(255);
+}
+
+/**
+ * @brief Unpack an LDR RGBA color that uses scaled encoding.
+ *
+ * Note only the RGB channels use the scaled encoding, alpha uses direct.
+ *
+ * @param input0 The packed endpoint 0 color.
+ * @param alpha1 The packed endpoint 1 alpha value.
+ * @param scale The packed quantized scale.
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void rgb_scale_alpha_unpack(
+ vint4 input0,
+ uint8_t alpha1,
+ uint8_t scale,
+ vint4& output0,
+ vint4& output1
+) {
+ output1 = input0;
+ output1.set_lane<3>(alpha1);
+
+ output0 = asr<8>(input0 * scale);
+ output0.set_lane<3>(input0.lane<3>());
+}
+
+/**
+ * @brief Unpack an LDR RGB color that uses scaled encoding.
+ *
+ * Output alpha is 255.
+ *
+ * @param input0 The packed endpoint 0 color.
+ * @param scale The packed scale.
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void rgb_scale_unpack(
+ vint4 input0,
+ int scale,
+ vint4& output0,
+ vint4& output1
+) {
+ output1 = input0;
+ output1.set_lane<3>(255);
+
+ output0 = asr<8>(input0 * scale);
+ output0.set_lane<3>(255);
+}
+
+/**
+ * @brief Unpack an LDR L color that uses direct encoding.
+ *
+ * Output alpha is 255.
+ *
+ * @param input The packed endpoints.
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void luminance_unpack(
+ const uint8_t input[2],
+ vint4& output0,
+ vint4& output1
+) {
+ int lum0 = input[0];
+ int lum1 = input[1];
+ output0 = vint4(lum0, lum0, lum0, 255);
+ output1 = vint4(lum1, lum1, lum1, 255);
+}
+
+/**
+ * @brief Unpack an LDR L color that uses delta encoding.
+ *
+ * Output alpha is 255.
+ *
+ * @param input The packed endpoints (L0, L1).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void luminance_delta_unpack(
+ const uint8_t input[2],
+ vint4& output0,
+ vint4& output1
+) {
+ int v0 = input[0];
+ int v1 = input[1];
+ int l0 = (v0 >> 2) | (v1 & 0xC0);
+ int l1 = l0 + (v1 & 0x3F);
+
+ l1 = astc::min(l1, 255);
+
+ output0 = vint4(l0, l0, l0, 255);
+ output1 = vint4(l1, l1, l1, 255);
+}
+
+/**
+ * @brief Unpack an LDR LA color that uses direct encoding.
+ *
+ * @param input The packed endpoints (L0, L1, A0, A1).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void luminance_alpha_unpack(
+ const uint8_t input[4],
+ vint4& output0,
+ vint4& output1
+) {
+ int lum0 = input[0];
+ int lum1 = input[1];
+ int alpha0 = input[2];
+ int alpha1 = input[3];
+ output0 = vint4(lum0, lum0, lum0, alpha0);
+ output1 = vint4(lum1, lum1, lum1, alpha1);
+}
+
+/**
+ * @brief Unpack an LDR LA color that uses delta encoding.
+ *
+ * @param input The packed endpoints (L0, L1, A0, A1).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void luminance_alpha_delta_unpack(
+ const uint8_t input[4],
+ vint4& output0,
+ vint4& output1
+) {
+ int lum0 = input[0];
+ int lum1 = input[1];
+ int alpha0 = input[2];
+ int alpha1 = input[3];
+
+ lum0 |= (lum1 & 0x80) << 1;
+ alpha0 |= (alpha1 & 0x80) << 1;
+ lum1 &= 0x7F;
+ alpha1 &= 0x7F;
+
+ if (lum1 & 0x40)
+ {
+ lum1 -= 0x80;
+ }
+
+ if (alpha1 & 0x40)
+ {
+ alpha1 -= 0x80;
+ }
+
+ lum0 >>= 1;
+ lum1 >>= 1;
+ alpha0 >>= 1;
+ alpha1 >>= 1;
+ lum1 += lum0;
+ alpha1 += alpha0;
+
+ lum1 = astc::clamp(lum1, 0, 255);
+ alpha1 = astc::clamp(alpha1, 0, 255);
+
+ output0 = vint4(lum0, lum0, lum0, alpha0);
+ output1 = vint4(lum1, lum1, lum1, alpha1);
+}
+
+/**
+ * @brief Unpack an HDR RGB + offset encoding.
+ *
+ * @param input The packed endpoints (packed and modal).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void hdr_rgbo_unpack(
+ const uint8_t input[4],
+ vint4& output0,
+ vint4& output1
+) {
+ int v0 = input[0];
+ int v1 = input[1];
+ int v2 = input[2];
+ int v3 = input[3];
+
+ int modeval = ((v0 & 0xC0) >> 6) | (((v1 & 0x80) >> 7) << 2) | (((v2 & 0x80) >> 7) << 3);
+
+ int majcomp;
+ int mode;
+ if ((modeval & 0xC) != 0xC)
+ {
+ majcomp = modeval >> 2;
+ mode = modeval & 3;
+ }
+ else if (modeval != 0xF)
+ {
+ majcomp = modeval & 3;
+ mode = 4;
+ }
+ else
+ {
+ majcomp = 0;
+ mode = 5;
+ }
+
+ int red = v0 & 0x3F;
+ int green = v1 & 0x1F;
+ int blue = v2 & 0x1F;
+ int scale = v3 & 0x1F;
+
+ int bit0 = (v1 >> 6) & 1;
+ int bit1 = (v1 >> 5) & 1;
+ int bit2 = (v2 >> 6) & 1;
+ int bit3 = (v2 >> 5) & 1;
+ int bit4 = (v3 >> 7) & 1;
+ int bit5 = (v3 >> 6) & 1;
+ int bit6 = (v3 >> 5) & 1;
+
+ int ohcomp = 1 << mode;
+
+ if (ohcomp & 0x30)
+ green |= bit0 << 6;
+ if (ohcomp & 0x3A)
+ green |= bit1 << 5;
+ if (ohcomp & 0x30)
+ blue |= bit2 << 6;
+ if (ohcomp & 0x3A)
+ blue |= bit3 << 5;
+
+ if (ohcomp & 0x3D)
+ scale |= bit6 << 5;
+ if (ohcomp & 0x2D)
+ scale |= bit5 << 6;
+ if (ohcomp & 0x04)
+ scale |= bit4 << 7;
+
+ if (ohcomp & 0x3B)
+ red |= bit4 << 6;
+ if (ohcomp & 0x04)
+ red |= bit3 << 6;
+
+ if (ohcomp & 0x10)
+ red |= bit5 << 7;
+ if (ohcomp & 0x0F)
+ red |= bit2 << 7;
+
+ if (ohcomp & 0x05)
+ red |= bit1 << 8;
+ if (ohcomp & 0x0A)
+ red |= bit0 << 8;
+
+ if (ohcomp & 0x05)
+ red |= bit0 << 9;
+ if (ohcomp & 0x02)
+ red |= bit6 << 9;
+
+ if (ohcomp & 0x01)
+ red |= bit3 << 10;
+ if (ohcomp & 0x02)
+ red |= bit5 << 10;
+
+ // expand to 12 bits.
+ static const int shamts[6] { 1, 1, 2, 3, 4, 5 };
+ int shamt = shamts[mode];
+ red <<= shamt;
+ green <<= shamt;
+ blue <<= shamt;
+ scale <<= shamt;
+
+ // on modes 0 to 4, the values stored for "green" and "blue" are differentials,
+ // not absolute values.
+ if (mode != 5)
+ {
+ green = red - green;
+ blue = red - blue;
+ }
+
+ // switch around components.
+ int temp;
+ switch (majcomp)
+ {
+ case 1:
+ temp = red;
+ red = green;
+ green = temp;
+ break;
+ case 2:
+ temp = red;
+ red = blue;
+ blue = temp;
+ break;
+ default:
+ break;
+ }
+
+ int red0 = red - scale;
+ int green0 = green - scale;
+ int blue0 = blue - scale;
+
+ // clamp to [0,0xFFF].
+ if (red < 0)
+ red = 0;
+ if (green < 0)
+ green = 0;
+ if (blue < 0)
+ blue = 0;
+
+ if (red0 < 0)
+ red0 = 0;
+ if (green0 < 0)
+ green0 = 0;
+ if (blue0 < 0)
+ blue0 = 0;
+
+ output0 = vint4(red0 << 4, green0 << 4, blue0 << 4, 0x7800);
+ output1 = vint4(red << 4, green << 4, blue << 4, 0x7800);
+}
+
+/**
+ * @brief Unpack an HDR RGB direct encoding.
+ *
+ * @param input The packed endpoints (packed and modal).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void hdr_rgb_unpack(
+ const uint8_t input[6],
+ vint4& output0,
+ vint4& output1
+) {
+
+ int v0 = input[0];
+ int v1 = input[1];
+ int v2 = input[2];
+ int v3 = input[3];
+ int v4 = input[4];
+ int v5 = input[5];
+
+ // extract all the fixed-placement bitfields
+ int modeval = ((v1 & 0x80) >> 7) | (((v2 & 0x80) >> 7) << 1) | (((v3 & 0x80) >> 7) << 2);
+
+ int majcomp = ((v4 & 0x80) >> 7) | (((v5 & 0x80) >> 7) << 1);
+
+ if (majcomp == 3)
+ {
+ output0 = vint4(v0 << 8, v2 << 8, (v4 & 0x7F) << 9, 0x7800);
+ output1 = vint4(v1 << 8, v3 << 8, (v5 & 0x7F) << 9, 0x7800);
+ return;
+ }
+
+ int a = v0 | ((v1 & 0x40) << 2);
+ int b0 = v2 & 0x3f;
+ int b1 = v3 & 0x3f;
+ int c = v1 & 0x3f;
+ int d0 = v4 & 0x7f;
+ int d1 = v5 & 0x7f;
+
+ // get hold of the number of bits in 'd0' and 'd1'
+ static const int dbits_tab[8] { 7, 6, 7, 6, 5, 6, 5, 6 };
+ int dbits = dbits_tab[modeval];
+
+ // extract six variable-placement bits
+ int bit0 = (v2 >> 6) & 1;
+ int bit1 = (v3 >> 6) & 1;
+ int bit2 = (v4 >> 6) & 1;
+ int bit3 = (v5 >> 6) & 1;
+ int bit4 = (v4 >> 5) & 1;
+ int bit5 = (v5 >> 5) & 1;
+
+ // and prepend the variable-placement bits depending on mode.
+ int ohmod = 1 << modeval; // one-hot-mode
+ if (ohmod & 0xA4)
+ a |= bit0 << 9;
+ if (ohmod & 0x8)
+ a |= bit2 << 9;
+ if (ohmod & 0x50)
+ a |= bit4 << 9;
+
+ if (ohmod & 0x50)
+ a |= bit5 << 10;
+ if (ohmod & 0xA0)
+ a |= bit1 << 10;
+
+ if (ohmod & 0xC0)
+ a |= bit2 << 11;
+
+ if (ohmod & 0x4)
+ c |= bit1 << 6;
+ if (ohmod & 0xE8)
+ c |= bit3 << 6;
+
+ if (ohmod & 0x20)
+ c |= bit2 << 7;
+
+ if (ohmod & 0x5B)
+ {
+ b0 |= bit0 << 6;
+ b1 |= bit1 << 6;
+ }
+
+ if (ohmod & 0x12)
+ {
+ b0 |= bit2 << 7;
+ b1 |= bit3 << 7;
+ }
+
+ if (ohmod & 0xAF)
+ {
+ d0 |= bit4 << 5;
+ d1 |= bit5 << 5;
+ }
+
+ if (ohmod & 0x5)
+ {
+ d0 |= bit2 << 6;
+ d1 |= bit3 << 6;
+ }
+
+ // sign-extend 'd0' and 'd1'
+ // note: this code assumes that signed right-shift actually sign-fills, not zero-fills.
+ int32_t d0x = d0;
+ int32_t d1x = d1;
+ int sx_shamt = 32 - dbits;
+ d0x <<= sx_shamt;
+ d0x >>= sx_shamt;
+ d1x <<= sx_shamt;
+ d1x >>= sx_shamt;
+ d0 = d0x;
+ d1 = d1x;
+
+ // expand all values to 12 bits, with left-shift as needed.
+ int val_shamt = (modeval >> 1) ^ 3;
+ a <<= val_shamt;
+ b0 <<= val_shamt;
+ b1 <<= val_shamt;
+ c <<= val_shamt;
+ d0 <<= val_shamt;
+ d1 <<= val_shamt;
+
+ // then compute the actual color values.
+ int red1 = a;
+ int green1 = a - b0;
+ int blue1 = a - b1;
+ int red0 = a - c;
+ int green0 = a - b0 - c - d0;
+ int blue0 = a - b1 - c - d1;
+
+ // clamp the color components to [0,2^12 - 1]
+ red0 = astc::clamp(red0, 0, 4095);
+ green0 = astc::clamp(green0, 0, 4095);
+ blue0 = astc::clamp(blue0, 0, 4095);
+
+ red1 = astc::clamp(red1, 0, 4095);
+ green1 = astc::clamp(green1, 0, 4095);
+ blue1 = astc::clamp(blue1, 0, 4095);
+
+ // switch around the color components
+ int temp0, temp1;
+ switch (majcomp)
+ {
+ case 1: // switch around red and green
+ temp0 = red0;
+ temp1 = red1;
+ red0 = green0;
+ red1 = green1;
+ green0 = temp0;
+ green1 = temp1;
+ break;
+ case 2: // switch around red and blue
+ temp0 = red0;
+ temp1 = red1;
+ red0 = blue0;
+ red1 = blue1;
+ blue0 = temp0;
+ blue1 = temp1;
+ break;
+ case 0: // no switch
+ break;
+ }
+
+ output0 = vint4(red0 << 4, green0 << 4, blue0 << 4, 0x7800);
+ output1 = vint4(red1 << 4, green1 << 4, blue1 << 4, 0x7800);
+}
+
+/**
+ * @brief Unpack an HDR RGB + LDR A direct encoding.
+ *
+ * @param input The packed endpoints (packed and modal).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void hdr_rgb_ldr_alpha_unpack(
+ const uint8_t input[8],
+ vint4& output0,
+ vint4& output1
+) {
+ hdr_rgb_unpack(input, output0, output1);
+
+ int v6 = input[6];
+ int v7 = input[7];
+ output0.set_lane<3>(v6);
+ output1.set_lane<3>(v7);
+}
+
+/**
+ * @brief Unpack an HDR L (small range) direct encoding.
+ *
+ * @param input The packed endpoints (packed and modal).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void hdr_luminance_small_range_unpack(
+ const uint8_t input[2],
+ vint4& output0,
+ vint4& output1
+) {
+ int v0 = input[0];
+ int v1 = input[1];
+
+ int y0, y1;
+ if (v0 & 0x80)
+ {
+ y0 = ((v1 & 0xE0) << 4) | ((v0 & 0x7F) << 2);
+ y1 = (v1 & 0x1F) << 2;
+ }
+ else
+ {
+ y0 = ((v1 & 0xF0) << 4) | ((v0 & 0x7F) << 1);
+ y1 = (v1 & 0xF) << 1;
+ }
+
+ y1 += y0;
+ if (y1 > 0xFFF)
+ {
+ y1 = 0xFFF;
+ }
+
+ output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800);
+ output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800);
+}
+
+/**
+ * @brief Unpack an HDR L (large range) direct encoding.
+ *
+ * @param input The packed endpoints (packed and modal).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void hdr_luminance_large_range_unpack(
+ const uint8_t input[2],
+ vint4& output0,
+ vint4& output1
+) {
+ int v0 = input[0];
+ int v1 = input[1];
+
+ int y0, y1;
+ if (v1 >= v0)
+ {
+ y0 = v0 << 4;
+ y1 = v1 << 4;
+ }
+ else
+ {
+ y0 = (v1 << 4) + 8;
+ y1 = (v0 << 4) - 8;
+ }
+
+ output0 = vint4(y0 << 4, y0 << 4, y0 << 4, 0x7800);
+ output1 = vint4(y1 << 4, y1 << 4, y1 << 4, 0x7800);
+}
+
+/**
+ * @brief Unpack an HDR A direct encoding.
+ *
+ * @param input The packed endpoints (packed and modal).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void hdr_alpha_unpack(
+ const uint8_t input[2],
+ int& output0,
+ int& output1
+) {
+
+ int v6 = input[0];
+ int v7 = input[1];
+
+ int selector = ((v6 >> 7) & 1) | ((v7 >> 6) & 2);
+ v6 &= 0x7F;
+ v7 &= 0x7F;
+ if (selector == 3)
+ {
+ output0 = v6 << 5;
+ output1 = v7 << 5;
+ }
+ else
+ {
+ v6 |= (v7 << (selector + 1)) & 0x780;
+ v7 &= (0x3f >> selector);
+ v7 ^= 32 >> selector;
+ v7 -= 32 >> selector;
+ v6 <<= (4 - selector);
+ v7 <<= (4 - selector);
+ v7 += v6;
+
+ if (v7 < 0)
+ {
+ v7 = 0;
+ }
+ else if (v7 > 0xFFF)
+ {
+ v7 = 0xFFF;
+ }
+
+ output0 = v6;
+ output1 = v7;
+ }
+
+ output0 <<= 4;
+ output1 <<= 4;
+}
+
+/**
+ * @brief Unpack an HDR RGBA direct encoding.
+ *
+ * @param input The packed endpoints (packed and modal).
+ * @param[out] output0 The unpacked endpoint 0 color.
+ * @param[out] output1 The unpacked endpoint 1 color.
+ */
+static void hdr_rgb_hdr_alpha_unpack(
+ const uint8_t input[8],
+ vint4& output0,
+ vint4& output1
+) {
+ hdr_rgb_unpack(input, output0, output1);
+
+ int alpha0, alpha1;
+ hdr_alpha_unpack(input + 6, alpha0, alpha1);
+
+ output0.set_lane<3>(alpha0);
+ output1.set_lane<3>(alpha1);
+}
+
+/* See header for documentation. */
+void unpack_color_endpoints(
+ astcenc_profile decode_mode,
+ int format,
+ const uint8_t* input,
+ bool& rgb_hdr,
+ bool& alpha_hdr,
+ vint4& output0,
+ vint4& output1
+) {
+ // Assume no NaNs and LDR endpoints unless set later
+ rgb_hdr = false;
+ alpha_hdr = false;
+
+ bool alpha_hdr_default = false;
+
+ switch (format)
+ {
+ case FMT_LUMINANCE:
+ luminance_unpack(input, output0, output1);
+ break;
+
+ case FMT_LUMINANCE_DELTA:
+ luminance_delta_unpack(input, output0, output1);
+ break;
+
+ case FMT_HDR_LUMINANCE_SMALL_RANGE:
+ rgb_hdr = true;
+ alpha_hdr_default = true;
+ hdr_luminance_small_range_unpack(input, output0, output1);
+ break;
+
+ case FMT_HDR_LUMINANCE_LARGE_RANGE:
+ rgb_hdr = true;
+ alpha_hdr_default = true;
+ hdr_luminance_large_range_unpack(input, output0, output1);
+ break;
+
+ case FMT_LUMINANCE_ALPHA:
+ luminance_alpha_unpack(input, output0, output1);
+ break;
+
+ case FMT_LUMINANCE_ALPHA_DELTA:
+ luminance_alpha_delta_unpack(input, output0, output1);
+ break;
+
+ case FMT_RGB_SCALE:
+ {
+ vint4 input0q(input[0], input[1], input[2], 0);
+ uint8_t scale = input[3];
+ rgb_scale_unpack(input0q, scale, output0, output1);
+ }
+ break;
+
+ case FMT_RGB_SCALE_ALPHA:
+ {
+ vint4 input0q(input[0], input[1], input[2], input[4]);
+ uint8_t alpha1q = input[5];
+ uint8_t scaleq = input[3];
+ rgb_scale_alpha_unpack(input0q, alpha1q, scaleq, output0, output1);
+ }
+ break;
+
+ case FMT_HDR_RGB_SCALE:
+ rgb_hdr = true;
+ alpha_hdr_default = true;
+ hdr_rgbo_unpack(input, output0, output1);
+ break;
+
+ case FMT_RGB:
+ {
+ vint4 input0q(input[0], input[2], input[4], 0);
+ vint4 input1q(input[1], input[3], input[5], 0);
+ rgb_unpack(input0q, input1q, output0, output1);
+ }
+ break;
+
+ case FMT_RGB_DELTA:
+ {
+ vint4 input0q(input[0], input[2], input[4], 0);
+ vint4 input1q(input[1], input[3], input[5], 0);
+ rgb_delta_unpack(input0q, input1q, output0, output1);
+ }
+ break;
+
+ case FMT_HDR_RGB:
+ rgb_hdr = true;
+ alpha_hdr_default = true;
+ hdr_rgb_unpack(input, output0, output1);
+ break;
+
+ case FMT_RGBA:
+ {
+ vint4 input0q(input[0], input[2], input[4], input[6]);
+ vint4 input1q(input[1], input[3], input[5], input[7]);
+ rgba_unpack(input0q, input1q, output0, output1);
+ }
+ break;
+
+ case FMT_RGBA_DELTA:
+ {
+ vint4 input0q(input[0], input[2], input[4], input[6]);
+ vint4 input1q(input[1], input[3], input[5], input[7]);
+ rgba_delta_unpack(input0q, input1q, output0, output1);
+ }
+ break;
+
+ case FMT_HDR_RGB_LDR_ALPHA:
+ rgb_hdr = true;
+ hdr_rgb_ldr_alpha_unpack(input, output0, output1);
+ break;
+
+ case FMT_HDR_RGBA:
+ rgb_hdr = true;
+ alpha_hdr = true;
+ hdr_rgb_hdr_alpha_unpack(input, output0, output1);
+ break;
+ }
+
+ // Assign a correct default alpha
+ if (alpha_hdr_default)
+ {
+ if (decode_mode == ASTCENC_PRF_HDR)
+ {
+ output0.set_lane<3>(0x7800);
+ output1.set_lane<3>(0x7800);
+ alpha_hdr = true;
+ }
+ else
+ {
+ output0.set_lane<3>(0x00FF);
+ output1.set_lane<3>(0x00FF);
+ alpha_hdr = false;
+ }
+ }
+
+ vint4 ldr_scale(257);
+ vint4 hdr_scale(1);
+ vint4 output_scale = ldr_scale;
+
+ // An LDR profile image
+ if ((decode_mode == ASTCENC_PRF_LDR) ||
+ (decode_mode == ASTCENC_PRF_LDR_SRGB))
+ {
+ // Also matches HDR alpha, as cannot have HDR alpha without HDR RGB
+ if (rgb_hdr == true)
+ {
+ output0 = vint4(0xFF00, 0x0000, 0xFF00, 0xFF00);
+ output1 = vint4(0xFF00, 0x0000, 0xFF00, 0xFF00);
+ output_scale = hdr_scale;
+
+ rgb_hdr = false;
+ alpha_hdr = false;
+ }
+ }
+ // An HDR profile image
+ else
+ {
+ vmask4 hdr_lanes(rgb_hdr, rgb_hdr, rgb_hdr, alpha_hdr);
+ output_scale = select(ldr_scale, hdr_scale, hdr_lanes);
+ }
+
+ output0 = output0 * output_scale;
+ output1 = output1 * output_scale;
+}
diff --git a/thirdparty/astcenc/astcenc_compress_symbolic.cpp b/thirdparty/astcenc/astcenc_compress_symbolic.cpp
new file mode 100644
index 0000000000..afb76246e7
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_compress_symbolic.cpp
@@ -0,0 +1,1455 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Functions to compress a symbolic block.
+ */
+
+#include "astcenc_internal.h"
+#include "astcenc_diagnostic_trace.h"
+
+#include <cassert>
+
+/**
+ * @brief Merge two planes of endpoints into a single vector.
+ *
+ * @param ep_plane1 The endpoints for plane 1.
+ * @param ep_plane2 The endpoints for plane 2.
+ * @param component_plane2 The color component for plane 2.
+ * @param[out] result The merged output.
+ */
+static void merge_endpoints(
+ const endpoints& ep_plane1,
+ const endpoints& ep_plane2,
+ unsigned int component_plane2,
+ endpoints& result
+) {
+ unsigned int partition_count = ep_plane1.partition_count;
+ assert(partition_count == 1);
+
+ vmask4 sep_mask = vint4::lane_id() == vint4(component_plane2);
+
+ result.partition_count = partition_count;
+ result.endpt0[0] = select(ep_plane1.endpt0[0], ep_plane2.endpt0[0], sep_mask);
+ result.endpt1[0] = select(ep_plane1.endpt1[0], ep_plane2.endpt1[0], sep_mask);
+}
+
+/**
+ * @brief Attempt to improve weights given a chosen configuration.
+ *
+ * Given a fixed weight grid decimation and weight value quantization, iterate over all weights (per
+ * partition and per plane) and attempt to improve image quality by moving each weight up by one or
+ * down by one quantization step.
+ *
+ * This is a specialized function which only supports operating on undecimated weight grids,
+ * therefore primarily improving the performance of 4x4 and 5x5 blocks where grid decimation
+ * is needed less often.
+ *
+ * @param decode_mode The decode mode (LDR, HDR).
+ * @param bsd The block size information.
+ * @param blk The image block color data to compress.
+ * @param[out] scb The symbolic compressed block output.
+ */
+static bool realign_weights_undecimated(
+ astcenc_profile decode_mode,
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ symbolic_compressed_block& scb
+) {
+ // Get the partition descriptor
+ unsigned int partition_count = scb.partition_count;
+ const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index);
+
+ // Get the quantization table
+ const block_mode& bm = bsd.get_block_mode(scb.block_mode);
+ unsigned int weight_quant_level = bm.quant_mode;
+ const quant_and_transfer_table& qat = quant_and_xfer_tables[weight_quant_level];
+
+ unsigned int max_plane = bm.is_dual_plane;
+ int plane2_component = scb.plane2_component;
+ vmask4 plane_mask = vint4::lane_id() == vint4(plane2_component);
+
+ // Decode the color endpoints
+ bool rgb_hdr;
+ bool alpha_hdr;
+ vint4 endpnt0[BLOCK_MAX_PARTITIONS];
+ vint4 endpnt1[BLOCK_MAX_PARTITIONS];
+ vfloat4 endpnt0f[BLOCK_MAX_PARTITIONS];
+ vfloat4 offset[BLOCK_MAX_PARTITIONS];
+
+ promise(partition_count > 0);
+
+ for (unsigned int pa_idx = 0; pa_idx < partition_count; pa_idx++)
+ {
+ unpack_color_endpoints(decode_mode,
+ scb.color_formats[pa_idx],
+ scb.color_values[pa_idx],
+ rgb_hdr, alpha_hdr,
+ endpnt0[pa_idx],
+ endpnt1[pa_idx]);
+ }
+
+ uint8_t* dec_weights_uquant = scb.weights;
+ bool adjustments = false;
+
+ // For each plane and partition ...
+ for (unsigned int pl_idx = 0; pl_idx <= max_plane; pl_idx++)
+ {
+ for (unsigned int pa_idx = 0; pa_idx < partition_count; pa_idx++)
+ {
+ // Compute the endpoint delta for all components in current plane
+ vint4 epd = endpnt1[pa_idx] - endpnt0[pa_idx];
+ epd = select(epd, vint4::zero(), plane_mask);
+
+ endpnt0f[pa_idx] = int_to_float(endpnt0[pa_idx]);
+ offset[pa_idx] = int_to_float(epd) * (1.0f / 64.0f);
+ }
+
+ // For each weight compute previous, current, and next errors
+ promise(bsd.texel_count > 0);
+ for (unsigned int texel = 0; texel < bsd.texel_count; texel++)
+ {
+ int uqw = dec_weights_uquant[texel];
+
+ uint32_t prev_and_next = qat.prev_next_values[uqw];
+ int uqw_down = prev_and_next & 0xFF;
+ int uqw_up = (prev_and_next >> 8) & 0xFF;
+
+ // Interpolate the colors to create the diffs
+ float weight_base = static_cast<float>(uqw);
+ float weight_down = static_cast<float>(uqw_down - uqw);
+ float weight_up = static_cast<float>(uqw_up - uqw);
+
+ unsigned int partition = pi.partition_of_texel[texel];
+ vfloat4 color_offset = offset[partition];
+ vfloat4 color_base = endpnt0f[partition];
+
+ vfloat4 color = color_base + color_offset * weight_base;
+ vfloat4 orig_color = blk.texel(texel);
+ vfloat4 error_weight = blk.channel_weight;
+
+ vfloat4 color_diff = color - orig_color;
+ vfloat4 color_diff_down = color_diff + color_offset * weight_down;
+ vfloat4 color_diff_up = color_diff + color_offset * weight_up;
+
+ float error_base = dot_s(color_diff * color_diff, error_weight);
+ float error_down = dot_s(color_diff_down * color_diff_down, error_weight);
+ float error_up = dot_s(color_diff_up * color_diff_up, error_weight);
+
+ // Check if the prev or next error is better, and if so use it
+ if ((error_up < error_base) && (error_up < error_down) && (uqw < 64))
+ {
+ dec_weights_uquant[texel] = static_cast<uint8_t>(uqw_up);
+ adjustments = true;
+ }
+ else if ((error_down < error_base) && (uqw > 0))
+ {
+ dec_weights_uquant[texel] = static_cast<uint8_t>(uqw_down);
+ adjustments = true;
+ }
+ }
+
+ // Prepare iteration for plane 2
+ dec_weights_uquant += WEIGHTS_PLANE2_OFFSET;
+ plane_mask = ~plane_mask;
+ }
+
+ return adjustments;
+}
+
+/**
+ * @brief Attempt to improve weights given a chosen configuration.
+ *
+ * Given a fixed weight grid decimation and weight value quantization, iterate over all weights (per
+ * partition and per plane) and attempt to improve image quality by moving each weight up by one or
+ * down by one quantization step.
+ *
+ * @param decode_mode The decode mode (LDR, HDR).
+ * @param bsd The block size information.
+ * @param blk The image block color data to compress.
+ * @param[out] scb The symbolic compressed block output.
+ */
+static bool realign_weights_decimated(
+ astcenc_profile decode_mode,
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ symbolic_compressed_block& scb
+) {
+ // Get the partition descriptor
+ unsigned int partition_count = scb.partition_count;
+ const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index);
+
+ // Get the quantization table
+ const block_mode& bm = bsd.get_block_mode(scb.block_mode);
+ unsigned int weight_quant_level = bm.quant_mode;
+ const quant_and_transfer_table& qat = quant_and_xfer_tables[weight_quant_level];
+
+ // Get the decimation table
+ const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode);
+ unsigned int weight_count = di.weight_count;
+ assert(weight_count != bsd.texel_count);
+
+ unsigned int max_plane = bm.is_dual_plane;
+ int plane2_component = scb.plane2_component;
+ vmask4 plane_mask = vint4::lane_id() == vint4(plane2_component);
+
+ // Decode the color endpoints
+ bool rgb_hdr;
+ bool alpha_hdr;
+ vint4 endpnt0[BLOCK_MAX_PARTITIONS];
+ vint4 endpnt1[BLOCK_MAX_PARTITIONS];
+ vfloat4 endpnt0f[BLOCK_MAX_PARTITIONS];
+ vfloat4 offset[BLOCK_MAX_PARTITIONS];
+
+ promise(partition_count > 0);
+ promise(weight_count > 0);
+
+ for (unsigned int pa_idx = 0; pa_idx < partition_count; pa_idx++)
+ {
+ unpack_color_endpoints(decode_mode,
+ scb.color_formats[pa_idx],
+ scb.color_values[pa_idx],
+ rgb_hdr, alpha_hdr,
+ endpnt0[pa_idx],
+ endpnt1[pa_idx]);
+ }
+
+ uint8_t* dec_weights_uquant = scb.weights;
+ bool adjustments = false;
+
+ // For each plane and partition ...
+ for (unsigned int pl_idx = 0; pl_idx <= max_plane; pl_idx++)
+ {
+ for (unsigned int pa_idx = 0; pa_idx < partition_count; pa_idx++)
+ {
+ // Compute the endpoint delta for all components in current plane
+ vint4 epd = endpnt1[pa_idx] - endpnt0[pa_idx];
+ epd = select(epd, vint4::zero(), plane_mask);
+
+ endpnt0f[pa_idx] = int_to_float(endpnt0[pa_idx]);
+ offset[pa_idx] = int_to_float(epd) * (1.0f / 64.0f);
+ }
+
+ // Create an unquantized weight grid for this decimation level
+ alignas(ASTCENC_VECALIGN) float uq_weightsf[BLOCK_MAX_WEIGHTS];
+ for (unsigned int we_idx = 0; we_idx < weight_count; we_idx += ASTCENC_SIMD_WIDTH)
+ {
+ vint unquant_value(dec_weights_uquant + we_idx);
+ vfloat unquant_valuef = int_to_float(unquant_value);
+ storea(unquant_valuef, uq_weightsf + we_idx);
+ }
+
+ // For each weight compute previous, current, and next errors
+ for (unsigned int we_idx = 0; we_idx < weight_count; we_idx++)
+ {
+ int uqw = dec_weights_uquant[we_idx];
+ uint32_t prev_and_next = qat.prev_next_values[uqw];
+
+ float uqw_base = uq_weightsf[we_idx];
+ float uqw_down = static_cast<float>(prev_and_next & 0xFF);
+ float uqw_up = static_cast<float>((prev_and_next >> 8) & 0xFF);
+
+ float uqw_diff_down = uqw_down - uqw_base;
+ float uqw_diff_up = uqw_up - uqw_base;
+
+ vfloat4 error_basev = vfloat4::zero();
+ vfloat4 error_downv = vfloat4::zero();
+ vfloat4 error_upv = vfloat4::zero();
+
+ // Interpolate the colors to create the diffs
+ unsigned int texels_to_evaluate = di.weight_texel_count[we_idx];
+ promise(texels_to_evaluate > 0);
+ for (unsigned int te_idx = 0; te_idx < texels_to_evaluate; te_idx++)
+ {
+ unsigned int texel = di.weight_texels_tr[te_idx][we_idx];
+
+ float tw_base = di.texel_contrib_for_weight[te_idx][we_idx];
+
+ float weight_base = (uq_weightsf[di.texel_weights_tr[0][texel]] * di.texel_weight_contribs_float_tr[0][texel]
+ + uq_weightsf[di.texel_weights_tr[1][texel]] * di.texel_weight_contribs_float_tr[1][texel])
+ + (uq_weightsf[di.texel_weights_tr[2][texel]] * di.texel_weight_contribs_float_tr[2][texel]
+ + uq_weightsf[di.texel_weights_tr[3][texel]] * di.texel_weight_contribs_float_tr[3][texel]);
+
+ // Ideally this is integer rounded, but IQ gain it isn't worth the overhead
+ // float weight = astc::flt_rd(weight_base + 0.5f);
+ // float weight_down = astc::flt_rd(weight_base + 0.5f + uqw_diff_down * tw_base) - weight;
+ // float weight_up = astc::flt_rd(weight_base + 0.5f + uqw_diff_up * tw_base) - weight;
+ float weight_down = weight_base + uqw_diff_down * tw_base - weight_base;
+ float weight_up = weight_base + uqw_diff_up * tw_base - weight_base;
+
+ unsigned int partition = pi.partition_of_texel[texel];
+ vfloat4 color_offset = offset[partition];
+ vfloat4 color_base = endpnt0f[partition];
+
+ vfloat4 color = color_base + color_offset * weight_base;
+ vfloat4 orig_color = blk.texel(texel);
+
+ vfloat4 color_diff = color - orig_color;
+ vfloat4 color_down_diff = color_diff + color_offset * weight_down;
+ vfloat4 color_up_diff = color_diff + color_offset * weight_up;
+
+ error_basev += color_diff * color_diff;
+ error_downv += color_down_diff * color_down_diff;
+ error_upv += color_up_diff * color_up_diff;
+ }
+
+ vfloat4 error_weight = blk.channel_weight;
+ float error_base = hadd_s(error_basev * error_weight);
+ float error_down = hadd_s(error_downv * error_weight);
+ float error_up = hadd_s(error_upv * error_weight);
+
+ // Check if the prev or next error is better, and if so use it
+ if ((error_up < error_base) && (error_up < error_down) && (uqw < 64))
+ {
+ uq_weightsf[we_idx] = uqw_up;
+ dec_weights_uquant[we_idx] = static_cast<uint8_t>(uqw_up);
+ adjustments = true;
+ }
+ else if ((error_down < error_base) && (uqw > 0))
+ {
+ uq_weightsf[we_idx] = uqw_down;
+ dec_weights_uquant[we_idx] = static_cast<uint8_t>(uqw_down);
+ adjustments = true;
+ }
+ }
+
+ // Prepare iteration for plane 2
+ dec_weights_uquant += WEIGHTS_PLANE2_OFFSET;
+ plane_mask = ~plane_mask;
+ }
+
+ return adjustments;
+}
+
+/**
+ * @brief Compress a block using a chosen partitioning and 1 plane of weights.
+ *
+ * @param config The compressor configuration.
+ * @param bsd The block size information.
+ * @param blk The image block color data to compress.
+ * @param only_always True if we only use "always" percentile block modes.
+ * @param tune_errorval_threshold The error value threshold.
+ * @param partition_count The partition count.
+ * @param partition_index The partition index if @c partition_count is 2-4.
+ * @param[out] scb The symbolic compressed block output.
+ * @param[out] tmpbuf The quantized weights for plane 1.
+ */
+static float compress_symbolic_block_for_partition_1plane(
+ const astcenc_config& config,
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ bool only_always,
+ float tune_errorval_threshold,
+ unsigned int partition_count,
+ unsigned int partition_index,
+ symbolic_compressed_block& scb,
+ compression_working_buffers& tmpbuf,
+ int quant_limit
+) {
+ promise(partition_count > 0);
+ promise(config.tune_candidate_limit > 0);
+ promise(config.tune_refinement_limit > 0);
+
+ int max_weight_quant = astc::min(static_cast<int>(QUANT_32), quant_limit);
+
+ auto compute_difference = &compute_symbolic_block_difference_1plane;
+ if ((partition_count == 1) && !(config.flags & ASTCENC_FLG_MAP_RGBM))
+ {
+ compute_difference = &compute_symbolic_block_difference_1plane_1partition;
+ }
+
+ const auto& pi = bsd.get_partition_info(partition_count, partition_index);
+
+ // Compute ideal weights and endpoint colors, with no quantization or decimation
+ endpoints_and_weights& ei = tmpbuf.ei1;
+ compute_ideal_colors_and_weights_1plane(blk, pi, ei);
+
+ // Compute ideal weights and endpoint colors for every decimation
+ float* dec_weights_ideal = tmpbuf.dec_weights_ideal;
+ uint8_t* dec_weights_uquant = tmpbuf.dec_weights_uquant;
+
+ // For each decimation mode, compute an ideal set of weights with no quantization
+ unsigned int max_decimation_modes = only_always ? bsd.decimation_mode_count_always
+ : bsd.decimation_mode_count_selected;
+ promise(max_decimation_modes > 0);
+ for (unsigned int i = 0; i < max_decimation_modes; i++)
+ {
+ const auto& dm = bsd.get_decimation_mode(i);
+ if (!dm.is_ref_1_plane(static_cast<quant_method>(max_weight_quant)))
+ {
+ continue;
+ }
+
+ const auto& di = bsd.get_decimation_info(i);
+
+ compute_ideal_weights_for_decimation(
+ ei,
+ di,
+ dec_weights_ideal + i * BLOCK_MAX_WEIGHTS);
+ }
+
+ // Compute maximum colors for the endpoints and ideal weights, then for each endpoint and ideal
+ // weight pair, compute the smallest weight that will result in a color value greater than 1
+ vfloat4 min_ep(10.0f);
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ vfloat4 ep = (vfloat4(1.0f) - ei.ep.endpt0[i]) / (ei.ep.endpt1[i] - ei.ep.endpt0[i]);
+
+ vmask4 use_ep = (ep > vfloat4(0.5f)) & (ep < min_ep);
+ min_ep = select(min_ep, ep, use_ep);
+ }
+
+ float min_wt_cutoff = hmin_s(min_ep);
+
+ // For each mode, use the angular method to compute a shift
+ compute_angular_endpoints_1plane(
+ only_always, bsd, dec_weights_ideal, max_weight_quant, tmpbuf);
+
+ float* weight_low_value = tmpbuf.weight_low_value1;
+ float* weight_high_value = tmpbuf.weight_high_value1;
+ int8_t* qwt_bitcounts = tmpbuf.qwt_bitcounts;
+ float* qwt_errors = tmpbuf.qwt_errors;
+
+ // For each mode (which specifies a decimation and a quantization):
+ // * Compute number of bits needed for the quantized weights
+ // * Generate an optimized set of quantized weights
+ // * Compute quantization errors for the mode
+
+
+ static const int8_t free_bits_for_partition_count[4] {
+ 115 - 4, 111 - 4 - PARTITION_INDEX_BITS, 108 - 4 - PARTITION_INDEX_BITS, 105 - 4 - PARTITION_INDEX_BITS
+ };
+
+ unsigned int max_block_modes = only_always ? bsd.block_mode_count_1plane_always
+ : bsd.block_mode_count_1plane_selected;
+ promise(max_block_modes > 0);
+ for (unsigned int i = 0; i < max_block_modes; i++)
+ {
+ const block_mode& bm = bsd.block_modes[i];
+
+ if (bm.quant_mode > max_weight_quant)
+ {
+ qwt_errors[i] = 1e38f;
+ continue;
+ }
+
+ assert(!bm.is_dual_plane);
+ int bitcount = free_bits_for_partition_count[partition_count - 1] - bm.weight_bits;
+ if (bitcount <= 0)
+ {
+ qwt_errors[i] = 1e38f;
+ continue;
+ }
+
+ if (weight_high_value[i] > 1.02f * min_wt_cutoff)
+ {
+ weight_high_value[i] = 1.0f;
+ }
+
+ int decimation_mode = bm.decimation_mode;
+ const auto& di = bsd.get_decimation_info(decimation_mode);
+
+ qwt_bitcounts[i] = static_cast<int8_t>(bitcount);
+
+ alignas(ASTCENC_VECALIGN) float dec_weights_uquantf[BLOCK_MAX_WEIGHTS];
+
+ // Generate the optimized set of weights for the weight mode
+ compute_quantized_weights_for_decimation(
+ di,
+ weight_low_value[i], weight_high_value[i],
+ dec_weights_ideal + BLOCK_MAX_WEIGHTS * decimation_mode,
+ dec_weights_uquantf,
+ dec_weights_uquant + BLOCK_MAX_WEIGHTS * i,
+ bm.get_weight_quant_mode());
+
+ // Compute weight quantization errors for the block mode
+ qwt_errors[i] = compute_error_of_weight_set_1plane(
+ ei,
+ di,
+ dec_weights_uquantf);
+ }
+
+ // Decide the optimal combination of color endpoint encodings and weight encodings
+ uint8_t partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS];
+ int block_mode_index[TUNE_MAX_TRIAL_CANDIDATES];
+
+ quant_method color_quant_level[TUNE_MAX_TRIAL_CANDIDATES];
+ quant_method color_quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES];
+
+ unsigned int candidate_count = compute_ideal_endpoint_formats(
+ pi, blk, ei.ep, qwt_bitcounts, qwt_errors,
+ config.tune_candidate_limit, 0, max_block_modes,
+ partition_format_specifiers, block_mode_index,
+ color_quant_level, color_quant_level_mod, tmpbuf);
+
+ // Iterate over the N believed-to-be-best modes to find out which one is actually best
+ float best_errorval_in_mode = ERROR_CALC_DEFAULT;
+ float best_errorval_in_scb = scb.errorval;
+
+ for (unsigned int i = 0; i < candidate_count; i++)
+ {
+ TRACE_NODE(node0, "candidate");
+
+ const int bm_packed_index = block_mode_index[i];
+ assert(bm_packed_index >= 0 && bm_packed_index < static_cast<int>(bsd.block_mode_count_1plane_selected));
+ const block_mode& qw_bm = bsd.block_modes[bm_packed_index];
+
+ int decimation_mode = qw_bm.decimation_mode;
+ const auto& di = bsd.get_decimation_info(decimation_mode);
+ promise(di.weight_count > 0);
+
+ trace_add_data("weight_x", di.weight_x);
+ trace_add_data("weight_y", di.weight_y);
+ trace_add_data("weight_z", di.weight_z);
+ trace_add_data("weight_quant", qw_bm.quant_mode);
+
+ // Recompute the ideal color endpoints before storing them
+ vfloat4 rgbs_colors[BLOCK_MAX_PARTITIONS];
+ vfloat4 rgbo_colors[BLOCK_MAX_PARTITIONS];
+
+ symbolic_compressed_block workscb;
+ endpoints workep = ei.ep;
+
+ uint8_t* u8_weight_src = dec_weights_uquant + BLOCK_MAX_WEIGHTS * bm_packed_index;
+
+ for (unsigned int j = 0; j < di.weight_count; j++)
+ {
+ workscb.weights[j] = u8_weight_src[j];
+ }
+
+ for (unsigned int l = 0; l < config.tune_refinement_limit; l++)
+ {
+ recompute_ideal_colors_1plane(
+ blk, pi, di, workscb.weights,
+ workep, rgbs_colors, rgbo_colors);
+
+ // Quantize the chosen color, tracking if worth trying the mod value
+ bool all_same = color_quant_level[i] != color_quant_level_mod[i];
+ for (unsigned int j = 0; j < partition_count; j++)
+ {
+ workscb.color_formats[j] = pack_color_endpoints(
+ workep.endpt0[j],
+ workep.endpt1[j],
+ rgbs_colors[j],
+ rgbo_colors[j],
+ partition_format_specifiers[i][j],
+ workscb.color_values[j],
+ color_quant_level[i]);
+
+ all_same = all_same && workscb.color_formats[j] == workscb.color_formats[0];
+ }
+
+ // If all the color endpoint modes are the same, we get a few more bits to store colors;
+ // let's see if we can take advantage of this: requantize all the colors and see if the
+ // endpoint modes remain the same.
+ workscb.color_formats_matched = 0;
+ if (partition_count >= 2 && all_same)
+ {
+ uint8_t colorvals[BLOCK_MAX_PARTITIONS][12];
+ uint8_t color_formats_mod[BLOCK_MAX_PARTITIONS] { 0 };
+ bool all_same_mod = true;
+ for (unsigned int j = 0; j < partition_count; j++)
+ {
+ color_formats_mod[j] = pack_color_endpoints(
+ workep.endpt0[j],
+ workep.endpt1[j],
+ rgbs_colors[j],
+ rgbo_colors[j],
+ partition_format_specifiers[i][j],
+ colorvals[j],
+ color_quant_level_mod[i]);
+
+ // Early out as soon as it's no longer possible to use mod
+ if (color_formats_mod[j] != color_formats_mod[0])
+ {
+ all_same_mod = false;
+ break;
+ }
+ }
+
+ if (all_same_mod)
+ {
+ workscb.color_formats_matched = 1;
+ for (unsigned int j = 0; j < BLOCK_MAX_PARTITIONS; j++)
+ {
+ for (unsigned int k = 0; k < 8; k++)
+ {
+ workscb.color_values[j][k] = colorvals[j][k];
+ }
+
+ workscb.color_formats[j] = color_formats_mod[j];
+ }
+ }
+ }
+
+ // Store header fields
+ workscb.partition_count = static_cast<uint8_t>(partition_count);
+ workscb.partition_index = static_cast<uint16_t>(partition_index);
+ workscb.plane2_component = -1;
+ workscb.quant_mode = workscb.color_formats_matched ? color_quant_level_mod[i] : color_quant_level[i];
+ workscb.block_mode = qw_bm.mode_index;
+ workscb.block_type = SYM_BTYPE_NONCONST;
+
+ // Pre-realign test
+ if (l == 0)
+ {
+ float errorval = compute_difference(config, bsd, workscb, blk);
+ if (errorval == -ERROR_CALC_DEFAULT)
+ {
+ errorval = -errorval;
+ workscb.block_type = SYM_BTYPE_ERROR;
+ }
+
+ trace_add_data("error_prerealign", errorval);
+ best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);
+
+ // Average refinement improvement is 3.5% per iteration (allow 4.5%), but the first
+ // iteration can help more so we give it a extra 8% leeway. Use this knowledge to
+ // drive a heuristic to skip blocks that are unlikely to catch up with the best
+ // block we have already.
+ unsigned int iters_remaining = config.tune_refinement_limit - l;
+ float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.08f;
+ if (errorval > (threshold * best_errorval_in_scb))
+ {
+ break;
+ }
+
+ if (errorval < best_errorval_in_scb)
+ {
+ best_errorval_in_scb = errorval;
+ workscb.errorval = errorval;
+ scb = workscb;
+
+ if (errorval < tune_errorval_threshold)
+ {
+ // Skip remaining candidates - this is "good enough"
+ i = candidate_count;
+ break;
+ }
+ }
+ }
+
+ bool adjustments;
+ if (di.weight_count != bsd.texel_count)
+ {
+ adjustments = realign_weights_decimated(
+ config.profile, bsd, blk, workscb);
+ }
+ else
+ {
+ adjustments = realign_weights_undecimated(
+ config.profile, bsd, blk, workscb);
+ }
+
+ // Post-realign test
+ float errorval = compute_difference(config, bsd, workscb, blk);
+ if (errorval == -ERROR_CALC_DEFAULT)
+ {
+ errorval = -errorval;
+ workscb.block_type = SYM_BTYPE_ERROR;
+ }
+
+ trace_add_data("error_postrealign", errorval);
+ best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);
+
+ // Average refinement improvement is 3.5% per iteration, so skip blocks that are
+ // unlikely to catch up with the best block we have already. Assume a 4.5% per step to
+ // give benefit of the doubt ...
+ unsigned int iters_remaining = config.tune_refinement_limit - 1 - l;
+ float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.0f;
+ if (errorval > (threshold * best_errorval_in_scb))
+ {
+ break;
+ }
+
+ if (errorval < best_errorval_in_scb)
+ {
+ best_errorval_in_scb = errorval;
+ workscb.errorval = errorval;
+ scb = workscb;
+
+ if (errorval < tune_errorval_threshold)
+ {
+ // Skip remaining candidates - this is "good enough"
+ i = candidate_count;
+ break;
+ }
+ }
+
+ if (!adjustments)
+ {
+ break;
+ }
+ }
+ }
+
+ return best_errorval_in_mode;
+}
+
+/**
+ * @brief Compress a block using a chosen partitioning and 2 planes of weights.
+ *
+ * @param config The compressor configuration.
+ * @param bsd The block size information.
+ * @param blk The image block color data to compress.
+ * @param tune_errorval_threshold The error value threshold.
+ * @param plane2_component The component index for the second plane of weights.
+ * @param[out] scb The symbolic compressed block output.
+ * @param[out] tmpbuf The quantized weights for plane 1.
+ */
+static float compress_symbolic_block_for_partition_2planes(
+ const astcenc_config& config,
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ float tune_errorval_threshold,
+ unsigned int plane2_component,
+ symbolic_compressed_block& scb,
+ compression_working_buffers& tmpbuf,
+ int quant_limit
+) {
+ promise(config.tune_candidate_limit > 0);
+ promise(config.tune_refinement_limit > 0);
+ promise(bsd.decimation_mode_count_selected > 0);
+
+ int max_weight_quant = astc::min(static_cast<int>(QUANT_32), quant_limit);
+
+ // Compute ideal weights and endpoint colors, with no quantization or decimation
+ endpoints_and_weights& ei1 = tmpbuf.ei1;
+ endpoints_and_weights& ei2 = tmpbuf.ei2;
+
+ compute_ideal_colors_and_weights_2planes(bsd, blk, plane2_component, ei1, ei2);
+
+ // Compute ideal weights and endpoint colors for every decimation
+ float* dec_weights_ideal = tmpbuf.dec_weights_ideal;
+ uint8_t* dec_weights_uquant = tmpbuf.dec_weights_uquant;
+
+ // For each decimation mode, compute an ideal set of weights with no quantization
+ for (unsigned int i = 0; i < bsd.decimation_mode_count_selected; i++)
+ {
+ const auto& dm = bsd.get_decimation_mode(i);
+ if (!dm.is_ref_2_plane(static_cast<quant_method>(max_weight_quant)))
+ {
+ continue;
+ }
+
+ const auto& di = bsd.get_decimation_info(i);
+
+ compute_ideal_weights_for_decimation(
+ ei1,
+ di,
+ dec_weights_ideal + i * BLOCK_MAX_WEIGHTS);
+
+ compute_ideal_weights_for_decimation(
+ ei2,
+ di,
+ dec_weights_ideal + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET);
+ }
+
+ // Compute maximum colors for the endpoints and ideal weights, then for each endpoint and ideal
+ // weight pair, compute the smallest weight that will result in a color value greater than 1
+ vfloat4 min_ep1(10.0f);
+ vfloat4 min_ep2(10.0f);
+
+ vfloat4 ep1 = (vfloat4(1.0f) - ei1.ep.endpt0[0]) / (ei1.ep.endpt1[0] - ei1.ep.endpt0[0]);
+ vmask4 use_ep1 = (ep1 > vfloat4(0.5f)) & (ep1 < min_ep1);
+ min_ep1 = select(min_ep1, ep1, use_ep1);
+
+ vfloat4 ep2 = (vfloat4(1.0f) - ei2.ep.endpt0[0]) / (ei2.ep.endpt1[0] - ei2.ep.endpt0[0]);
+ vmask4 use_ep2 = (ep2 > vfloat4(0.5f)) & (ep2 < min_ep2);
+ min_ep2 = select(min_ep2, ep2, use_ep2);
+
+ vfloat4 err_max(ERROR_CALC_DEFAULT);
+ vmask4 err_mask = vint4::lane_id() == vint4(plane2_component);
+
+ // Set the plane2 component to max error in ep1
+ min_ep1 = select(min_ep1, err_max, err_mask);
+
+ float min_wt_cutoff1 = hmin_s(min_ep1);
+
+ // Set the minwt2 to the plane2 component min in ep2
+ float min_wt_cutoff2 = hmin_s(select(err_max, min_ep2, err_mask));
+
+ compute_angular_endpoints_2planes(
+ bsd, dec_weights_ideal, max_weight_quant, tmpbuf);
+
+ // For each mode (which specifies a decimation and a quantization):
+ // * Compute number of bits needed for the quantized weights
+ // * Generate an optimized set of quantized weights
+ // * Compute quantization errors for the mode
+
+ float* weight_low_value1 = tmpbuf.weight_low_value1;
+ float* weight_high_value1 = tmpbuf.weight_high_value1;
+ float* weight_low_value2 = tmpbuf.weight_low_value2;
+ float* weight_high_value2 = tmpbuf.weight_high_value2;
+
+ int8_t* qwt_bitcounts = tmpbuf.qwt_bitcounts;
+ float* qwt_errors = tmpbuf.qwt_errors;
+
+ unsigned int start_2plane = bsd.block_mode_count_1plane_selected;
+ unsigned int end_2plane = bsd.block_mode_count_1plane_2plane_selected;
+
+ for (unsigned int i = start_2plane; i < end_2plane; i++)
+ {
+ const block_mode& bm = bsd.block_modes[i];
+ assert(bm.is_dual_plane);
+
+ if (bm.quant_mode > max_weight_quant)
+ {
+ qwt_errors[i] = 1e38f;
+ continue;
+ }
+
+ qwt_bitcounts[i] = static_cast<int8_t>(109 - bm.weight_bits);
+
+ if (weight_high_value1[i] > 1.02f * min_wt_cutoff1)
+ {
+ weight_high_value1[i] = 1.0f;
+ }
+
+ if (weight_high_value2[i] > 1.02f * min_wt_cutoff2)
+ {
+ weight_high_value2[i] = 1.0f;
+ }
+
+ unsigned int decimation_mode = bm.decimation_mode;
+ const auto& di = bsd.get_decimation_info(decimation_mode);
+
+ alignas(ASTCENC_VECALIGN) float dec_weights_uquantf[BLOCK_MAX_WEIGHTS];
+
+ // Generate the optimized set of weights for the mode
+ compute_quantized_weights_for_decimation(
+ di,
+ weight_low_value1[i],
+ weight_high_value1[i],
+ dec_weights_ideal + BLOCK_MAX_WEIGHTS * decimation_mode,
+ dec_weights_uquantf,
+ dec_weights_uquant + BLOCK_MAX_WEIGHTS * i,
+ bm.get_weight_quant_mode());
+
+ compute_quantized_weights_for_decimation(
+ di,
+ weight_low_value2[i],
+ weight_high_value2[i],
+ dec_weights_ideal + BLOCK_MAX_WEIGHTS * decimation_mode + WEIGHTS_PLANE2_OFFSET,
+ dec_weights_uquantf + WEIGHTS_PLANE2_OFFSET,
+ dec_weights_uquant + BLOCK_MAX_WEIGHTS * i + WEIGHTS_PLANE2_OFFSET,
+ bm.get_weight_quant_mode());
+
+ // Compute weight quantization errors for the block mode
+ qwt_errors[i] = compute_error_of_weight_set_2planes(
+ ei1,
+ ei2,
+ di,
+ dec_weights_uquantf,
+ dec_weights_uquantf + WEIGHTS_PLANE2_OFFSET);
+ }
+
+ // Decide the optimal combination of color endpoint encodings and weight encodings
+ uint8_t partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS];
+ int block_mode_index[TUNE_MAX_TRIAL_CANDIDATES];
+
+ quant_method color_quant_level[TUNE_MAX_TRIAL_CANDIDATES];
+ quant_method color_quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES];
+
+ endpoints epm;
+ merge_endpoints(ei1.ep, ei2.ep, plane2_component, epm);
+
+ const auto& pi = bsd.get_partition_info(1, 0);
+ unsigned int candidate_count = compute_ideal_endpoint_formats(
+ pi, blk, epm, qwt_bitcounts, qwt_errors,
+ config.tune_candidate_limit,
+ bsd.block_mode_count_1plane_selected, bsd.block_mode_count_1plane_2plane_selected,
+ partition_format_specifiers, block_mode_index,
+ color_quant_level, color_quant_level_mod, tmpbuf);
+
+ // Iterate over the N believed-to-be-best modes to find out which one is actually best
+ float best_errorval_in_mode = ERROR_CALC_DEFAULT;
+ float best_errorval_in_scb = scb.errorval;
+
+ for (unsigned int i = 0; i < candidate_count; i++)
+ {
+ TRACE_NODE(node0, "candidate");
+
+ const int bm_packed_index = block_mode_index[i];
+ assert(bm_packed_index >= static_cast<int>(bsd.block_mode_count_1plane_selected) &&
+ bm_packed_index < static_cast<int>(bsd.block_mode_count_1plane_2plane_selected));
+ const block_mode& qw_bm = bsd.block_modes[bm_packed_index];
+
+ int decimation_mode = qw_bm.decimation_mode;
+ const auto& di = bsd.get_decimation_info(decimation_mode);
+ promise(di.weight_count > 0);
+
+ trace_add_data("weight_x", di.weight_x);
+ trace_add_data("weight_y", di.weight_y);
+ trace_add_data("weight_z", di.weight_z);
+ trace_add_data("weight_quant", qw_bm.quant_mode);
+
+ vfloat4 rgbs_color;
+ vfloat4 rgbo_color;
+
+ symbolic_compressed_block workscb;
+ endpoints workep = epm;
+
+ uint8_t* u8_weight1_src = dec_weights_uquant + BLOCK_MAX_WEIGHTS * bm_packed_index;
+ uint8_t* u8_weight2_src = dec_weights_uquant + BLOCK_MAX_WEIGHTS * bm_packed_index + WEIGHTS_PLANE2_OFFSET;
+
+ for (int j = 0; j < di.weight_count; j++)
+ {
+ workscb.weights[j] = u8_weight1_src[j];
+ workscb.weights[j + WEIGHTS_PLANE2_OFFSET] = u8_weight2_src[j];
+ }
+
+ for (unsigned int l = 0; l < config.tune_refinement_limit; l++)
+ {
+ recompute_ideal_colors_2planes(
+ blk, bsd, di,
+ workscb.weights, workscb.weights + WEIGHTS_PLANE2_OFFSET,
+ workep, rgbs_color, rgbo_color, plane2_component);
+
+ // Quantize the chosen color
+ workscb.color_formats[0] = pack_color_endpoints(
+ workep.endpt0[0],
+ workep.endpt1[0],
+ rgbs_color, rgbo_color,
+ partition_format_specifiers[i][0],
+ workscb.color_values[0],
+ color_quant_level[i]);
+
+ // Store header fields
+ workscb.partition_count = 1;
+ workscb.partition_index = 0;
+ workscb.quant_mode = color_quant_level[i];
+ workscb.color_formats_matched = 0;
+ workscb.block_mode = qw_bm.mode_index;
+ workscb.plane2_component = static_cast<int8_t>(plane2_component);
+ workscb.block_type = SYM_BTYPE_NONCONST;
+
+ // Pre-realign test
+ if (l == 0)
+ {
+ float errorval = compute_symbolic_block_difference_2plane(config, bsd, workscb, blk);
+ if (errorval == -ERROR_CALC_DEFAULT)
+ {
+ errorval = -errorval;
+ workscb.block_type = SYM_BTYPE_ERROR;
+ }
+
+ trace_add_data("error_prerealign", errorval);
+ best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);
+
+ // Average refinement improvement is 3.5% per iteration (allow 4.5%), but the first
+ // iteration can help more so we give it a extra 8% leeway. Use this knowledge to
+ // drive a heuristic to skip blocks that are unlikely to catch up with the best
+ // block we have already.
+ unsigned int iters_remaining = config.tune_refinement_limit - l;
+ float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.08f;
+ if (errorval > (threshold * best_errorval_in_scb))
+ {
+ break;
+ }
+
+ if (errorval < best_errorval_in_scb)
+ {
+ best_errorval_in_scb = errorval;
+ workscb.errorval = errorval;
+ scb = workscb;
+
+ if (errorval < tune_errorval_threshold)
+ {
+ // Skip remaining candidates - this is "good enough"
+ i = candidate_count;
+ break;
+ }
+ }
+ }
+
+ // Perform a final pass over the weights to try to improve them.
+ bool adjustments;
+ if (di.weight_count != bsd.texel_count)
+ {
+ adjustments = realign_weights_decimated(
+ config.profile, bsd, blk, workscb);
+ }
+ else
+ {
+ adjustments = realign_weights_undecimated(
+ config.profile, bsd, blk, workscb);
+ }
+
+ // Post-realign test
+ float errorval = compute_symbolic_block_difference_2plane(config, bsd, workscb, blk);
+ if (errorval == -ERROR_CALC_DEFAULT)
+ {
+ errorval = -errorval;
+ workscb.block_type = SYM_BTYPE_ERROR;
+ }
+
+ trace_add_data("error_postrealign", errorval);
+ best_errorval_in_mode = astc::min(errorval, best_errorval_in_mode);
+
+ // Average refinement improvement is 3.5% per iteration, so skip blocks that are
+ // unlikely to catch up with the best block we have already. Assume a 4.5% per step to
+ // give benefit of the doubt ...
+ unsigned int iters_remaining = config.tune_refinement_limit - 1 - l;
+ float threshold = (0.045f * static_cast<float>(iters_remaining)) + 1.0f;
+ if (errorval > (threshold * best_errorval_in_scb))
+ {
+ break;
+ }
+
+ if (errorval < best_errorval_in_scb)
+ {
+ best_errorval_in_scb = errorval;
+ workscb.errorval = errorval;
+ scb = workscb;
+
+ if (errorval < tune_errorval_threshold)
+ {
+ // Skip remaining candidates - this is "good enough"
+ i = candidate_count;
+ break;
+ }
+ }
+
+ if (!adjustments)
+ {
+ break;
+ }
+ }
+ }
+
+ return best_errorval_in_mode;
+}
+
+/**
+ * @brief Determine the lowest cross-channel correlation factor.
+ *
+ * @param texels_per_block The number of texels in a block.
+ * @param blk The image block color data to compress.
+ *
+ * @return Return the lowest correlation factor.
+ */
+static float prepare_block_statistics(
+ int texels_per_block,
+ const image_block& blk
+) {
+ // Compute covariance matrix, as a collection of 10 scalars that form the upper-triangular row
+ // of the matrix. The matrix is symmetric, so this is all we need for this use case.
+ float rs = 0.0f;
+ float gs = 0.0f;
+ float bs = 0.0f;
+ float as = 0.0f;
+ float rr_var = 0.0f;
+ float gg_var = 0.0f;
+ float bb_var = 0.0f;
+ float aa_var = 0.0f;
+ float rg_cov = 0.0f;
+ float rb_cov = 0.0f;
+ float ra_cov = 0.0f;
+ float gb_cov = 0.0f;
+ float ga_cov = 0.0f;
+ float ba_cov = 0.0f;
+
+ float weight_sum = 0.0f;
+
+ promise(texels_per_block > 0);
+ for (int i = 0; i < texels_per_block; i++)
+ {
+ float weight = hadd_s(blk.channel_weight) / 4.0f;
+ assert(weight >= 0.0f);
+ weight_sum += weight;
+
+ float r = blk.data_r[i];
+ float g = blk.data_g[i];
+ float b = blk.data_b[i];
+ float a = blk.data_a[i];
+
+ float rw = r * weight;
+ rs += rw;
+ rr_var += r * rw;
+ rg_cov += g * rw;
+ rb_cov += b * rw;
+ ra_cov += a * rw;
+
+ float gw = g * weight;
+ gs += gw;
+ gg_var += g * gw;
+ gb_cov += b * gw;
+ ga_cov += a * gw;
+
+ float bw = b * weight;
+ bs += bw;
+ bb_var += b * bw;
+ ba_cov += a * bw;
+
+ float aw = a * weight;
+ as += aw;
+ aa_var += a * aw;
+ }
+
+ float rpt = 1.0f / astc::max(weight_sum, 1e-7f);
+
+ rr_var -= rs * (rs * rpt);
+ rg_cov -= gs * (rs * rpt);
+ rb_cov -= bs * (rs * rpt);
+ ra_cov -= as * (rs * rpt);
+
+ gg_var -= gs * (gs * rpt);
+ gb_cov -= bs * (gs * rpt);
+ ga_cov -= as * (gs * rpt);
+
+ bb_var -= bs * (bs * rpt);
+ ba_cov -= as * (bs * rpt);
+
+ aa_var -= as * (as * rpt);
+
+ // These will give a NaN if a channel is constant - these are fixed up in the next step
+ rg_cov *= astc::rsqrt(rr_var * gg_var);
+ rb_cov *= astc::rsqrt(rr_var * bb_var);
+ ra_cov *= astc::rsqrt(rr_var * aa_var);
+ gb_cov *= astc::rsqrt(gg_var * bb_var);
+ ga_cov *= astc::rsqrt(gg_var * aa_var);
+ ba_cov *= astc::rsqrt(bb_var * aa_var);
+
+ if (astc::isnan(rg_cov)) rg_cov = 1.0f;
+ if (astc::isnan(rb_cov)) rb_cov = 1.0f;
+ if (astc::isnan(ra_cov)) ra_cov = 1.0f;
+ if (astc::isnan(gb_cov)) gb_cov = 1.0f;
+ if (astc::isnan(ga_cov)) ga_cov = 1.0f;
+ if (astc::isnan(ba_cov)) ba_cov = 1.0f;
+
+ float lowest_correlation = astc::min(fabsf(rg_cov), fabsf(rb_cov));
+ lowest_correlation = astc::min(lowest_correlation, fabsf(ra_cov));
+ lowest_correlation = astc::min(lowest_correlation, fabsf(gb_cov));
+ lowest_correlation = astc::min(lowest_correlation, fabsf(ga_cov));
+ lowest_correlation = astc::min(lowest_correlation, fabsf(ba_cov));
+
+ // Diagnostic trace points
+ trace_add_data("min_r", blk.data_min.lane<0>());
+ trace_add_data("max_r", blk.data_max.lane<0>());
+ trace_add_data("min_g", blk.data_min.lane<1>());
+ trace_add_data("max_g", blk.data_max.lane<1>());
+ trace_add_data("min_b", blk.data_min.lane<2>());
+ trace_add_data("max_b", blk.data_max.lane<2>());
+ trace_add_data("min_a", blk.data_min.lane<3>());
+ trace_add_data("max_a", blk.data_max.lane<3>());
+ trace_add_data("cov_rg", fabsf(rg_cov));
+ trace_add_data("cov_rb", fabsf(rb_cov));
+ trace_add_data("cov_ra", fabsf(ra_cov));
+ trace_add_data("cov_gb", fabsf(gb_cov));
+ trace_add_data("cov_ga", fabsf(ga_cov));
+ trace_add_data("cov_ba", fabsf(ba_cov));
+
+ return lowest_correlation;
+}
+
+/* See header for documentation. */
+void compress_block(
+ const astcenc_contexti& ctx,
+ const image_block& blk,
+ physical_compressed_block& pcb,
+ compression_working_buffers& tmpbuf)
+{
+ astcenc_profile decode_mode = ctx.config.profile;
+ symbolic_compressed_block scb;
+ const block_size_descriptor& bsd = *ctx.bsd;
+ float lowest_correl;
+
+ TRACE_NODE(node0, "block");
+ trace_add_data("pos_x", blk.xpos);
+ trace_add_data("pos_y", blk.ypos);
+ trace_add_data("pos_z", blk.zpos);
+
+ // Set stricter block targets for luminance data as we have more bits to play with
+ bool block_is_l = blk.is_luminance();
+ float block_is_l_scale = block_is_l ? 1.0f / 1.5f : 1.0f;
+
+ // Set slightly stricter block targets for lumalpha data as we have more bits to play with
+ bool block_is_la = blk.is_luminancealpha();
+ float block_is_la_scale = block_is_la ? 1.0f / 1.05f : 1.0f;
+
+ bool block_skip_two_plane = false;
+ int max_partitions = ctx.config.tune_partition_count_limit;
+
+ unsigned int requested_partition_indices[3] {
+ ctx.config.tune_2partition_index_limit,
+ ctx.config.tune_3partition_index_limit,
+ ctx.config.tune_4partition_index_limit
+ };
+
+ unsigned int requested_partition_trials[3] {
+ ctx.config.tune_2partitioning_candidate_limit,
+ ctx.config.tune_3partitioning_candidate_limit,
+ ctx.config.tune_4partitioning_candidate_limit
+ };
+
+#if defined(ASTCENC_DIAGNOSTICS)
+ // Do this early in diagnostic builds so we can dump uniform metrics
+ // for every block. Do it later in release builds to avoid redundant work!
+ float error_weight_sum = hadd_s(blk.channel_weight) * bsd.texel_count;
+ float error_threshold = ctx.config.tune_db_limit
+ * error_weight_sum
+ * block_is_l_scale
+ * block_is_la_scale;
+
+ lowest_correl = prepare_block_statistics(bsd.texel_count, blk);
+ trace_add_data("lowest_correl", lowest_correl);
+ trace_add_data("tune_error_threshold", error_threshold);
+#endif
+
+ // Detected a constant-color block
+ if (all(blk.data_min == blk.data_max))
+ {
+ TRACE_NODE(node1, "pass");
+ trace_add_data("partition_count", 0);
+ trace_add_data("plane_count", 1);
+
+ scb.partition_count = 0;
+
+ // Encode as FP16 if using HDR
+ if ((decode_mode == ASTCENC_PRF_HDR) ||
+ (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A))
+ {
+ scb.block_type = SYM_BTYPE_CONST_F16;
+ vint4 color_f16 = float_to_float16(blk.origin_texel);
+ store(color_f16, scb.constant_color);
+ }
+ // Encode as UNORM16 if NOT using HDR
+ else
+ {
+ scb.block_type = SYM_BTYPE_CONST_U16;
+ vfloat4 color_f32 = clamp(0.0f, 1.0f, blk.origin_texel) * 65535.0f;
+ vint4 color_u16 = float_to_int_rtn(color_f32);
+ store(color_u16, scb.constant_color);
+ }
+
+ trace_add_data("exit", "quality hit");
+
+ symbolic_to_physical(bsd, scb, pcb);
+ return;
+ }
+
+#if !defined(ASTCENC_DIAGNOSTICS)
+ float error_weight_sum = hadd_s(blk.channel_weight) * bsd.texel_count;
+ float error_threshold = ctx.config.tune_db_limit
+ * error_weight_sum
+ * block_is_l_scale
+ * block_is_la_scale;
+#endif
+
+ // Set SCB and mode errors to a very high error value
+ scb.errorval = ERROR_CALC_DEFAULT;
+ scb.block_type = SYM_BTYPE_ERROR;
+
+ float best_errorvals_for_pcount[BLOCK_MAX_PARTITIONS] {
+ ERROR_CALC_DEFAULT, ERROR_CALC_DEFAULT, ERROR_CALC_DEFAULT, ERROR_CALC_DEFAULT
+ };
+
+ float exit_thresholds_for_pcount[BLOCK_MAX_PARTITIONS] {
+ 0.0f,
+ ctx.config.tune_2_partition_early_out_limit_factor,
+ ctx.config.tune_3_partition_early_out_limit_factor,
+ 0.0f
+ };
+
+ // Trial using 1 plane of weights and 1 partition.
+
+ // Most of the time we test it twice, first with a mode cutoff of 0 and then with the specified
+ // mode cutoff. This causes an early-out that speeds up encoding of easy blocks. However, this
+ // optimization is disabled for 4x4 and 5x4 blocks where it nearly always slows down the
+ // compression and slightly reduces image quality.
+
+ float errorval_mult[2] {
+ 1.0f / ctx.config.tune_mse_overshoot,
+ 1.0f
+ };
+
+ static const float errorval_overshoot = 1.0f / ctx.config.tune_mse_overshoot;
+
+ // Only enable MODE0 fast path (trial 0) if 2D, and more than 25 texels
+ int start_trial = 1;
+ if ((bsd.texel_count >= TUNE_MIN_TEXELS_MODE0_FASTPATH) && (bsd.zdim == 1))
+ {
+ start_trial = 0;
+ }
+
+ int quant_limit = QUANT_32;
+ for (int i = start_trial; i < 2; i++)
+ {
+ TRACE_NODE(node1, "pass");
+ trace_add_data("partition_count", 1);
+ trace_add_data("plane_count", 1);
+ trace_add_data("search_mode", i);
+
+ float errorval = compress_symbolic_block_for_partition_1plane(
+ ctx.config, bsd, blk, i == 0,
+ error_threshold * errorval_mult[i] * errorval_overshoot,
+ 1, 0, scb, tmpbuf, QUANT_32);
+
+ // Record the quant level so we can use the filter later searches
+ const auto& bm = bsd.get_block_mode(scb.block_mode);
+ quant_limit = bm.get_weight_quant_mode();
+
+ best_errorvals_for_pcount[0] = astc::min(best_errorvals_for_pcount[0], errorval);
+ if (errorval < (error_threshold * errorval_mult[i]))
+ {
+ trace_add_data("exit", "quality hit");
+ goto END_OF_TESTS;
+ }
+ }
+
+#if !defined(ASTCENC_DIAGNOSTICS)
+ lowest_correl = prepare_block_statistics(bsd.texel_count, blk);
+#endif
+
+ block_skip_two_plane = lowest_correl > ctx.config.tune_2_plane_early_out_limit_correlation;
+
+ // Test the four possible 1-partition, 2-planes modes. Do this in reverse, as
+ // alpha is the most likely to be non-correlated if it is present in the data.
+ for (int i = BLOCK_MAX_COMPONENTS - 1; i >= 0; i--)
+ {
+ TRACE_NODE(node1, "pass");
+ trace_add_data("partition_count", 1);
+ trace_add_data("plane_count", 2);
+ trace_add_data("plane_component", i);
+
+ if (block_skip_two_plane)
+ {
+ trace_add_data("skip", "tune_2_plane_early_out_limit_correlation");
+ continue;
+ }
+
+ if (blk.grayscale && i != 3)
+ {
+ trace_add_data("skip", "grayscale block");
+ continue;
+ }
+
+ if (blk.is_constant_channel(i))
+ {
+ trace_add_data("skip", "constant component");
+ continue;
+ }
+
+ float errorval = compress_symbolic_block_for_partition_2planes(
+ ctx.config, bsd, blk, error_threshold * errorval_overshoot,
+ i, scb, tmpbuf, quant_limit);
+
+ // If attempting two planes is much worse than the best one plane result
+ // then further two plane searches are unlikely to help so move on ...
+ if (errorval > (best_errorvals_for_pcount[0] * 1.85f))
+ {
+ break;
+ }
+
+ if (errorval < error_threshold)
+ {
+ trace_add_data("exit", "quality hit");
+ goto END_OF_TESTS;
+ }
+ }
+
+ // Find best blocks for 2, 3 and 4 partitions
+ for (int partition_count = 2; partition_count <= max_partitions; partition_count++)
+ {
+ unsigned int partition_indices[TUNE_MAX_PARTITIONING_CANDIDATES];
+
+ unsigned int requested_indices = requested_partition_indices[partition_count - 2];
+
+ unsigned int requested_trials = requested_partition_trials[partition_count - 2];
+ requested_trials = astc::min(requested_trials, requested_indices);
+
+ unsigned int actual_trials = find_best_partition_candidates(
+ bsd, blk, partition_count, requested_indices, partition_indices, requested_trials);
+
+ float best_error_in_prev = best_errorvals_for_pcount[partition_count - 2];
+
+ for (unsigned int i = 0; i < actual_trials; i++)
+ {
+ TRACE_NODE(node1, "pass");
+ trace_add_data("partition_count", partition_count);
+ trace_add_data("partition_index", partition_indices[i]);
+ trace_add_data("plane_count", 1);
+ trace_add_data("search_mode", i);
+
+ float errorval = compress_symbolic_block_for_partition_1plane(
+ ctx.config, bsd, blk, false,
+ error_threshold * errorval_overshoot,
+ partition_count, partition_indices[i],
+ scb, tmpbuf, quant_limit);
+
+ best_errorvals_for_pcount[partition_count - 1] = astc::min(best_errorvals_for_pcount[partition_count - 1], errorval);
+
+ // If using N partitions doesn't improve much over using N-1 partitions then skip trying
+ // N+1. Error can dramatically improve if the data is correlated or non-correlated and
+ // aligns with a partitioning that suits that encoding, so for this inner loop check add
+ // a large error scale because the "other" trial could be a lot better.
+ float best_error = best_errorvals_for_pcount[partition_count - 1];
+ float best_error_scale = exit_thresholds_for_pcount[partition_count - 1] * 1.85f;
+ if (best_error > (best_error_in_prev * best_error_scale))
+ {
+ trace_add_data("skip", "tune_partition_early_out_limit_factor");
+ goto END_OF_TESTS;
+ }
+
+ if (errorval < error_threshold)
+ {
+ trace_add_data("exit", "quality hit");
+ goto END_OF_TESTS;
+ }
+ }
+
+ // If using N partitions doesn't improve much over using N-1 partitions then skip trying N+1
+ float best_error = best_errorvals_for_pcount[partition_count - 1];
+ float best_error_scale = exit_thresholds_for_pcount[partition_count - 1];
+ if (best_error > (best_error_in_prev * best_error_scale))
+ {
+ trace_add_data("skip", "tune_partition_early_out_limit_factor");
+ goto END_OF_TESTS;
+ }
+ }
+
+ trace_add_data("exit", "quality not hit");
+
+END_OF_TESTS:
+ // If we still have an error block then convert to something we can encode
+ // TODO: Do something more sensible here, such as average color block
+ if (scb.block_type == SYM_BTYPE_ERROR)
+ {
+#if defined(ASTCENC_DIAGNOSTICS)
+ static bool printed_once = false;
+ if (!printed_once)
+ {
+ printed_once = true;
+ printf("WARN: At least one block failed to find a valid encoding.\n"
+ " Try increasing compression quality settings.\n\n");
+ }
+#endif
+
+ scb.block_type = SYM_BTYPE_CONST_U16;
+ vfloat4 color_f32 = clamp(0.0f, 1.0f, blk.origin_texel) * 65535.0f;
+ vint4 color_u16 = float_to_int_rtn(color_f32);
+ store(color_u16, scb.constant_color);
+ }
+
+ // Compress to a physical block
+ symbolic_to_physical(bsd, scb, pcb);
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_compute_variance.cpp b/thirdparty/astcenc/astcenc_compute_variance.cpp
new file mode 100644
index 0000000000..48a4af8cef
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_compute_variance.cpp
@@ -0,0 +1,472 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Functions to calculate variance per component in a NxN footprint.
+ *
+ * We need N to be parametric, so the routine below uses summed area tables in order to execute in
+ * O(1) time independent of how big N is.
+ *
+ * The addition uses a Brent-Kung-based parallel prefix adder. This uses the prefix tree to first
+ * perform a binary reduction, and then distributes the results. This method means that there is no
+ * serial dependency between a given element and the next one, and also significantly improves
+ * numerical stability allowing us to use floats rather than doubles.
+ */
+
+#include "astcenc_internal.h"
+
+#include <cassert>
+
+/**
+ * @brief Generate a prefix-sum array using the Brent-Kung algorithm.
+ *
+ * This will take an input array of the form:
+ * v0, v1, v2, ...
+ * ... and modify in-place to turn it into a prefix-sum array of the form:
+ * v0, v0+v1, v0+v1+v2, ...
+ *
+ * @param d The array to prefix-sum.
+ * @param items The number of items in the array.
+ * @param stride The item spacing in the array; i.e. dense arrays should use 1.
+ */
+static void brent_kung_prefix_sum(
+ vfloat4* d,
+ size_t items,
+ int stride
+) {
+ if (items < 2)
+ return;
+
+ size_t lc_stride = 2;
+ size_t log2_stride = 1;
+
+ // The reduction-tree loop
+ do {
+ size_t step = lc_stride >> 1;
+ size_t start = lc_stride - 1;
+ size_t iters = items >> log2_stride;
+
+ vfloat4 *da = d + (start * stride);
+ ptrdiff_t ofs = -static_cast<ptrdiff_t>(step * stride);
+ size_t ofs_stride = stride << log2_stride;
+
+ while (iters)
+ {
+ *da = *da + da[ofs];
+ da += ofs_stride;
+ iters--;
+ }
+
+ log2_stride += 1;
+ lc_stride <<= 1;
+ } while (lc_stride <= items);
+
+ // The expansion-tree loop
+ do {
+ log2_stride -= 1;
+ lc_stride >>= 1;
+
+ size_t step = lc_stride >> 1;
+ size_t start = step + lc_stride - 1;
+ size_t iters = (items - step) >> log2_stride;
+
+ vfloat4 *da = d + (start * stride);
+ ptrdiff_t ofs = -static_cast<ptrdiff_t>(step * stride);
+ size_t ofs_stride = stride << log2_stride;
+
+ while (iters)
+ {
+ *da = *da + da[ofs];
+ da += ofs_stride;
+ iters--;
+ }
+ } while (lc_stride > 2);
+}
+
+/* See header for documentation. */
+void compute_pixel_region_variance(
+ astcenc_contexti& ctx,
+ const pixel_region_args& arg
+) {
+ // Unpack the memory structure into local variables
+ const astcenc_image* img = arg.img;
+ astcenc_swizzle swz = arg.swz;
+ bool have_z = arg.have_z;
+
+ int size_x = arg.size_x;
+ int size_y = arg.size_y;
+ int size_z = arg.size_z;
+
+ int offset_x = arg.offset_x;
+ int offset_y = arg.offset_y;
+ int offset_z = arg.offset_z;
+
+ int alpha_kernel_radius = arg.alpha_kernel_radius;
+
+ float* input_alpha_averages = ctx.input_alpha_averages;
+ vfloat4* work_memory = arg.work_memory;
+
+ // Compute memory sizes and dimensions that we need
+ int kernel_radius = alpha_kernel_radius;
+ int kerneldim = 2 * kernel_radius + 1;
+ int kernel_radius_xy = kernel_radius;
+ int kernel_radius_z = have_z ? kernel_radius : 0;
+
+ int padsize_x = size_x + kerneldim;
+ int padsize_y = size_y + kerneldim;
+ int padsize_z = size_z + (have_z ? kerneldim : 0);
+ int sizeprod = padsize_x * padsize_y * padsize_z;
+
+ int zd_start = have_z ? 1 : 0;
+
+ vfloat4 *varbuf1 = work_memory;
+ vfloat4 *varbuf2 = work_memory + sizeprod;
+
+ // Scaling factors to apply to Y and Z for accesses into the work buffers
+ int yst = padsize_x;
+ int zst = padsize_x * padsize_y;
+
+ // Scaling factors to apply to Y and Z for accesses into result buffers
+ int ydt = img->dim_x;
+ int zdt = img->dim_x * img->dim_y;
+
+ // Macros to act as accessor functions for the work-memory
+ #define VARBUF1(z, y, x) varbuf1[z * zst + y * yst + x]
+ #define VARBUF2(z, y, x) varbuf2[z * zst + y * yst + x]
+
+ // Load N and N^2 values into the work buffers
+ if (img->data_type == ASTCENC_TYPE_U8)
+ {
+ // Swizzle data structure 4 = ZERO, 5 = ONE
+ uint8_t data[6];
+ data[ASTCENC_SWZ_0] = 0;
+ data[ASTCENC_SWZ_1] = 255;
+
+ for (int z = zd_start; z < padsize_z; z++)
+ {
+ int z_src = (z - zd_start) + offset_z - kernel_radius_z;
+ z_src = astc::clamp(z_src, 0, static_cast<int>(img->dim_z - 1));
+ uint8_t* data8 = static_cast<uint8_t*>(img->data[z_src]);
+
+ for (int y = 1; y < padsize_y; y++)
+ {
+ int y_src = (y - 1) + offset_y - kernel_radius_xy;
+ y_src = astc::clamp(y_src, 0, static_cast<int>(img->dim_y - 1));
+
+ for (int x = 1; x < padsize_x; x++)
+ {
+ int x_src = (x - 1) + offset_x - kernel_radius_xy;
+ x_src = astc::clamp(x_src, 0, static_cast<int>(img->dim_x - 1));
+
+ data[0] = data8[(4 * img->dim_x * y_src) + (4 * x_src )];
+ data[1] = data8[(4 * img->dim_x * y_src) + (4 * x_src + 1)];
+ data[2] = data8[(4 * img->dim_x * y_src) + (4 * x_src + 2)];
+ data[3] = data8[(4 * img->dim_x * y_src) + (4 * x_src + 3)];
+
+ uint8_t r = data[swz.r];
+ uint8_t g = data[swz.g];
+ uint8_t b = data[swz.b];
+ uint8_t a = data[swz.a];
+
+ vfloat4 d = vfloat4 (r * (1.0f / 255.0f),
+ g * (1.0f / 255.0f),
+ b * (1.0f / 255.0f),
+ a * (1.0f / 255.0f));
+
+ VARBUF1(z, y, x) = d;
+ VARBUF2(z, y, x) = d * d;
+ }
+ }
+ }
+ }
+ else if (img->data_type == ASTCENC_TYPE_F16)
+ {
+ // Swizzle data structure 4 = ZERO, 5 = ONE (in FP16)
+ uint16_t data[6];
+ data[ASTCENC_SWZ_0] = 0;
+ data[ASTCENC_SWZ_1] = 0x3C00;
+
+ for (int z = zd_start; z < padsize_z; z++)
+ {
+ int z_src = (z - zd_start) + offset_z - kernel_radius_z;
+ z_src = astc::clamp(z_src, 0, static_cast<int>(img->dim_z - 1));
+ uint16_t* data16 = static_cast<uint16_t*>(img->data[z_src]);
+
+ for (int y = 1; y < padsize_y; y++)
+ {
+ int y_src = (y - 1) + offset_y - kernel_radius_xy;
+ y_src = astc::clamp(y_src, 0, static_cast<int>(img->dim_y - 1));
+
+ for (int x = 1; x < padsize_x; x++)
+ {
+ int x_src = (x - 1) + offset_x - kernel_radius_xy;
+ x_src = astc::clamp(x_src, 0, static_cast<int>(img->dim_x - 1));
+
+ data[0] = data16[(4 * img->dim_x * y_src) + (4 * x_src )];
+ data[1] = data16[(4 * img->dim_x * y_src) + (4 * x_src + 1)];
+ data[2] = data16[(4 * img->dim_x * y_src) + (4 * x_src + 2)];
+ data[3] = data16[(4 * img->dim_x * y_src) + (4 * x_src + 3)];
+
+ vint4 di(data[swz.r], data[swz.g], data[swz.b], data[swz.a]);
+ vfloat4 d = float16_to_float(di);
+
+ VARBUF1(z, y, x) = d;
+ VARBUF2(z, y, x) = d * d;
+ }
+ }
+ }
+ }
+ else // if (img->data_type == ASTCENC_TYPE_F32)
+ {
+ assert(img->data_type == ASTCENC_TYPE_F32);
+
+ // Swizzle data structure 4 = ZERO, 5 = ONE (in FP16)
+ float data[6];
+ data[ASTCENC_SWZ_0] = 0.0f;
+ data[ASTCENC_SWZ_1] = 1.0f;
+
+ for (int z = zd_start; z < padsize_z; z++)
+ {
+ int z_src = (z - zd_start) + offset_z - kernel_radius_z;
+ z_src = astc::clamp(z_src, 0, static_cast<int>(img->dim_z - 1));
+ float* data32 = static_cast<float*>(img->data[z_src]);
+
+ for (int y = 1; y < padsize_y; y++)
+ {
+ int y_src = (y - 1) + offset_y - kernel_radius_xy;
+ y_src = astc::clamp(y_src, 0, static_cast<int>(img->dim_y - 1));
+
+ for (int x = 1; x < padsize_x; x++)
+ {
+ int x_src = (x - 1) + offset_x - kernel_radius_xy;
+ x_src = astc::clamp(x_src, 0, static_cast<int>(img->dim_x - 1));
+
+ data[0] = data32[(4 * img->dim_x * y_src) + (4 * x_src )];
+ data[1] = data32[(4 * img->dim_x * y_src) + (4 * x_src + 1)];
+ data[2] = data32[(4 * img->dim_x * y_src) + (4 * x_src + 2)];
+ data[3] = data32[(4 * img->dim_x * y_src) + (4 * x_src + 3)];
+
+ float r = data[swz.r];
+ float g = data[swz.g];
+ float b = data[swz.b];
+ float a = data[swz.a];
+
+ vfloat4 d(r, g, b, a);
+
+ VARBUF1(z, y, x) = d;
+ VARBUF2(z, y, x) = d * d;
+ }
+ }
+ }
+ }
+
+ // Pad with an extra layer of 0s; this forms the edge of the SAT tables
+ vfloat4 vbz = vfloat4::zero();
+ for (int z = 0; z < padsize_z; z++)
+ {
+ for (int y = 0; y < padsize_y; y++)
+ {
+ VARBUF1(z, y, 0) = vbz;
+ VARBUF2(z, y, 0) = vbz;
+ }
+
+ for (int x = 0; x < padsize_x; x++)
+ {
+ VARBUF1(z, 0, x) = vbz;
+ VARBUF2(z, 0, x) = vbz;
+ }
+ }
+
+ if (have_z)
+ {
+ for (int y = 0; y < padsize_y; y++)
+ {
+ for (int x = 0; x < padsize_x; x++)
+ {
+ VARBUF1(0, y, x) = vbz;
+ VARBUF2(0, y, x) = vbz;
+ }
+ }
+ }
+
+ // Generate summed-area tables for N and N^2; this is done in-place, using
+ // a Brent-Kung parallel-prefix based algorithm to minimize precision loss
+ for (int z = zd_start; z < padsize_z; z++)
+ {
+ for (int y = 1; y < padsize_y; y++)
+ {
+ brent_kung_prefix_sum(&(VARBUF1(z, y, 1)), padsize_x - 1, 1);
+ brent_kung_prefix_sum(&(VARBUF2(z, y, 1)), padsize_x - 1, 1);
+ }
+ }
+
+ for (int z = zd_start; z < padsize_z; z++)
+ {
+ for (int x = 1; x < padsize_x; x++)
+ {
+ brent_kung_prefix_sum(&(VARBUF1(z, 1, x)), padsize_y - 1, yst);
+ brent_kung_prefix_sum(&(VARBUF2(z, 1, x)), padsize_y - 1, yst);
+ }
+ }
+
+ if (have_z)
+ {
+ for (int y = 1; y < padsize_y; y++)
+ {
+ for (int x = 1; x < padsize_x; x++)
+ {
+ brent_kung_prefix_sum(&(VARBUF1(1, y, x)), padsize_z - 1, zst);
+ brent_kung_prefix_sum(&(VARBUF2(1, y, x)), padsize_z - 1, zst);
+ }
+ }
+ }
+
+ // Compute a few constants used in the variance-calculation.
+ float alpha_kdim = static_cast<float>(2 * alpha_kernel_radius + 1);
+ float alpha_rsamples;
+
+ if (have_z)
+ {
+ alpha_rsamples = 1.0f / (alpha_kdim * alpha_kdim * alpha_kdim);
+ }
+ else
+ {
+ alpha_rsamples = 1.0f / (alpha_kdim * alpha_kdim);
+ }
+
+ // Use the summed-area tables to compute variance for each neighborhood
+ if (have_z)
+ {
+ for (int z = 0; z < size_z; z++)
+ {
+ int z_src = z + kernel_radius_z;
+ int z_dst = z + offset_z;
+ int z_low = z_src - alpha_kernel_radius;
+ int z_high = z_src + alpha_kernel_radius + 1;
+
+ for (int y = 0; y < size_y; y++)
+ {
+ int y_src = y + kernel_radius_xy;
+ int y_dst = y + offset_y;
+ int y_low = y_src - alpha_kernel_radius;
+ int y_high = y_src + alpha_kernel_radius + 1;
+
+ for (int x = 0; x < size_x; x++)
+ {
+ int x_src = x + kernel_radius_xy;
+ int x_dst = x + offset_x;
+ int x_low = x_src - alpha_kernel_radius;
+ int x_high = x_src + alpha_kernel_radius + 1;
+
+ // Summed-area table lookups for alpha average
+ float vasum = ( VARBUF1(z_high, y_low, x_low).lane<3>()
+ - VARBUF1(z_high, y_low, x_high).lane<3>()
+ - VARBUF1(z_high, y_high, x_low).lane<3>()
+ + VARBUF1(z_high, y_high, x_high).lane<3>()) -
+ ( VARBUF1(z_low, y_low, x_low).lane<3>()
+ - VARBUF1(z_low, y_low, x_high).lane<3>()
+ - VARBUF1(z_low, y_high, x_low).lane<3>()
+ + VARBUF1(z_low, y_high, x_high).lane<3>());
+
+ int out_index = z_dst * zdt + y_dst * ydt + x_dst;
+ input_alpha_averages[out_index] = (vasum * alpha_rsamples);
+ }
+ }
+ }
+ }
+ else
+ {
+ for (int y = 0; y < size_y; y++)
+ {
+ int y_src = y + kernel_radius_xy;
+ int y_dst = y + offset_y;
+ int y_low = y_src - alpha_kernel_radius;
+ int y_high = y_src + alpha_kernel_radius + 1;
+
+ for (int x = 0; x < size_x; x++)
+ {
+ int x_src = x + kernel_radius_xy;
+ int x_dst = x + offset_x;
+ int x_low = x_src - alpha_kernel_radius;
+ int x_high = x_src + alpha_kernel_radius + 1;
+
+ // Summed-area table lookups for alpha average
+ float vasum = VARBUF1(0, y_low, x_low).lane<3>()
+ - VARBUF1(0, y_low, x_high).lane<3>()
+ - VARBUF1(0, y_high, x_low).lane<3>()
+ + VARBUF1(0, y_high, x_high).lane<3>();
+
+ int out_index = y_dst * ydt + x_dst;
+ input_alpha_averages[out_index] = (vasum * alpha_rsamples);
+ }
+ }
+ }
+}
+
+/* See header for documentation. */
+unsigned int init_compute_averages(
+ const astcenc_image& img,
+ unsigned int alpha_kernel_radius,
+ const astcenc_swizzle& swz,
+ avg_args& ag
+) {
+ unsigned int size_x = img.dim_x;
+ unsigned int size_y = img.dim_y;
+ unsigned int size_z = img.dim_z;
+
+ // Compute maximum block size and from that the working memory buffer size
+ unsigned int kernel_radius = alpha_kernel_radius;
+ unsigned int kerneldim = 2 * kernel_radius + 1;
+
+ bool have_z = (size_z > 1);
+ unsigned int max_blk_size_xy = have_z ? 16 : 32;
+ unsigned int max_blk_size_z = astc::min(size_z, have_z ? 16u : 1u);
+
+ unsigned int max_padsize_xy = max_blk_size_xy + kerneldim;
+ unsigned int max_padsize_z = max_blk_size_z + (have_z ? kerneldim : 0);
+
+ // Perform block-wise averages calculations across the image
+ // Initialize fields which are not populated until later
+ ag.arg.size_x = 0;
+ ag.arg.size_y = 0;
+ ag.arg.size_z = 0;
+ ag.arg.offset_x = 0;
+ ag.arg.offset_y = 0;
+ ag.arg.offset_z = 0;
+ ag.arg.work_memory = nullptr;
+
+ ag.arg.img = &img;
+ ag.arg.swz = swz;
+ ag.arg.have_z = have_z;
+ ag.arg.alpha_kernel_radius = alpha_kernel_radius;
+
+ ag.img_size_x = size_x;
+ ag.img_size_y = size_y;
+ ag.img_size_z = size_z;
+ ag.blk_size_xy = max_blk_size_xy;
+ ag.blk_size_z = max_blk_size_z;
+ ag.work_memory_size = 2 * max_padsize_xy * max_padsize_xy * max_padsize_z;
+
+ // The parallel task count
+ unsigned int z_tasks = (size_z + max_blk_size_z - 1) / max_blk_size_z;
+ unsigned int y_tasks = (size_y + max_blk_size_xy - 1) / max_blk_size_xy;
+ return z_tasks * y_tasks;
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_decompress_symbolic.cpp b/thirdparty/astcenc/astcenc_decompress_symbolic.cpp
new file mode 100644
index 0000000000..39e5525c3b
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_decompress_symbolic.cpp
@@ -0,0 +1,623 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions to decompress a symbolic block.
+ */
+
+#include "astcenc_internal.h"
+
+#include <stdio.h>
+#include <assert.h>
+
+/**
+ * @brief Compute the integer linear interpolation of two color endpoints.
+ *
+ * @param decode_mode The ASTC profile (linear or sRGB)
+ * @param color0 The endpoint0 color.
+ * @param color1 The endpoint1 color.
+ * @param weights The interpolation weight (between 0 and 64).
+ *
+ * @return The interpolated color.
+ */
+static vint4 lerp_color_int(
+ astcenc_profile decode_mode,
+ vint4 color0,
+ vint4 color1,
+ vint4 weights
+) {
+ vint4 weight1 = weights;
+ vint4 weight0 = vint4(64) - weight1;
+
+ if (decode_mode == ASTCENC_PRF_LDR_SRGB)
+ {
+ color0 = asr<8>(color0);
+ color1 = asr<8>(color1);
+ }
+
+ vint4 color = (color0 * weight0) + (color1 * weight1) + vint4(32);
+ color = asr<6>(color);
+
+ if (decode_mode == ASTCENC_PRF_LDR_SRGB)
+ {
+ color = color * vint4(257);
+ }
+
+ return color;
+}
+
+
+/**
+ * @brief Convert integer color value into a float value for the decoder.
+ *
+ * @param data The integer color value post-interpolation.
+ * @param lns_mask If set treat lane as HDR (LNS) else LDR (unorm16).
+ *
+ * @return The float color value.
+ */
+static inline vfloat4 decode_texel(
+ vint4 data,
+ vmask4 lns_mask
+) {
+ vint4 color_lns = vint4::zero();
+ vint4 color_unorm = vint4::zero();
+
+ if (any(lns_mask))
+ {
+ color_lns = lns_to_sf16(data);
+ }
+
+ if (!all(lns_mask))
+ {
+ color_unorm = unorm16_to_sf16(data);
+ }
+
+ // Pick components and then convert to FP16
+ vint4 datai = select(color_unorm, color_lns, lns_mask);
+ return float16_to_float(datai);
+}
+
+/* See header for documentation. */
+void unpack_weights(
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ const decimation_info& di,
+ bool is_dual_plane,
+ int weights_plane1[BLOCK_MAX_TEXELS],
+ int weights_plane2[BLOCK_MAX_TEXELS]
+) {
+ // Safe to overshoot as all arrays are allocated to full size
+ if (!is_dual_plane)
+ {
+ // Build full 64-entry weight lookup table
+ vint4 tab0(reinterpret_cast<const int*>(scb.weights + 0));
+ vint4 tab1(reinterpret_cast<const int*>(scb.weights + 16));
+ vint4 tab2(reinterpret_cast<const int*>(scb.weights + 32));
+ vint4 tab3(reinterpret_cast<const int*>(scb.weights + 48));
+
+ vint tab0p, tab1p, tab2p, tab3p;
+ vtable_prepare(tab0, tab1, tab2, tab3, tab0p, tab1p, tab2p, tab3p);
+
+ for (unsigned int i = 0; i < bsd.texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint summed_value(8);
+ vint weight_count(di.texel_weight_count + i);
+ int max_weight_count = hmax(weight_count).lane<0>();
+
+ promise(max_weight_count > 0);
+ for (int j = 0; j < max_weight_count; j++)
+ {
+ vint texel_weights(di.texel_weights_tr[j] + i);
+ vint texel_weights_int(di.texel_weight_contribs_int_tr[j] + i);
+
+ summed_value += vtable_8bt_32bi(tab0p, tab1p, tab2p, tab3p, texel_weights) * texel_weights_int;
+ }
+
+ store(lsr<4>(summed_value), weights_plane1 + i);
+ }
+ }
+ else
+ {
+ // Build a 32-entry weight lookup table per plane
+ // Plane 1
+ vint4 tab0_plane1(reinterpret_cast<const int*>(scb.weights + 0));
+ vint4 tab1_plane1(reinterpret_cast<const int*>(scb.weights + 16));
+ vint tab0_plane1p, tab1_plane1p;
+ vtable_prepare(tab0_plane1, tab1_plane1, tab0_plane1p, tab1_plane1p);
+
+ // Plane 2
+ vint4 tab0_plane2(reinterpret_cast<const int*>(scb.weights + 32));
+ vint4 tab1_plane2(reinterpret_cast<const int*>(scb.weights + 48));
+ vint tab0_plane2p, tab1_plane2p;
+ vtable_prepare(tab0_plane2, tab1_plane2, tab0_plane2p, tab1_plane2p);
+
+ for (unsigned int i = 0; i < bsd.texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint sum_plane1(8);
+ vint sum_plane2(8);
+
+ vint weight_count(di.texel_weight_count + i);
+ int max_weight_count = hmax(weight_count).lane<0>();
+
+ promise(max_weight_count > 0);
+ for (int j = 0; j < max_weight_count; j++)
+ {
+ vint texel_weights(di.texel_weights_tr[j] + i);
+ vint texel_weights_int(di.texel_weight_contribs_int_tr[j] + i);
+
+ sum_plane1 += vtable_8bt_32bi(tab0_plane1p, tab1_plane1p, texel_weights) * texel_weights_int;
+ sum_plane2 += vtable_8bt_32bi(tab0_plane2p, tab1_plane2p, texel_weights) * texel_weights_int;
+ }
+
+ store(lsr<4>(sum_plane1), weights_plane1 + i);
+ store(lsr<4>(sum_plane2), weights_plane2 + i);
+ }
+ }
+}
+
+/**
+ * @brief Return an FP32 NaN value for use in error colors.
+ *
+ * This NaN encoding will turn into 0xFFFF when converted to an FP16 NaN.
+ *
+ * @return The float color value.
+ */
+static float error_color_nan()
+{
+ if32 v;
+ v.u = 0xFFFFE000U;
+ return v.f;
+}
+
+/* See header for documentation. */
+void decompress_symbolic_block(
+ astcenc_profile decode_mode,
+ const block_size_descriptor& bsd,
+ int xpos,
+ int ypos,
+ int zpos,
+ const symbolic_compressed_block& scb,
+ image_block& blk
+) {
+ blk.xpos = xpos;
+ blk.ypos = ypos;
+ blk.zpos = zpos;
+
+ blk.data_min = vfloat4::zero();
+ blk.data_mean = vfloat4::zero();
+ blk.data_max = vfloat4::zero();
+ blk.grayscale = false;
+
+ // If we detected an error-block, blow up immediately.
+ if (scb.block_type == SYM_BTYPE_ERROR)
+ {
+ for (unsigned int i = 0; i < bsd.texel_count; i++)
+ {
+ blk.data_r[i] = error_color_nan();
+ blk.data_g[i] = error_color_nan();
+ blk.data_b[i] = error_color_nan();
+ blk.data_a[i] = error_color_nan();
+ blk.rgb_lns[i] = 0;
+ blk.alpha_lns[i] = 0;
+ }
+
+ return;
+ }
+
+ if ((scb.block_type == SYM_BTYPE_CONST_F16) ||
+ (scb.block_type == SYM_BTYPE_CONST_U16))
+ {
+ vfloat4 color;
+ uint8_t use_lns = 0;
+
+ // UNORM16 constant color block
+ if (scb.block_type == SYM_BTYPE_CONST_U16)
+ {
+ vint4 colori(scb.constant_color);
+
+ // For sRGB decoding a real decoder would just use the top 8 bits for color conversion.
+ // We don't color convert, so rescale the top 8 bits into the full 16 bit dynamic range.
+ if (decode_mode == ASTCENC_PRF_LDR_SRGB)
+ {
+ colori = asr<8>(colori) * 257;
+ }
+
+ vint4 colorf16 = unorm16_to_sf16(colori);
+ color = float16_to_float(colorf16);
+ }
+ // FLOAT16 constant color block
+ else
+ {
+ switch (decode_mode)
+ {
+ case ASTCENC_PRF_LDR_SRGB:
+ case ASTCENC_PRF_LDR:
+ color = vfloat4(error_color_nan());
+ break;
+ case ASTCENC_PRF_HDR_RGB_LDR_A:
+ case ASTCENC_PRF_HDR:
+ // Constant-color block; unpack from FP16 to FP32.
+ color = float16_to_float(vint4(scb.constant_color));
+ use_lns = 1;
+ break;
+ }
+ }
+
+ for (unsigned int i = 0; i < bsd.texel_count; i++)
+ {
+ blk.data_r[i] = color.lane<0>();
+ blk.data_g[i] = color.lane<1>();
+ blk.data_b[i] = color.lane<2>();
+ blk.data_a[i] = color.lane<3>();
+ blk.rgb_lns[i] = use_lns;
+ blk.alpha_lns[i] = use_lns;
+ }
+
+ return;
+ }
+
+ // Get the appropriate partition-table entry
+ int partition_count = scb.partition_count;
+ const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index);
+
+ // Get the appropriate block descriptors
+ const auto& bm = bsd.get_block_mode(scb.block_mode);
+ const auto& di = bsd.get_decimation_info(bm.decimation_mode);
+
+ bool is_dual_plane = static_cast<bool>(bm.is_dual_plane);
+
+ // Unquantize and undecimate the weights
+ int plane1_weights[BLOCK_MAX_TEXELS];
+ int plane2_weights[BLOCK_MAX_TEXELS];
+ unpack_weights(bsd, scb, di, is_dual_plane, plane1_weights, plane2_weights);
+
+ // Now that we have endpoint colors and weights, we can unpack texel colors
+ int plane2_component = scb.plane2_component;
+ vmask4 plane2_mask = vint4::lane_id() == vint4(plane2_component);
+
+ for (int i = 0; i < partition_count; i++)
+ {
+ // Decode the color endpoints for this partition
+ vint4 ep0;
+ vint4 ep1;
+ bool rgb_lns;
+ bool a_lns;
+
+ unpack_color_endpoints(decode_mode,
+ scb.color_formats[i],
+ scb.color_values[i],
+ rgb_lns, a_lns,
+ ep0, ep1);
+
+ vmask4 lns_mask(rgb_lns, rgb_lns, rgb_lns, a_lns);
+
+ int texel_count = pi.partition_texel_count[i];
+ for (int j = 0; j < texel_count; j++)
+ {
+ int tix = pi.texels_of_partition[i][j];
+ vint4 weight = select(vint4(plane1_weights[tix]), vint4(plane2_weights[tix]), plane2_mask);
+ vint4 color = lerp_color_int(decode_mode, ep0, ep1, weight);
+ vfloat4 colorf = decode_texel(color, lns_mask);
+
+ blk.data_r[tix] = colorf.lane<0>();
+ blk.data_g[tix] = colorf.lane<1>();
+ blk.data_b[tix] = colorf.lane<2>();
+ blk.data_a[tix] = colorf.lane<3>();
+ }
+ }
+}
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/* See header for documentation. */
+float compute_symbolic_block_difference_2plane(
+ const astcenc_config& config,
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ const image_block& blk
+) {
+ // If we detected an error-block, blow up immediately.
+ if (scb.block_type == SYM_BTYPE_ERROR)
+ {
+ return ERROR_CALC_DEFAULT;
+ }
+
+ assert(scb.block_mode >= 0);
+ assert(scb.partition_count == 1);
+ assert(bsd.get_block_mode(scb.block_mode).is_dual_plane == 1);
+
+ // Get the appropriate block descriptor
+ const block_mode& bm = bsd.get_block_mode(scb.block_mode);
+ const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode);
+
+ // Unquantize and undecimate the weights
+ int plane1_weights[BLOCK_MAX_TEXELS];
+ int plane2_weights[BLOCK_MAX_TEXELS];
+ unpack_weights(bsd, scb, di, true, plane1_weights, plane2_weights);
+
+ vmask4 plane2_mask = vint4::lane_id() == vint4(scb.plane2_component);
+
+ vfloat4 summa = vfloat4::zero();
+
+ // Decode the color endpoints for this partition
+ vint4 ep0;
+ vint4 ep1;
+ bool rgb_lns;
+ bool a_lns;
+
+ unpack_color_endpoints(config.profile,
+ scb.color_formats[0],
+ scb.color_values[0],
+ rgb_lns, a_lns,
+ ep0, ep1);
+
+ // Unpack and compute error for each texel in the partition
+ unsigned int texel_count = bsd.texel_count;
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ vint4 weight = select(vint4(plane1_weights[i]), vint4(plane2_weights[i]), plane2_mask);
+ vint4 colori = lerp_color_int(config.profile, ep0, ep1, weight);
+
+ vfloat4 color = int_to_float(colori);
+ vfloat4 oldColor = blk.texel(i);
+
+ // Compare error using a perceptual decode metric for RGBM textures
+ if (config.flags & ASTCENC_FLG_MAP_RGBM)
+ {
+ // Fail encodings that result in zero weight M pixels. Note that this can cause
+ // "interesting" artifacts if we reject all useful encodings - we typically get max
+ // brightness encodings instead which look just as bad. We recommend users apply a
+ // bias to their stored M value, limiting the lower value to 16 or 32 to avoid
+ // getting small M values post-quantization, but we can't prove it would never
+ // happen, especially at low bit rates ...
+ if (color.lane<3>() == 0.0f)
+ {
+ return -ERROR_CALC_DEFAULT;
+ }
+
+ // Compute error based on decoded RGBM color
+ color = vfloat4(
+ color.lane<0>() * color.lane<3>() * config.rgbm_m_scale,
+ color.lane<1>() * color.lane<3>() * config.rgbm_m_scale,
+ color.lane<2>() * color.lane<3>() * config.rgbm_m_scale,
+ 1.0f
+ );
+
+ oldColor = vfloat4(
+ oldColor.lane<0>() * oldColor.lane<3>() * config.rgbm_m_scale,
+ oldColor.lane<1>() * oldColor.lane<3>() * config.rgbm_m_scale,
+ oldColor.lane<2>() * oldColor.lane<3>() * config.rgbm_m_scale,
+ 1.0f
+ );
+ }
+
+ vfloat4 error = oldColor - color;
+ error = min(abs(error), 1e15f);
+ error = error * error;
+
+ summa += min(dot(error, blk.channel_weight), ERROR_CALC_DEFAULT);
+ }
+
+ return summa.lane<0>();
+}
+
+/* See header for documentation. */
+float compute_symbolic_block_difference_1plane(
+ const astcenc_config& config,
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ const image_block& blk
+) {
+ assert(bsd.get_block_mode(scb.block_mode).is_dual_plane == 0);
+
+ // If we detected an error-block, blow up immediately.
+ if (scb.block_type == SYM_BTYPE_ERROR)
+ {
+ return ERROR_CALC_DEFAULT;
+ }
+
+ assert(scb.block_mode >= 0);
+
+ // Get the appropriate partition-table entry
+ unsigned int partition_count = scb.partition_count;
+ const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index);
+
+ // Get the appropriate block descriptor
+ const block_mode& bm = bsd.get_block_mode(scb.block_mode);
+ const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode);
+
+ // Unquantize and undecimate the weights
+ int plane1_weights[BLOCK_MAX_TEXELS];
+ unpack_weights(bsd, scb, di, false, plane1_weights, nullptr);
+
+ vfloat4 summa = vfloat4::zero();
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ // Decode the color endpoints for this partition
+ vint4 ep0;
+ vint4 ep1;
+ bool rgb_lns;
+ bool a_lns;
+
+ unpack_color_endpoints(config.profile,
+ scb.color_formats[i],
+ scb.color_values[i],
+ rgb_lns, a_lns,
+ ep0, ep1);
+
+ // Unpack and compute error for each texel in the partition
+ unsigned int texel_count = pi.partition_texel_count[i];
+ for (unsigned int j = 0; j < texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ vint4 colori = lerp_color_int(config.profile, ep0, ep1,
+ vint4(plane1_weights[tix]));
+
+ vfloat4 color = int_to_float(colori);
+ vfloat4 oldColor = blk.texel(tix);
+
+ // Compare error using a perceptual decode metric for RGBM textures
+ if (config.flags & ASTCENC_FLG_MAP_RGBM)
+ {
+ // Fail encodings that result in zero weight M pixels. Note that this can cause
+ // "interesting" artifacts if we reject all useful encodings - we typically get max
+ // brightness encodings instead which look just as bad. We recommend users apply a
+ // bias to their stored M value, limiting the lower value to 16 or 32 to avoid
+ // getting small M values post-quantization, but we can't prove it would never
+ // happen, especially at low bit rates ...
+ if (color.lane<3>() == 0.0f)
+ {
+ return -ERROR_CALC_DEFAULT;
+ }
+
+ // Compute error based on decoded RGBM color
+ color = vfloat4(
+ color.lane<0>() * color.lane<3>() * config.rgbm_m_scale,
+ color.lane<1>() * color.lane<3>() * config.rgbm_m_scale,
+ color.lane<2>() * color.lane<3>() * config.rgbm_m_scale,
+ 1.0f
+ );
+
+ oldColor = vfloat4(
+ oldColor.lane<0>() * oldColor.lane<3>() * config.rgbm_m_scale,
+ oldColor.lane<1>() * oldColor.lane<3>() * config.rgbm_m_scale,
+ oldColor.lane<2>() * oldColor.lane<3>() * config.rgbm_m_scale,
+ 1.0f
+ );
+ }
+
+ vfloat4 error = oldColor - color;
+ error = min(abs(error), 1e15f);
+ error = error * error;
+
+ summa += min(dot(error, blk.channel_weight), ERROR_CALC_DEFAULT);
+ }
+ }
+
+ return summa.lane<0>();
+}
+
+/* See header for documentation. */
+float compute_symbolic_block_difference_1plane_1partition(
+ const astcenc_config& config,
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ const image_block& blk
+) {
+ // If we detected an error-block, blow up immediately.
+ if (scb.block_type == SYM_BTYPE_ERROR)
+ {
+ return ERROR_CALC_DEFAULT;
+ }
+
+ assert(scb.block_mode >= 0);
+ assert(bsd.get_partition_info(scb.partition_count, scb.partition_index).partition_count == 1);
+
+ // Get the appropriate block descriptor
+ const block_mode& bm = bsd.get_block_mode(scb.block_mode);
+ const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode);
+
+ // Unquantize and undecimate the weights
+ alignas(ASTCENC_VECALIGN) int plane1_weights[BLOCK_MAX_TEXELS];
+ unpack_weights(bsd, scb, di, false, plane1_weights, nullptr);
+
+ // Decode the color endpoints for this partition
+ vint4 ep0;
+ vint4 ep1;
+ bool rgb_lns;
+ bool a_lns;
+
+ unpack_color_endpoints(config.profile,
+ scb.color_formats[0],
+ scb.color_values[0],
+ rgb_lns, a_lns,
+ ep0, ep1);
+
+
+ // Pre-shift sRGB so things round correctly
+ if (config.profile == ASTCENC_PRF_LDR_SRGB)
+ {
+ ep0 = asr<8>(ep0);
+ ep1 = asr<8>(ep1);
+ }
+
+ // Unpack and compute error for each texel in the partition
+ vfloatacc summav = vfloatacc::zero();
+
+ vint lane_id = vint::lane_id();
+ vint srgb_scale(config.profile == ASTCENC_PRF_LDR_SRGB ? 257 : 1);
+
+ unsigned int texel_count = bsd.texel_count;
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Compute EP1 contribution
+ vint weight1 = vint::loada(plane1_weights + i);
+ vint ep1_r = vint(ep1.lane<0>()) * weight1;
+ vint ep1_g = vint(ep1.lane<1>()) * weight1;
+ vint ep1_b = vint(ep1.lane<2>()) * weight1;
+ vint ep1_a = vint(ep1.lane<3>()) * weight1;
+
+ // Compute EP0 contribution
+ vint weight0 = vint(64) - weight1;
+ vint ep0_r = vint(ep0.lane<0>()) * weight0;
+ vint ep0_g = vint(ep0.lane<1>()) * weight0;
+ vint ep0_b = vint(ep0.lane<2>()) * weight0;
+ vint ep0_a = vint(ep0.lane<3>()) * weight0;
+
+ // Shift so things round correctly
+ vint colori_r = asr<6>(ep0_r + ep1_r + vint(32)) * srgb_scale;
+ vint colori_g = asr<6>(ep0_g + ep1_g + vint(32)) * srgb_scale;
+ vint colori_b = asr<6>(ep0_b + ep1_b + vint(32)) * srgb_scale;
+ vint colori_a = asr<6>(ep0_a + ep1_a + vint(32)) * srgb_scale;
+
+ // Compute color diff
+ vfloat color_r = int_to_float(colori_r);
+ vfloat color_g = int_to_float(colori_g);
+ vfloat color_b = int_to_float(colori_b);
+ vfloat color_a = int_to_float(colori_a);
+
+ vfloat color_orig_r = loada(blk.data_r + i);
+ vfloat color_orig_g = loada(blk.data_g + i);
+ vfloat color_orig_b = loada(blk.data_b + i);
+ vfloat color_orig_a = loada(blk.data_a + i);
+
+ vfloat color_error_r = min(abs(color_orig_r - color_r), vfloat(1e15f));
+ vfloat color_error_g = min(abs(color_orig_g - color_g), vfloat(1e15f));
+ vfloat color_error_b = min(abs(color_orig_b - color_b), vfloat(1e15f));
+ vfloat color_error_a = min(abs(color_orig_a - color_a), vfloat(1e15f));
+
+ // Compute squared error metric
+ color_error_r = color_error_r * color_error_r;
+ color_error_g = color_error_g * color_error_g;
+ color_error_b = color_error_b * color_error_b;
+ color_error_a = color_error_a * color_error_a;
+
+ vfloat metric = color_error_r * blk.channel_weight.lane<0>()
+ + color_error_g * blk.channel_weight.lane<1>()
+ + color_error_b * blk.channel_weight.lane<2>()
+ + color_error_a * blk.channel_weight.lane<3>();
+
+ // Mask off bad lanes
+ vmask mask = lane_id < vint(texel_count);
+ lane_id += vint(ASTCENC_SIMD_WIDTH);
+ haccumulate(summav, metric, mask);
+ }
+
+ return hadd_s(summav);
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_diagnostic_trace.cpp b/thirdparty/astcenc/astcenc_diagnostic_trace.cpp
new file mode 100644
index 0000000000..7fa7ab1a8b
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_diagnostic_trace.cpp
@@ -0,0 +1,230 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2021-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for the library entrypoint.
+ */
+
+#if defined(ASTCENC_DIAGNOSTICS)
+
+#include <cassert>
+#include <cstdarg>
+#include <cstdio>
+#include <string>
+
+#include "astcenc_diagnostic_trace.h"
+
+/** @brief The global trace logger. */
+static TraceLog* g_TraceLog = nullptr;
+
+/** @brief The JSON indentation level. */
+static const size_t g_trace_indent = 2;
+
+TraceLog::TraceLog(
+ const char* file_name):
+ m_file(file_name, std::ofstream::out | std::ofstream::binary)
+{
+ assert(!g_TraceLog);
+ g_TraceLog = this;
+ m_root = new TraceNode("root");
+}
+
+/* See header for documentation. */
+TraceNode* TraceLog::get_current_leaf()
+{
+ if (m_stack.size())
+ {
+ return m_stack.back();
+ }
+
+ return nullptr;
+}
+
+/* See header for documentation. */
+size_t TraceLog::get_depth()
+{
+ return m_stack.size();
+}
+
+/* See header for documentation. */
+TraceLog::~TraceLog()
+{
+ assert(g_TraceLog == this);
+ delete m_root;
+ g_TraceLog = nullptr;
+}
+
+/* See header for documentation. */
+TraceNode::TraceNode(
+ const char* format,
+ ...
+) {
+ // Format the name string
+ constexpr size_t bufsz = 256;
+ char buffer[bufsz];
+
+ va_list args;
+ va_start (args, format);
+ vsnprintf (buffer, bufsz, format, args);
+ va_end (args);
+
+ // Guarantee there is a nul terminator
+ buffer[bufsz - 1] = 0;
+
+ // Generate the node
+ TraceNode* parent = g_TraceLog->get_current_leaf();
+ size_t depth = g_TraceLog->get_depth();
+ g_TraceLog->m_stack.push_back(this);
+
+ bool comma = parent && parent->m_attrib_count;
+ auto& out = g_TraceLog->m_file;
+
+ if (parent)
+ {
+ parent->m_attrib_count++;
+ }
+
+ if (comma)
+ {
+ out << ',';
+ }
+
+ if (depth)
+ {
+ out << '\n';
+ }
+
+ size_t out_indent = (depth * 2) * g_trace_indent;
+ size_t in_indent = (depth * 2 + 1) * g_trace_indent;
+
+ std::string out_indents("");
+ if (out_indent)
+ {
+ out_indents = std::string(out_indent, ' ');
+ }
+
+ std::string in_indents(in_indent, ' ');
+
+ out << out_indents << "[ \"node\", \"" << buffer << "\",\n";
+ out << in_indents << "[";
+}
+
+/* See header for documentation. */
+void TraceNode::add_attrib(
+ std::string type,
+ std::string key,
+ std::string value
+) {
+ (void)type;
+
+ size_t depth = g_TraceLog->get_depth();
+ size_t indent = (depth * 2) * g_trace_indent;
+ auto& out = g_TraceLog->m_file;
+ bool comma = m_attrib_count;
+ m_attrib_count++;
+
+ if (comma)
+ {
+ out << ',';
+ }
+
+ out << '\n';
+ out << std::string(indent, ' ') << "[ "
+ << "\"" << key << "\", "
+ << value << " ]";
+}
+
+/* See header for documentation. */
+TraceNode::~TraceNode()
+{
+ g_TraceLog->m_stack.pop_back();
+
+ auto& out = g_TraceLog->m_file;
+ size_t depth = g_TraceLog->get_depth();
+ size_t out_indent = (depth * 2) * g_trace_indent;
+ size_t in_indent = (depth * 2 + 1) * g_trace_indent;
+
+ std::string out_indents("");
+ if (out_indent)
+ {
+ out_indents = std::string(out_indent, ' ');
+ }
+
+ std::string in_indents(in_indent, ' ');
+
+ if (m_attrib_count)
+ {
+ out << "\n" << in_indents;
+ }
+ out << "]\n";
+
+ out << out_indents << "]";
+}
+
+/* See header for documentation. */
+void trace_add_data(
+ const char* key,
+ const char* format,
+ ...
+) {
+ constexpr size_t bufsz = 256;
+ char buffer[bufsz];
+
+ va_list args;
+ va_start (args, format);
+ vsnprintf (buffer, bufsz, format, args);
+ va_end (args);
+
+ // Guarantee there is a nul terminator
+ buffer[bufsz - 1] = 0;
+
+ std::string value = "\"" + std::string(buffer) + "\"";
+
+ TraceNode* node = g_TraceLog->get_current_leaf();
+ node->add_attrib("str", key, value);
+}
+
+/* See header for documentation. */
+void trace_add_data(
+ const char* key,
+ float value
+) {
+ char buffer[256];
+ sprintf(buffer, "%.20g", (double)value);
+ TraceNode* node = g_TraceLog->get_current_leaf();
+ node->add_attrib("float", key, buffer);
+}
+
+/* See header for documentation. */
+void trace_add_data(
+ const char* key,
+ int value
+) {
+ TraceNode* node = g_TraceLog->get_current_leaf();
+ node->add_attrib("int", key, std::to_string(value));
+}
+
+/* See header for documentation. */
+void trace_add_data(
+ const char* key,
+ unsigned int value
+) {
+ TraceNode* node = g_TraceLog->get_current_leaf();
+ node->add_attrib("int", key, std::to_string(value));
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_diagnostic_trace.h b/thirdparty/astcenc/astcenc_diagnostic_trace.h
new file mode 100644
index 0000000000..f5586b0ad5
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_diagnostic_trace.h
@@ -0,0 +1,219 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2021-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief This module provides a set of diagnostic tracing utilities.
+ *
+ * Overview
+ * ========
+ *
+ * The built-in diagnostic trace tool generates a hierarchical JSON tree structure. The tree
+ * hierarchy contains three levels:
+ *
+ * - block
+ * - pass
+ * - candidate
+ *
+ * One block node exists for each compressed block in the image. One pass node exists for each major
+ * pass (N partition, M planes, O components) applied to a block. One candidate node exists for each
+ * encoding candidate trialed for a pass.
+ *
+ * Each node contains both the hierarchy but also a number of attributes which explain the behavior.
+ * For example, the block node contains the block coordinates in the image, the pass explains the
+ * pass configuration, and the candidate will explain the candidate encoding such as weight
+ * decimation, refinement error, etc.
+ *
+ * Trace Nodes are designed as scope-managed C++ objects with stack-like push/pop behavior.
+ * Constructing a trace node on the stack will automatically add it to the current node as a child,
+ * and then make it the current node. Destroying the current node will pop the stack and set the
+ * parent to the current node. This provides a robust mechanism for ensuring reliable nesting in the
+ * tree structure.
+ *
+ * A set of utility macros are provided to add attribute annotations to the current trace node.
+ *
+ * Usage
+ * =====
+ *
+ * Create Trace Nodes on the stack using the @c TRACE_NODE() macro. This will compile-out completely
+ * in builds with diagnostics disabled.
+ *
+ * Add annotations to the current trace node using the @c trace_add_data() macro. This will
+ * similarly compile out completely in builds with diagnostics disabled.
+ *
+ * If you need to add additional code to support diagnostics-only behavior wrap
+ * it in preprocessor guards:
+ *
+ * #if defined(ASTCENC_DIAGNOSTICS)
+ * #endif
+ */
+
+#ifndef ASTCENC_DIAGNOSTIC_TRACE_INCLUDED
+#define ASTCENC_DIAGNOSTIC_TRACE_INCLUDED
+
+#if defined(ASTCENC_DIAGNOSTICS)
+
+#include <iostream>
+#include <fstream>
+#include <vector>
+
+/**
+ * @brief Class representing a single node in the trace hierarchy.
+ */
+class TraceNode
+{
+public:
+ /**
+ * @brief Construct a new node.
+ *
+ * Constructing a node will push to the the top of the stack, automatically making it a child of
+ * the current node, and then setting it to become the current node.
+ *
+ * @param format The format template for the node name.
+ * @param ... The format parameters.
+ */
+ TraceNode(const char* format, ...);
+
+ /**
+ * @brief Add an attribute to this node.
+ *
+ * Note that no quoting is applied to the @c value, so if quoting is needed it must be done by
+ * the caller.
+ *
+ * @param type The type of the attribute.
+ * @param key The key of the attribute.
+ * @param value The value of the attribute.
+ */
+ void add_attrib(std::string type, std::string key, std::string value);
+
+ /**
+ * @brief Destroy this node.
+ *
+ * Destroying a node will pop it from the top of the stack, making its parent the current node.
+ * It is invalid behavior to destroy a node that is not the current node; usage must conform to
+ * stack push-pop semantics.
+ */
+ ~TraceNode();
+
+ /**
+ * @brief The number of attributes and child nodes in this node.
+ */
+ unsigned int m_attrib_count { 0 };
+};
+
+/**
+ * @brief Class representing the trace log file being written.
+ */
+class TraceLog
+{
+public:
+ /**
+ * @brief Create a new trace log.
+ *
+ * The trace log is global; there can be only one at a time.
+ *
+ * @param file_name The name of the file to write.
+ */
+ TraceLog(const char* file_name);
+
+ /**
+ * @brief Detroy the trace log.
+ *
+ * Trace logs MUST be cleanly destroyed to ensure the file gets written.
+ */
+ ~TraceLog();
+
+ /**
+ * @brief Get the current child node.
+ *
+ * @return The current leaf node.
+ */
+ TraceNode* get_current_leaf();
+
+ /**
+ * @brief Get the stack depth of the current child node.
+ *
+ * @return The current leaf node stack depth.
+ */
+ size_t get_depth();
+
+ /**
+ * @brief The file stream to write to.
+ */
+ std::ofstream m_file;
+
+ /**
+ * @brief The stack of nodes (newest at the back).
+ */
+ std::vector<TraceNode*> m_stack;
+
+private:
+ /**
+ * @brief The root node in the JSON file.
+ */
+ TraceNode* m_root;
+};
+
+/**
+ * @brief Utility macro to create a trace node on the stack.
+ *
+ * @param name The variable name to use.
+ * @param ... The name template and format parameters.
+ */
+#define TRACE_NODE(name, ...) TraceNode name(__VA_ARGS__);
+
+/**
+ * @brief Add a string annotation to the current node.
+ *
+ * @param key The name of the attribute.
+ * @param format The format template for the attribute value.
+ * @param ... The format parameters.
+ */
+void trace_add_data(const char* key, const char* format, ...);
+
+/**
+ * @brief Add a float annotation to the current node.
+ *
+ * @param key The name of the attribute.
+ * @param value The value of the attribute.
+ */
+void trace_add_data(const char* key, float value);
+
+/**
+ * @brief Add an integer annotation to the current node.
+ *
+ * @param key The name of the attribute.
+ * @param value The value of the attribute.
+ */
+void trace_add_data(const char* key, int value);
+
+/**
+ * @brief Add an unsigned integer annotation to the current node.
+ *
+ * @param key The name of the attribute.
+ * @param value The value of the attribute.
+ */
+void trace_add_data(const char* key, unsigned int value);
+
+#else
+
+#define TRACE_NODE(name, ...)
+
+#define trace_add_data(...)
+
+#endif
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_entry.cpp b/thirdparty/astcenc/astcenc_entry.cpp
new file mode 100644
index 0000000000..e59f1fe61a
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_entry.cpp
@@ -0,0 +1,1427 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for the library entrypoint.
+ */
+
+#include <array>
+#include <cstring>
+#include <new>
+
+#include "astcenc.h"
+#include "astcenc_internal_entry.h"
+#include "astcenc_diagnostic_trace.h"
+
+/**
+ * @brief Record of the quality tuning parameter values.
+ *
+ * See the @c astcenc_config structure for detailed parameter documentation.
+ *
+ * Note that the mse_overshoot entries are scaling factors relative to the base MSE to hit db_limit.
+ * A 20% overshoot is harder to hit for a higher base db_limit, so we may actually use lower ratios
+ * for the more through search presets because the underlying db_limit is so much higher.
+ */
+struct astcenc_preset_config
+{
+ float quality;
+ unsigned int tune_partition_count_limit;
+ unsigned int tune_2partition_index_limit;
+ unsigned int tune_3partition_index_limit;
+ unsigned int tune_4partition_index_limit;
+ unsigned int tune_block_mode_limit;
+ unsigned int tune_refinement_limit;
+ unsigned int tune_candidate_limit;
+ unsigned int tune_2partitioning_candidate_limit;
+ unsigned int tune_3partitioning_candidate_limit;
+ unsigned int tune_4partitioning_candidate_limit;
+ float tune_db_limit_a_base;
+ float tune_db_limit_b_base;
+ float tune_mse_overshoot;
+ float tune_2_partition_early_out_limit_factor;
+ float tune_3_partition_early_out_limit_factor;
+ float tune_2_plane_early_out_limit_correlation;
+};
+
+/**
+ * @brief The static presets for high bandwidth encodings (x < 25 texels per block).
+ */
+static const std::array<astcenc_preset_config, 6> preset_configs_high {{
+ {
+ ASTCENC_PRE_FASTEST,
+ 2, 10, 6, 4, 43, 2, 2, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.85f
+ }, {
+ ASTCENC_PRE_FAST,
+ 3, 18, 10, 8, 55, 3, 3, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.90f
+ }, {
+ ASTCENC_PRE_MEDIUM,
+ 4, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 2.5f, 1.1f, 1.05f, 0.95f
+ }, {
+ ASTCENC_PRE_THOROUGH,
+ 4, 82, 60, 30, 94, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.35f, 1.15f, 0.97f
+ }, {
+ ASTCENC_PRE_VERYTHOROUGH,
+ 4, 256, 128, 64, 98, 4, 6, 20, 14, 8, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f
+ }, {
+ ASTCENC_PRE_EXHAUSTIVE,
+ 4, 512, 512, 512, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f
+ }
+}};
+
+/**
+ * @brief The static presets for medium bandwidth encodings (25 <= x < 64 texels per block).
+ */
+static const std::array<astcenc_preset_config, 6> preset_configs_mid {{
+ {
+ ASTCENC_PRE_FASTEST,
+ 2, 10, 6, 4, 43, 2, 2, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.80f
+ }, {
+ ASTCENC_PRE_FAST,
+ 3, 18, 12, 10, 55, 3, 3, 2, 2, 2, 85.2f, 63.2f, 3.5f, 1.0f, 1.0f, 0.85f
+ }, {
+ ASTCENC_PRE_MEDIUM,
+ 4, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 3.0f, 1.1f, 1.05f, 0.90f
+ }, {
+ ASTCENC_PRE_THOROUGH,
+ 4, 82, 60, 30, 94, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.4f, 1.2f, 0.95f
+ }, {
+ ASTCENC_PRE_VERYTHOROUGH,
+ 4, 256, 128, 64, 98, 4, 6, 12, 8, 3, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f
+ }, {
+ ASTCENC_PRE_EXHAUSTIVE,
+ 4, 256, 256, 256, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f
+ }
+}};
+
+/**
+ * @brief The static presets for low bandwidth encodings (64 <= x texels per block).
+ */
+static const std::array<astcenc_preset_config, 6> preset_configs_low {{
+ {
+ ASTCENC_PRE_FASTEST,
+ 2, 10, 6, 4, 40, 2, 2, 2, 2, 2, 85.0f, 63.0f, 3.5f, 1.0f, 1.0f, 0.80f
+ }, {
+ ASTCENC_PRE_FAST,
+ 2, 18, 12, 10, 55, 3, 3, 2, 2, 2, 85.0f, 63.0f, 3.5f, 1.0f, 1.0f, 0.85f
+ }, {
+ ASTCENC_PRE_MEDIUM,
+ 3, 34, 28, 16, 77, 3, 3, 2, 2, 2, 95.0f, 70.0f, 3.5f, 1.1f, 1.05f, 0.90f
+ }, {
+ ASTCENC_PRE_THOROUGH,
+ 4, 82, 60, 30, 93, 4, 4, 3, 2, 2, 105.0f, 77.0f, 10.0f, 1.3f, 1.2f, 0.97f
+ }, {
+ ASTCENC_PRE_VERYTHOROUGH,
+ 4, 256, 128, 64, 98, 4, 6, 9, 5, 2, 200.0f, 200.0f, 10.0f, 1.6f, 1.4f, 0.98f
+ }, {
+ ASTCENC_PRE_EXHAUSTIVE,
+ 4, 256, 256, 256, 100, 4, 8, 32, 32, 32, 200.0f, 200.0f, 10.0f, 2.0f, 2.0f, 0.99f
+ }
+}};
+
+/**
+ * @brief Validate CPU floating point meets assumptions made in the codec.
+ *
+ * The codec is written with the assumption that a float threaded through the @c if32 union will be
+ * stored and reloaded as a 32-bit IEEE-754 float with round-to-nearest rounding. This is always the
+ * case in an IEEE-754 compliant system, however not every system or compilation mode is actually
+ * IEEE-754 compliant. This normally fails if the code is compiled with fast math enabled.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_cpu_float()
+{
+ if32 p;
+ volatile float xprec_testval = 2.51f;
+ p.f = xprec_testval + 12582912.0f;
+ float q = p.f - 12582912.0f;
+
+ if (q != 3.0f)
+ {
+ return ASTCENC_ERR_BAD_CPU_FLOAT;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+/**
+ * @brief Validate CPU ISA support meets the requirements of this build of the library.
+ *
+ * Each library build is statically compiled for a particular set of CPU ISA features, such as the
+ * SIMD support or other ISA extensions such as POPCNT. This function checks that the host CPU
+ * actually supports everything this build needs.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_cpu_isa()
+{
+ #if ASTCENC_SSE >= 41
+ if (!cpu_supports_sse41())
+ {
+ return ASTCENC_ERR_BAD_CPU_ISA;
+ }
+ #endif
+
+ #if ASTCENC_POPCNT >= 1
+ if (!cpu_supports_popcnt())
+ {
+ return ASTCENC_ERR_BAD_CPU_ISA;
+ }
+ #endif
+
+ #if ASTCENC_F16C >= 1
+ if (!cpu_supports_f16c())
+ {
+ return ASTCENC_ERR_BAD_CPU_ISA;
+ }
+ #endif
+
+ #if ASTCENC_AVX >= 2
+ if (!cpu_supports_avx2())
+ {
+ return ASTCENC_ERR_BAD_CPU_ISA;
+ }
+ #endif
+
+ return ASTCENC_SUCCESS;
+}
+
+/**
+ * @brief Validate config profile.
+ *
+ * @param profile The profile to check.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_profile(
+ astcenc_profile profile
+) {
+ // Values in this enum are from an external user, so not guaranteed to be
+ // bounded to the enum values
+ switch (static_cast<int>(profile))
+ {
+ case ASTCENC_PRF_LDR_SRGB:
+ case ASTCENC_PRF_LDR:
+ case ASTCENC_PRF_HDR_RGB_LDR_A:
+ case ASTCENC_PRF_HDR:
+ return ASTCENC_SUCCESS;
+ default:
+ return ASTCENC_ERR_BAD_PROFILE;
+ }
+}
+
+/**
+ * @brief Validate block size.
+ *
+ * @param block_x The block x dimensions.
+ * @param block_y The block y dimensions.
+ * @param block_z The block z dimensions.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_block_size(
+ unsigned int block_x,
+ unsigned int block_y,
+ unsigned int block_z
+) {
+ // Test if this is a legal block size at all
+ bool is_legal = (((block_z <= 1) && is_legal_2d_block_size(block_x, block_y)) ||
+ ((block_z >= 2) && is_legal_3d_block_size(block_x, block_y, block_z)));
+ if (!is_legal)
+ {
+ return ASTCENC_ERR_BAD_BLOCK_SIZE;
+ }
+
+ // Test if this build has sufficient capacity for this block size
+ bool have_capacity = (block_x * block_y * block_z) <= BLOCK_MAX_TEXELS;
+ if (!have_capacity)
+ {
+ return ASTCENC_ERR_NOT_IMPLEMENTED;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+/**
+ * @brief Validate flags.
+ *
+ * @param flags The flags to check.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_flags(
+ unsigned int flags
+) {
+ // Flags field must not contain any unknown flag bits
+ unsigned int exMask = ~ASTCENC_ALL_FLAGS;
+ if (popcount(flags & exMask) != 0)
+ {
+ return ASTCENC_ERR_BAD_FLAGS;
+ }
+
+ // Flags field must only contain at most a single map type
+ exMask = ASTCENC_FLG_MAP_NORMAL
+ | ASTCENC_FLG_MAP_RGBM;
+ if (popcount(flags & exMask) > 1)
+ {
+ return ASTCENC_ERR_BAD_FLAGS;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Validate single channel compression swizzle.
+ *
+ * @param swizzle The swizzle to check.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_compression_swz(
+ astcenc_swz swizzle
+) {
+ // Not all enum values are handled; SWZ_Z is invalid for compression
+ switch (static_cast<int>(swizzle))
+ {
+ case ASTCENC_SWZ_R:
+ case ASTCENC_SWZ_G:
+ case ASTCENC_SWZ_B:
+ case ASTCENC_SWZ_A:
+ case ASTCENC_SWZ_0:
+ case ASTCENC_SWZ_1:
+ return ASTCENC_SUCCESS;
+ default:
+ return ASTCENC_ERR_BAD_SWIZZLE;
+ }
+}
+
+/**
+ * @brief Validate overall compression swizzle.
+ *
+ * @param swizzle The swizzle to check.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_compression_swizzle(
+ const astcenc_swizzle& swizzle
+) {
+ if (validate_compression_swz(swizzle.r) ||
+ validate_compression_swz(swizzle.g) ||
+ validate_compression_swz(swizzle.b) ||
+ validate_compression_swz(swizzle.a))
+ {
+ return ASTCENC_ERR_BAD_SWIZZLE;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+#endif
+
+/**
+ * @brief Validate single channel decompression swizzle.
+ *
+ * @param swizzle The swizzle to check.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_decompression_swz(
+ astcenc_swz swizzle
+) {
+ // Values in this enum are from an external user, so not guaranteed to be
+ // bounded to the enum values
+ switch (static_cast<int>(swizzle))
+ {
+ case ASTCENC_SWZ_R:
+ case ASTCENC_SWZ_G:
+ case ASTCENC_SWZ_B:
+ case ASTCENC_SWZ_A:
+ case ASTCENC_SWZ_0:
+ case ASTCENC_SWZ_1:
+ case ASTCENC_SWZ_Z:
+ return ASTCENC_SUCCESS;
+ default:
+ return ASTCENC_ERR_BAD_SWIZZLE;
+ }
+}
+
+/**
+ * @brief Validate overall decompression swizzle.
+ *
+ * @param swizzle The swizzle to check.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_decompression_swizzle(
+ const astcenc_swizzle& swizzle
+) {
+ if (validate_decompression_swz(swizzle.r) ||
+ validate_decompression_swz(swizzle.g) ||
+ validate_decompression_swz(swizzle.b) ||
+ validate_decompression_swz(swizzle.a))
+ {
+ return ASTCENC_ERR_BAD_SWIZZLE;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+/**
+ * Validate that an incoming configuration is in-spec.
+ *
+ * This function can respond in two ways:
+ *
+ * * Numerical inputs that have valid ranges are clamped to those valid ranges. No error is thrown
+ * for out-of-range inputs in this case.
+ * * Numerical inputs and logic inputs are are logically invalid and which make no sense
+ * algorithmically will return an error.
+ *
+ * @param[in,out] config The input compressor configuration.
+ *
+ * @return Return @c ASTCENC_SUCCESS if validated, otherwise an error on failure.
+ */
+static astcenc_error validate_config(
+ astcenc_config &config
+) {
+ astcenc_error status;
+
+ status = validate_profile(config.profile);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ status = validate_flags(config.flags);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ status = validate_block_size(config.block_x, config.block_y, config.block_z);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+#if defined(ASTCENC_DECOMPRESS_ONLY)
+ // Decompress-only builds only support decompress-only contexts
+ if (!(config.flags & ASTCENC_FLG_DECOMPRESS_ONLY))
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+#endif
+
+ config.rgbm_m_scale = astc::max(config.rgbm_m_scale, 1.0f);
+
+ config.tune_partition_count_limit = astc::clamp(config.tune_partition_count_limit, 1u, 4u);
+ config.tune_2partition_index_limit = astc::clamp(config.tune_2partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS);
+ config.tune_3partition_index_limit = astc::clamp(config.tune_3partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS);
+ config.tune_4partition_index_limit = astc::clamp(config.tune_4partition_index_limit, 1u, BLOCK_MAX_PARTITIONINGS);
+ config.tune_block_mode_limit = astc::clamp(config.tune_block_mode_limit, 1u, 100u);
+ config.tune_refinement_limit = astc::max(config.tune_refinement_limit, 1u);
+ config.tune_candidate_limit = astc::clamp(config.tune_candidate_limit, 1u, TUNE_MAX_TRIAL_CANDIDATES);
+ config.tune_2partitioning_candidate_limit = astc::clamp(config.tune_2partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES);
+ config.tune_3partitioning_candidate_limit = astc::clamp(config.tune_3partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES);
+ config.tune_4partitioning_candidate_limit = astc::clamp(config.tune_4partitioning_candidate_limit, 1u, TUNE_MAX_PARTITIONING_CANDIDATES);
+ config.tune_db_limit = astc::max(config.tune_db_limit, 0.0f);
+ config.tune_mse_overshoot = astc::max(config.tune_mse_overshoot, 1.0f);
+ config.tune_2_partition_early_out_limit_factor = astc::max(config.tune_2_partition_early_out_limit_factor, 0.0f);
+ config.tune_3_partition_early_out_limit_factor = astc::max(config.tune_3_partition_early_out_limit_factor, 0.0f);
+ config.tune_2_plane_early_out_limit_correlation = astc::max(config.tune_2_plane_early_out_limit_correlation, 0.0f);
+
+ // Specifying a zero weight color component is not allowed; force to small value
+ float max_weight = astc::max(astc::max(config.cw_r_weight, config.cw_g_weight),
+ astc::max(config.cw_b_weight, config.cw_a_weight));
+ if (max_weight > 0.0f)
+ {
+ max_weight /= 1000.0f;
+ config.cw_r_weight = astc::max(config.cw_r_weight, max_weight);
+ config.cw_g_weight = astc::max(config.cw_g_weight, max_weight);
+ config.cw_b_weight = astc::max(config.cw_b_weight, max_weight);
+ config.cw_a_weight = astc::max(config.cw_a_weight, max_weight);
+ }
+ // If all color components error weights are zero then return an error
+ else
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+/* See header for documentation. */
+astcenc_error astcenc_config_init(
+ astcenc_profile profile,
+ unsigned int block_x,
+ unsigned int block_y,
+ unsigned int block_z,
+ float quality,
+ unsigned int flags,
+ astcenc_config* configp
+) {
+ astcenc_error status;
+
+ // Check basic library compatibility options here so they are checked early. Note, these checks
+ // are repeated in context_alloc for cases where callers use a manually defined config struct
+ status = validate_cpu_isa();
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ status = validate_cpu_float();
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ // Zero init all config fields; although most of will be over written
+ astcenc_config& config = *configp;
+ std::memset(&config, 0, sizeof(config));
+
+ // Process the block size
+ block_z = astc::max(block_z, 1u); // For 2D blocks Z==0 is accepted, but convert to 1
+ status = validate_block_size(block_x, block_y, block_z);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ config.block_x = block_x;
+ config.block_y = block_y;
+ config.block_z = block_z;
+
+ float texels = static_cast<float>(block_x * block_y * block_z);
+ float ltexels = logf(texels) / logf(10.0f);
+
+ // Process the performance quality level or preset; note that this must be done before we
+ // process any additional settings, such as color profile and flags, which may replace some of
+ // these settings with more use case tuned values
+ if (quality < ASTCENC_PRE_FASTEST ||
+ quality > ASTCENC_PRE_EXHAUSTIVE)
+ {
+ return ASTCENC_ERR_BAD_QUALITY;
+ }
+
+ static const std::array<astcenc_preset_config, 6>* preset_configs;
+ int texels_int = block_x * block_y * block_z;
+ if (texels_int < 25)
+ {
+ preset_configs = &preset_configs_high;
+ }
+ else if (texels_int < 64)
+ {
+ preset_configs = &preset_configs_mid;
+ }
+ else
+ {
+ preset_configs = &preset_configs_low;
+ }
+
+ // Determine which preset to use, or which pair to interpolate
+ size_t start;
+ size_t end;
+ for (end = 0; end < preset_configs->size(); end++)
+ {
+ if ((*preset_configs)[end].quality >= quality)
+ {
+ break;
+ }
+ }
+
+ start = end == 0 ? 0 : end - 1;
+
+ // Start and end node are the same - so just transfer the values.
+ if (start == end)
+ {
+ config.tune_partition_count_limit = (*preset_configs)[start].tune_partition_count_limit;
+ config.tune_2partition_index_limit = (*preset_configs)[start].tune_2partition_index_limit;
+ config.tune_3partition_index_limit = (*preset_configs)[start].tune_3partition_index_limit;
+ config.tune_4partition_index_limit = (*preset_configs)[start].tune_4partition_index_limit;
+ config.tune_block_mode_limit = (*preset_configs)[start].tune_block_mode_limit;
+ config.tune_refinement_limit = (*preset_configs)[start].tune_refinement_limit;
+ config.tune_candidate_limit = astc::min((*preset_configs)[start].tune_candidate_limit, TUNE_MAX_TRIAL_CANDIDATES);
+ config.tune_2partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_2partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES);
+ config.tune_3partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_3partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES);
+ config.tune_4partitioning_candidate_limit = astc::min((*preset_configs)[start].tune_4partitioning_candidate_limit, TUNE_MAX_PARTITIONING_CANDIDATES);
+ config.tune_db_limit = astc::max((*preset_configs)[start].tune_db_limit_a_base - 35 * ltexels,
+ (*preset_configs)[start].tune_db_limit_b_base - 19 * ltexels);
+
+ config.tune_mse_overshoot = (*preset_configs)[start].tune_mse_overshoot;
+
+ config.tune_2_partition_early_out_limit_factor = (*preset_configs)[start].tune_2_partition_early_out_limit_factor;
+ config.tune_3_partition_early_out_limit_factor =(*preset_configs)[start].tune_3_partition_early_out_limit_factor;
+ config.tune_2_plane_early_out_limit_correlation = (*preset_configs)[start].tune_2_plane_early_out_limit_correlation;
+ }
+ // Start and end node are not the same - so interpolate between them
+ else
+ {
+ auto& node_a = (*preset_configs)[start];
+ auto& node_b = (*preset_configs)[end];
+
+ float wt_range = node_b.quality - node_a.quality;
+ assert(wt_range > 0);
+
+ // Compute interpolation factors
+ float wt_node_a = (node_b.quality - quality) / wt_range;
+ float wt_node_b = (quality - node_a.quality) / wt_range;
+
+ #define LERP(param) ((node_a.param * wt_node_a) + (node_b.param * wt_node_b))
+ #define LERPI(param) astc::flt2int_rtn(\
+ (static_cast<float>(node_a.param) * wt_node_a) + \
+ (static_cast<float>(node_b.param) * wt_node_b))
+ #define LERPUI(param) static_cast<unsigned int>(LERPI(param))
+
+ config.tune_partition_count_limit = LERPI(tune_partition_count_limit);
+ config.tune_2partition_index_limit = LERPI(tune_2partition_index_limit);
+ config.tune_3partition_index_limit = LERPI(tune_3partition_index_limit);
+ config.tune_4partition_index_limit = LERPI(tune_4partition_index_limit);
+ config.tune_block_mode_limit = LERPI(tune_block_mode_limit);
+ config.tune_refinement_limit = LERPI(tune_refinement_limit);
+ config.tune_candidate_limit = astc::min(LERPUI(tune_candidate_limit),
+ TUNE_MAX_TRIAL_CANDIDATES);
+ config.tune_2partitioning_candidate_limit = astc::min(LERPUI(tune_2partitioning_candidate_limit),
+ BLOCK_MAX_PARTITIONINGS);
+ config.tune_3partitioning_candidate_limit = astc::min(LERPUI(tune_3partitioning_candidate_limit),
+ BLOCK_MAX_PARTITIONINGS);
+ config.tune_4partitioning_candidate_limit = astc::min(LERPUI(tune_4partitioning_candidate_limit),
+ BLOCK_MAX_PARTITIONINGS);
+ config.tune_db_limit = astc::max(LERP(tune_db_limit_a_base) - 35 * ltexels,
+ LERP(tune_db_limit_b_base) - 19 * ltexels);
+
+ config.tune_mse_overshoot = LERP(tune_mse_overshoot);
+
+ config.tune_2_partition_early_out_limit_factor = LERP(tune_2_partition_early_out_limit_factor);
+ config.tune_3_partition_early_out_limit_factor = LERP(tune_3_partition_early_out_limit_factor);
+ config.tune_2_plane_early_out_limit_correlation = LERP(tune_2_plane_early_out_limit_correlation);
+ #undef LERP
+ #undef LERPI
+ #undef LERPUI
+ }
+
+ // Set heuristics to the defaults for each color profile
+ config.cw_r_weight = 1.0f;
+ config.cw_g_weight = 1.0f;
+ config.cw_b_weight = 1.0f;
+ config.cw_a_weight = 1.0f;
+
+ config.a_scale_radius = 0;
+
+ config.rgbm_m_scale = 0.0f;
+
+ config.profile = profile;
+
+ // Values in this enum are from an external user, so not guaranteed to be
+ // bounded to the enum values
+ switch (static_cast<int>(profile))
+ {
+ case ASTCENC_PRF_LDR:
+ case ASTCENC_PRF_LDR_SRGB:
+ break;
+ case ASTCENC_PRF_HDR_RGB_LDR_A:
+ case ASTCENC_PRF_HDR:
+ config.tune_db_limit = 999.0f;
+ break;
+ default:
+ return ASTCENC_ERR_BAD_PROFILE;
+ }
+
+ // Flags field must not contain any unknown flag bits
+ status = validate_flags(flags);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ if (flags & ASTCENC_FLG_MAP_NORMAL)
+ {
+ // Normal map encoding uses L+A blocks, so allow one more partitioning
+ // than normal. We need need fewer bits for endpoints, so more likely
+ // to be able to use more partitions than an RGB/RGBA block
+ config.tune_partition_count_limit = astc::min(config.tune_partition_count_limit + 1u, 4u);
+
+ config.cw_g_weight = 0.0f;
+ config.cw_b_weight = 0.0f;
+ config.tune_2_partition_early_out_limit_factor *= 1.5f;
+ config.tune_3_partition_early_out_limit_factor *= 1.5f;
+ config.tune_2_plane_early_out_limit_correlation = 0.99f;
+
+ // Normals are prone to blocking artifacts on smooth curves
+ // so force compressor to try harder here ...
+ config.tune_db_limit *= 1.03f;
+ }
+ else if (flags & ASTCENC_FLG_MAP_RGBM)
+ {
+ config.rgbm_m_scale = 5.0f;
+ config.cw_a_weight = 2.0f * config.rgbm_m_scale;
+ }
+ else // (This is color data)
+ {
+ // This is a very basic perceptual metric for RGB color data, which weights error
+ // significance by the perceptual luminance contribution of each color channel. For
+ // luminance the usual weights to compute luminance from a linear RGB value are as
+ // follows:
+ //
+ // l = r * 0.3 + g * 0.59 + b * 0.11
+ //
+ // ... but we scale these up to keep a better balance between color and alpha. Note
+ // that if the content is using alpha we'd recommend using the -a option to weight
+ // the color contribution by the alpha transparency.
+ if (flags & ASTCENC_FLG_USE_PERCEPTUAL)
+ {
+ config.cw_r_weight = 0.30f * 2.25f;
+ config.cw_g_weight = 0.59f * 2.25f;
+ config.cw_b_weight = 0.11f * 2.25f;
+ }
+ }
+ config.flags = flags;
+
+ return ASTCENC_SUCCESS;
+}
+
+/* See header for documentation. */
+astcenc_error astcenc_context_alloc(
+ const astcenc_config* configp,
+ unsigned int thread_count,
+ astcenc_context** context
+) {
+ astcenc_error status;
+ const astcenc_config& config = *configp;
+
+ status = validate_cpu_isa();
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ status = validate_cpu_float();
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ if (thread_count == 0)
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+
+#if defined(ASTCENC_DIAGNOSTICS)
+ // Force single threaded compressor use in diagnostic mode.
+ if (thread_count != 1)
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+#endif
+
+ astcenc_context* ctxo = new astcenc_context;
+ astcenc_contexti* ctx = &ctxo->context;
+ ctx->thread_count = thread_count;
+ ctx->config = config;
+ ctx->working_buffers = nullptr;
+
+ // These are allocated per-compress, as they depend on image size
+ ctx->input_alpha_averages = nullptr;
+
+ // Copy the config first and validate the copy (we may modify it)
+ status = validate_config(ctx->config);
+ if (status != ASTCENC_SUCCESS)
+ {
+ delete ctxo;
+ return status;
+ }
+
+ ctx->bsd = aligned_malloc<block_size_descriptor>(sizeof(block_size_descriptor), ASTCENC_VECALIGN);
+ bool can_omit_modes = static_cast<bool>(config.flags & ASTCENC_FLG_SELF_DECOMPRESS_ONLY);
+ init_block_size_descriptor(config.block_x, config.block_y, config.block_z,
+ can_omit_modes,
+ config.tune_partition_count_limit,
+ static_cast<float>(config.tune_block_mode_limit) / 100.0f,
+ *ctx->bsd);
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+ // Do setup only needed by compression
+ if (!(status & ASTCENC_FLG_DECOMPRESS_ONLY))
+ {
+ // Turn a dB limit into a per-texel error for faster use later
+ if ((ctx->config.profile == ASTCENC_PRF_LDR) || (ctx->config.profile == ASTCENC_PRF_LDR_SRGB))
+ {
+ ctx->config.tune_db_limit = astc::pow(0.1f, ctx->config.tune_db_limit * 0.1f) * 65535.0f * 65535.0f;
+ }
+ else
+ {
+ ctx->config.tune_db_limit = 0.0f;
+ }
+
+ size_t worksize = sizeof(compression_working_buffers) * thread_count;
+ ctx->working_buffers = aligned_malloc<compression_working_buffers>(worksize, ASTCENC_VECALIGN);
+ static_assert((sizeof(compression_working_buffers) % ASTCENC_VECALIGN) == 0,
+ "compression_working_buffers size must be multiple of vector alignment");
+ if (!ctx->working_buffers)
+ {
+ aligned_free<block_size_descriptor>(ctx->bsd);
+ delete ctxo;
+ *context = nullptr;
+ return ASTCENC_ERR_OUT_OF_MEM;
+ }
+ }
+#endif
+
+#if defined(ASTCENC_DIAGNOSTICS)
+ ctx->trace_log = new TraceLog(ctx->config.trace_file_path);
+ if (!ctx->trace_log->m_file)
+ {
+ return ASTCENC_ERR_DTRACE_FAILURE;
+ }
+
+ trace_add_data("block_x", config.block_x);
+ trace_add_data("block_y", config.block_y);
+ trace_add_data("block_z", config.block_z);
+#endif
+
+ *context = ctxo;
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+ prepare_angular_tables();
+#endif
+
+ return ASTCENC_SUCCESS;
+}
+
+/* See header dor documentation. */
+void astcenc_context_free(
+ astcenc_context* ctxo
+) {
+ if (ctxo)
+ {
+ astcenc_contexti* ctx = &ctxo->context;
+ aligned_free<compression_working_buffers>(ctx->working_buffers);
+ aligned_free<block_size_descriptor>(ctx->bsd);
+#if defined(ASTCENC_DIAGNOSTICS)
+ delete ctx->trace_log;
+#endif
+ delete ctxo;
+ }
+}
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Compress an image, after any preflight has completed.
+ *
+ * @param[out] ctxo The compressor context.
+ * @param thread_index The thread index.
+ * @param image The intput image.
+ * @param swizzle The input swizzle.
+ * @param[out] buffer The output array for the compressed data.
+ */
+static void compress_image(
+ astcenc_context& ctxo,
+ unsigned int thread_index,
+ const astcenc_image& image,
+ const astcenc_swizzle& swizzle,
+ uint8_t* buffer
+) {
+ astcenc_contexti& ctx = ctxo.context;
+ const block_size_descriptor& bsd = *ctx.bsd;
+ astcenc_profile decode_mode = ctx.config.profile;
+
+ image_block blk;
+
+ int block_x = bsd.xdim;
+ int block_y = bsd.ydim;
+ int block_z = bsd.zdim;
+ blk.texel_count = static_cast<uint8_t>(block_x * block_y * block_z);
+
+ int dim_x = image.dim_x;
+ int dim_y = image.dim_y;
+ int dim_z = image.dim_z;
+
+ int xblocks = (dim_x + block_x - 1) / block_x;
+ int yblocks = (dim_y + block_y - 1) / block_y;
+ int zblocks = (dim_z + block_z - 1) / block_z;
+ int block_count = zblocks * yblocks * xblocks;
+
+ int row_blocks = xblocks;
+ int plane_blocks = xblocks * yblocks;
+
+ // Populate the block channel weights
+ blk.channel_weight = vfloat4(ctx.config.cw_r_weight,
+ ctx.config.cw_g_weight,
+ ctx.config.cw_b_weight,
+ ctx.config.cw_a_weight);
+
+ // Use preallocated scratch buffer
+ auto& temp_buffers = ctx.working_buffers[thread_index];
+
+ // Only the first thread actually runs the initializer
+ ctxo.manage_compress.init(block_count);
+
+ // Determine if we can use an optimized load function
+ bool needs_swz = (swizzle.r != ASTCENC_SWZ_R) || (swizzle.g != ASTCENC_SWZ_G) ||
+ (swizzle.b != ASTCENC_SWZ_B) || (swizzle.a != ASTCENC_SWZ_A);
+
+ bool needs_hdr = (decode_mode == ASTCENC_PRF_HDR) ||
+ (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A);
+
+ bool use_fast_load = !needs_swz && !needs_hdr &&
+ block_z == 1 && image.data_type == ASTCENC_TYPE_U8;
+
+ auto load_func = load_image_block;
+ if (use_fast_load)
+ {
+ load_func = load_image_block_fast_ldr;
+ }
+
+ // All threads run this processing loop until there is no work remaining
+ while (true)
+ {
+ unsigned int count;
+ unsigned int base = ctxo.manage_compress.get_task_assignment(16, count);
+ if (!count)
+ {
+ break;
+ }
+
+ for (unsigned int i = base; i < base + count; i++)
+ {
+ // Decode i into x, y, z block indices
+ int z = i / plane_blocks;
+ unsigned int rem = i - (z * plane_blocks);
+ int y = rem / row_blocks;
+ int x = rem - (y * row_blocks);
+
+ // Test if we can apply some basic alpha-scale RDO
+ bool use_full_block = true;
+ if (ctx.config.a_scale_radius != 0 && block_z == 1)
+ {
+ int start_x = x * block_x;
+ int end_x = astc::min(dim_x, start_x + block_x);
+
+ int start_y = y * block_y;
+ int end_y = astc::min(dim_y, start_y + block_y);
+
+ // SATs accumulate error, so don't test exactly zero. Test for
+ // less than 1 alpha in the expanded block footprint that
+ // includes the alpha radius.
+ int x_footprint = block_x + 2 * (ctx.config.a_scale_radius - 1);
+
+ int y_footprint = block_y + 2 * (ctx.config.a_scale_radius - 1);
+
+ float footprint = static_cast<float>(x_footprint * y_footprint);
+ float threshold = 0.9f / (255.0f * footprint);
+
+ // Do we have any alpha values?
+ use_full_block = false;
+ for (int ay = start_y; ay < end_y; ay++)
+ {
+ for (int ax = start_x; ax < end_x; ax++)
+ {
+ float a_avg = ctx.input_alpha_averages[ay * dim_x + ax];
+ if (a_avg > threshold)
+ {
+ use_full_block = true;
+ ax = end_x;
+ ay = end_y;
+ }
+ }
+ }
+ }
+
+ // Fetch the full block for compression
+ if (use_full_block)
+ {
+ load_func(decode_mode, image, blk, bsd, x * block_x, y * block_y, z * block_z, swizzle);
+
+ // Scale RGB error contribution by the maximum alpha in the block
+ // This encourages preserving alpha accuracy in regions with high
+ // transparency, and can buy up to 0.5 dB PSNR.
+ if (ctx.config.flags & ASTCENC_FLG_USE_ALPHA_WEIGHT)
+ {
+ float alpha_scale = blk.data_max.lane<3>() * (1.0f / 65535.0f);
+ blk.channel_weight = vfloat4(ctx.config.cw_r_weight * alpha_scale,
+ ctx.config.cw_g_weight * alpha_scale,
+ ctx.config.cw_b_weight * alpha_scale,
+ ctx.config.cw_a_weight);
+ }
+ }
+ // Apply alpha scale RDO - substitute constant color block
+ else
+ {
+ blk.origin_texel = vfloat4::zero();
+ blk.data_min = vfloat4::zero();
+ blk.data_mean = vfloat4::zero();
+ blk.data_max = vfloat4::zero();
+ blk.grayscale = true;
+ }
+
+ int offset = ((z * yblocks + y) * xblocks + x) * 16;
+ uint8_t *bp = buffer + offset;
+ physical_compressed_block* pcb = reinterpret_cast<physical_compressed_block*>(bp);
+ compress_block(ctx, blk, *pcb, temp_buffers);
+ }
+
+ ctxo.manage_compress.complete_task_assignment(count);
+ }
+}
+
+/**
+ * @brief Compute regional averages in an image.
+ *
+ * This function can be called by multiple threads, but only after a single
+ * thread calls the setup function @c init_compute_averages().
+ *
+ * Results are written back into @c img->input_alpha_averages.
+ *
+ * @param[out] ctx The context.
+ * @param ag The average and variance arguments created during setup.
+ */
+static void compute_averages(
+ astcenc_context& ctx,
+ const avg_args &ag
+) {
+ pixel_region_args arg = ag.arg;
+ arg.work_memory = new vfloat4[ag.work_memory_size];
+
+ int size_x = ag.img_size_x;
+ int size_y = ag.img_size_y;
+ int size_z = ag.img_size_z;
+
+ int step_xy = ag.blk_size_xy;
+ int step_z = ag.blk_size_z;
+
+ int y_tasks = (size_y + step_xy - 1) / step_xy;
+
+ // All threads run this processing loop until there is no work remaining
+ while (true)
+ {
+ unsigned int count;
+ unsigned int base = ctx.manage_avg.get_task_assignment(16, count);
+ if (!count)
+ {
+ break;
+ }
+
+ for (unsigned int i = base; i < base + count; i++)
+ {
+ int z = (i / (y_tasks)) * step_z;
+ int y = (i - (z * y_tasks)) * step_xy;
+
+ arg.size_z = astc::min(step_z, size_z - z);
+ arg.offset_z = z;
+
+ arg.size_y = astc::min(step_xy, size_y - y);
+ arg.offset_y = y;
+
+ for (int x = 0; x < size_x; x += step_xy)
+ {
+ arg.size_x = astc::min(step_xy, size_x - x);
+ arg.offset_x = x;
+ compute_pixel_region_variance(ctx.context, arg);
+ }
+ }
+
+ ctx.manage_avg.complete_task_assignment(count);
+ }
+
+ delete[] arg.work_memory;
+}
+
+#endif
+
+/* See header for documentation. */
+astcenc_error astcenc_compress_image(
+ astcenc_context* ctxo,
+ astcenc_image* imagep,
+ const astcenc_swizzle* swizzle,
+ uint8_t* data_out,
+ size_t data_len,
+ unsigned int thread_index
+) {
+#if defined(ASTCENC_DECOMPRESS_ONLY)
+ (void)ctxo;
+ (void)imagep;
+ (void)swizzle;
+ (void)data_out;
+ (void)data_len;
+ (void)thread_index;
+ return ASTCENC_ERR_BAD_CONTEXT;
+#else
+ astcenc_contexti* ctx = &ctxo->context;
+ astcenc_error status;
+ astcenc_image& image = *imagep;
+
+ if (ctx->config.flags & ASTCENC_FLG_DECOMPRESS_ONLY)
+ {
+ return ASTCENC_ERR_BAD_CONTEXT;
+ }
+
+ status = validate_compression_swizzle(*swizzle);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ if (thread_index >= ctx->thread_count)
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+
+ unsigned int block_x = ctx->config.block_x;
+ unsigned int block_y = ctx->config.block_y;
+ unsigned int block_z = ctx->config.block_z;
+
+ unsigned int xblocks = (image.dim_x + block_x - 1) / block_x;
+ unsigned int yblocks = (image.dim_y + block_y - 1) / block_y;
+ unsigned int zblocks = (image.dim_z + block_z - 1) / block_z;
+
+ // Check we have enough output space (16 bytes per block)
+ size_t size_needed = xblocks * yblocks * zblocks * 16;
+ if (data_len < size_needed)
+ {
+ return ASTCENC_ERR_OUT_OF_MEM;
+ }
+
+ // If context thread count is one then implicitly reset
+ if (ctx->thread_count == 1)
+ {
+ astcenc_compress_reset(ctxo);
+ }
+
+ if (ctx->config.a_scale_radius != 0)
+ {
+ // First thread to enter will do setup, other threads will subsequently
+ // enter the critical section but simply skip over the initialization
+ auto init_avg = [ctx, &image, swizzle]() {
+ // Perform memory allocations for the destination buffers
+ size_t texel_count = image.dim_x * image.dim_y * image.dim_z;
+ ctx->input_alpha_averages = new float[texel_count];
+
+ return init_compute_averages(
+ image, ctx->config.a_scale_radius, *swizzle,
+ ctx->avg_preprocess_args);
+ };
+
+ // Only the first thread actually runs the initializer
+ ctxo->manage_avg.init(init_avg);
+
+ // All threads will enter this function and dynamically grab work
+ compute_averages(*ctxo, ctx->avg_preprocess_args);
+ }
+
+ // Wait for compute_averages to complete before compressing
+ ctxo->manage_avg.wait();
+
+ compress_image(*ctxo, thread_index, image, *swizzle, data_out);
+
+ // Wait for compress to complete before freeing memory
+ ctxo->manage_compress.wait();
+
+ auto term_compress = [ctx]() {
+ delete[] ctx->input_alpha_averages;
+ ctx->input_alpha_averages = nullptr;
+ };
+
+ // Only the first thread to arrive actually runs the term
+ ctxo->manage_compress.term(term_compress);
+
+ return ASTCENC_SUCCESS;
+#endif
+}
+
+/* See header for documentation. */
+astcenc_error astcenc_compress_reset(
+ astcenc_context* ctxo
+) {
+#if defined(ASTCENC_DECOMPRESS_ONLY)
+ (void)ctxo;
+ return ASTCENC_ERR_BAD_CONTEXT;
+#else
+ astcenc_contexti* ctx = &ctxo->context;
+ if (ctx->config.flags & ASTCENC_FLG_DECOMPRESS_ONLY)
+ {
+ return ASTCENC_ERR_BAD_CONTEXT;
+ }
+
+ ctxo->manage_avg.reset();
+ ctxo->manage_compress.reset();
+ return ASTCENC_SUCCESS;
+#endif
+}
+
+/* See header for documentation. */
+astcenc_error astcenc_decompress_image(
+ astcenc_context* ctxo,
+ const uint8_t* data,
+ size_t data_len,
+ astcenc_image* image_outp,
+ const astcenc_swizzle* swizzle,
+ unsigned int thread_index
+) {
+ astcenc_error status;
+ astcenc_image& image_out = *image_outp;
+ astcenc_contexti* ctx = &ctxo->context;
+
+ // Today this doesn't matter (working set on stack) but might in future ...
+ if (thread_index >= ctx->thread_count)
+ {
+ return ASTCENC_ERR_BAD_PARAM;
+ }
+
+ status = validate_decompression_swizzle(*swizzle);
+ if (status != ASTCENC_SUCCESS)
+ {
+ return status;
+ }
+
+ unsigned int block_x = ctx->config.block_x;
+ unsigned int block_y = ctx->config.block_y;
+ unsigned int block_z = ctx->config.block_z;
+
+ unsigned int xblocks = (image_out.dim_x + block_x - 1) / block_x;
+ unsigned int yblocks = (image_out.dim_y + block_y - 1) / block_y;
+ unsigned int zblocks = (image_out.dim_z + block_z - 1) / block_z;
+
+ int row_blocks = xblocks;
+ int plane_blocks = xblocks * yblocks;
+
+ // Check we have enough output space (16 bytes per block)
+ size_t size_needed = xblocks * yblocks * zblocks * 16;
+ if (data_len < size_needed)
+ {
+ return ASTCENC_ERR_OUT_OF_MEM;
+ }
+
+ image_block blk;
+ blk.texel_count = static_cast<uint8_t>(block_x * block_y * block_z);
+
+ // If context thread count is one then implicitly reset
+ if (ctx->thread_count == 1)
+ {
+ astcenc_decompress_reset(ctxo);
+ }
+
+ // Only the first thread actually runs the initializer
+ ctxo->manage_decompress.init(zblocks * yblocks * xblocks);
+
+ // All threads run this processing loop until there is no work remaining
+ while (true)
+ {
+ unsigned int count;
+ unsigned int base = ctxo->manage_decompress.get_task_assignment(128, count);
+ if (!count)
+ {
+ break;
+ }
+
+ for (unsigned int i = base; i < base + count; i++)
+ {
+ // Decode i into x, y, z block indices
+ int z = i / plane_blocks;
+ unsigned int rem = i - (z * plane_blocks);
+ int y = rem / row_blocks;
+ int x = rem - (y * row_blocks);
+
+ unsigned int offset = (((z * yblocks + y) * xblocks) + x) * 16;
+ const uint8_t* bp = data + offset;
+
+ const physical_compressed_block& pcb = *reinterpret_cast<const physical_compressed_block*>(bp);
+ symbolic_compressed_block scb;
+
+ physical_to_symbolic(*ctx->bsd, pcb, scb);
+
+ decompress_symbolic_block(ctx->config.profile, *ctx->bsd,
+ x * block_x, y * block_y, z * block_z,
+ scb, blk);
+
+ store_image_block(image_out, blk, *ctx->bsd,
+ x * block_x, y * block_y, z * block_z, *swizzle);
+ }
+
+ ctxo->manage_decompress.complete_task_assignment(count);
+ }
+
+ return ASTCENC_SUCCESS;
+}
+
+/* See header for documentation. */
+astcenc_error astcenc_decompress_reset(
+ astcenc_context* ctxo
+) {
+ ctxo->manage_decompress.reset();
+ return ASTCENC_SUCCESS;
+}
+
+/* See header for documentation. */
+astcenc_error astcenc_get_block_info(
+ astcenc_context* ctxo,
+ const uint8_t data[16],
+ astcenc_block_info* info
+) {
+#if defined(ASTCENC_DECOMPRESS_ONLY)
+ (void)ctxo;
+ (void)data;
+ (void)info;
+ return ASTCENC_ERR_BAD_CONTEXT;
+#else
+ astcenc_contexti* ctx = &ctxo->context;
+
+ // Decode the compressed data into a symbolic form
+ const physical_compressed_block&pcb = *reinterpret_cast<const physical_compressed_block*>(data);
+ symbolic_compressed_block scb;
+ physical_to_symbolic(*ctx->bsd, pcb, scb);
+
+ // Fetch the appropriate partition and decimation tables
+ block_size_descriptor& bsd = *ctx->bsd;
+
+ // Start from a clean slate
+ memset(info, 0, sizeof(*info));
+
+ // Basic info we can always populate
+ info->profile = ctx->config.profile;
+
+ info->block_x = ctx->config.block_x;
+ info->block_y = ctx->config.block_y;
+ info->block_z = ctx->config.block_z;
+ info->texel_count = bsd.texel_count;
+
+ // Check for error blocks first
+ info->is_error_block = scb.block_type == SYM_BTYPE_ERROR;
+ if (info->is_error_block)
+ {
+ return ASTCENC_SUCCESS;
+ }
+
+ // Check for constant color blocks second
+ info->is_constant_block = scb.block_type == SYM_BTYPE_CONST_F16 ||
+ scb.block_type == SYM_BTYPE_CONST_U16;
+ if (info->is_constant_block)
+ {
+ return ASTCENC_SUCCESS;
+ }
+
+ // Otherwise handle a full block ; known to be valid after conditions above have been checked
+ int partition_count = scb.partition_count;
+ const auto& pi = bsd.get_partition_info(partition_count, scb.partition_index);
+
+ const block_mode& bm = bsd.get_block_mode(scb.block_mode);
+ const decimation_info& di = bsd.get_decimation_info(bm.decimation_mode);
+
+ info->weight_x = di.weight_x;
+ info->weight_y = di.weight_y;
+ info->weight_z = di.weight_z;
+
+ info->is_dual_plane_block = bm.is_dual_plane != 0;
+
+ info->partition_count = scb.partition_count;
+ info->partition_index = scb.partition_index;
+ info->dual_plane_component = scb.plane2_component;
+
+ info->color_level_count = get_quant_level(scb.get_color_quant_mode());
+ info->weight_level_count = get_quant_level(bm.get_weight_quant_mode());
+
+ // Unpack color endpoints for each active partition
+ for (unsigned int i = 0; i < scb.partition_count; i++)
+ {
+ bool rgb_hdr;
+ bool a_hdr;
+ vint4 endpnt[2];
+
+ unpack_color_endpoints(ctx->config.profile,
+ scb.color_formats[i],
+ scb.color_values[i],
+ rgb_hdr, a_hdr,
+ endpnt[0], endpnt[1]);
+
+ // Store the color endpoint mode info
+ info->color_endpoint_modes[i] = scb.color_formats[i];
+ info->is_hdr_block = info->is_hdr_block || rgb_hdr || a_hdr;
+
+ // Store the unpacked and decoded color endpoint
+ vmask4 hdr_mask(rgb_hdr, rgb_hdr, rgb_hdr, a_hdr);
+ for (int j = 0; j < 2; j++)
+ {
+ vint4 color_lns = lns_to_sf16(endpnt[j]);
+ vint4 color_unorm = unorm16_to_sf16(endpnt[j]);
+ vint4 datai = select(color_unorm, color_lns, hdr_mask);
+ store(float16_to_float(datai), info->color_endpoints[i][j]);
+ }
+ }
+
+ // Unpack weights for each texel
+ int weight_plane1[BLOCK_MAX_TEXELS];
+ int weight_plane2[BLOCK_MAX_TEXELS];
+
+ unpack_weights(bsd, scb, di, bm.is_dual_plane, weight_plane1, weight_plane2);
+ for (unsigned int i = 0; i < bsd.texel_count; i++)
+ {
+ info->weight_values_plane1[i] = static_cast<float>(weight_plane1[i]) * (1.0f / WEIGHTS_TEXEL_SUM);
+ if (info->is_dual_plane_block)
+ {
+ info->weight_values_plane2[i] = static_cast<float>(weight_plane2[i]) * (1.0f / WEIGHTS_TEXEL_SUM);
+ }
+ }
+
+ // Unpack partition assignments for each texel
+ for (unsigned int i = 0; i < bsd.texel_count; i++)
+ {
+ info->partition_assignment[i] = pi.partition_of_texel[i];
+ }
+
+ return ASTCENC_SUCCESS;
+#endif
+}
+
+/* See header for documentation. */
+const char* astcenc_get_error_string(
+ astcenc_error status
+) {
+ // Values in this enum are from an external user, so not guaranteed to be
+ // bounded to the enum values
+ switch (static_cast<int>(status))
+ {
+ case ASTCENC_SUCCESS:
+ return "ASTCENC_SUCCESS";
+ case ASTCENC_ERR_OUT_OF_MEM:
+ return "ASTCENC_ERR_OUT_OF_MEM";
+ case ASTCENC_ERR_BAD_CPU_FLOAT:
+ return "ASTCENC_ERR_BAD_CPU_FLOAT";
+ case ASTCENC_ERR_BAD_CPU_ISA:
+ return "ASTCENC_ERR_BAD_CPU_ISA";
+ case ASTCENC_ERR_BAD_PARAM:
+ return "ASTCENC_ERR_BAD_PARAM";
+ case ASTCENC_ERR_BAD_BLOCK_SIZE:
+ return "ASTCENC_ERR_BAD_BLOCK_SIZE";
+ case ASTCENC_ERR_BAD_PROFILE:
+ return "ASTCENC_ERR_BAD_PROFILE";
+ case ASTCENC_ERR_BAD_QUALITY:
+ return "ASTCENC_ERR_BAD_QUALITY";
+ case ASTCENC_ERR_BAD_FLAGS:
+ return "ASTCENC_ERR_BAD_FLAGS";
+ case ASTCENC_ERR_BAD_SWIZZLE:
+ return "ASTCENC_ERR_BAD_SWIZZLE";
+ case ASTCENC_ERR_BAD_CONTEXT:
+ return "ASTCENC_ERR_BAD_CONTEXT";
+ case ASTCENC_ERR_NOT_IMPLEMENTED:
+ return "ASTCENC_ERR_NOT_IMPLEMENTED";
+#if defined(ASTCENC_DIAGNOSTICS)
+ case ASTCENC_ERR_DTRACE_FAILURE:
+ return "ASTCENC_ERR_DTRACE_FAILURE";
+#endif
+ default:
+ return nullptr;
+ }
+}
diff --git a/thirdparty/astcenc/astcenc_find_best_partitioning.cpp b/thirdparty/astcenc/astcenc_find_best_partitioning.cpp
new file mode 100644
index 0000000000..ffde3c7060
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_find_best_partitioning.cpp
@@ -0,0 +1,780 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Functions for finding best partition for a block.
+ *
+ * The partition search operates in two stages. The first pass uses kmeans clustering to group
+ * texels into an ideal partitioning for the requested partition count, and then compares that
+ * against the 1024 partitionings generated by the ASTC partition hash function. The generated
+ * partitions are then ranked by the number of texels in the wrong partition, compared to the ideal
+ * clustering. All 1024 partitions are tested for similarity and ranked, apart from duplicates and
+ * partitionings that actually generate fewer than the requested partition count, but only the top
+ * N candidates are actually put through a more detailed search. N is determined by the compressor
+ * quality preset.
+ *
+ * For the detailed search, each candidate is checked against two possible encoding methods:
+ *
+ * - The best partitioning assuming different chroma colors (RGB + RGB or RGB + delta endpoints).
+ * - The best partitioning assuming same chroma colors (RGB + scale endpoints).
+ *
+ * This is implemented by computing the compute mean color and dominant direction for each
+ * partition. This defines two lines, both of which go through the mean color value.
+ *
+ * - One line has a direction defined by the dominant direction; this is used to assess the error
+ * from using an uncorrelated color representation.
+ * - The other line goes through (0,0,0,1) and is used to assess the error from using a same chroma
+ * (RGB + scale) color representation.
+ *
+ * The best candidate is selected by computing the squared-errors that result from using these
+ * lines for endpoint selection.
+ */
+
+#include <limits>
+#include "astcenc_internal.h"
+
+/**
+ * @brief Pick some initial kmeans cluster centers.
+ *
+ * @param blk The image block color data to compress.
+ * @param texel_count The number of texels in the block.
+ * @param partition_count The number of partitions in the block.
+ * @param[out] cluster_centers The initial partition cluster center colors.
+ */
+static void kmeans_init(
+ const image_block& blk,
+ unsigned int texel_count,
+ unsigned int partition_count,
+ vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS]
+) {
+ promise(texel_count > 0);
+ promise(partition_count > 0);
+
+ unsigned int clusters_selected = 0;
+ float distances[BLOCK_MAX_TEXELS];
+
+ // Pick a random sample as first cluster center; 145897 from random.org
+ unsigned int sample = 145897 % texel_count;
+ vfloat4 center_color = blk.texel(sample);
+ cluster_centers[clusters_selected] = center_color;
+ clusters_selected++;
+
+ // Compute the distance to the first cluster center
+ float distance_sum = 0.0f;
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ vfloat4 color = blk.texel(i);
+ vfloat4 diff = color - center_color;
+ float distance = dot_s(diff * diff, blk.channel_weight);
+ distance_sum += distance;
+ distances[i] = distance;
+ }
+
+ // More numbers from random.org for weighted-random center selection
+ const float cluster_cutoffs[9] {
+ 0.626220f, 0.932770f, 0.275454f,
+ 0.318558f, 0.240113f, 0.009190f,
+ 0.347661f, 0.731960f, 0.156391f
+ };
+
+ unsigned int cutoff = (clusters_selected - 1) + 3 * (partition_count - 2);
+
+ // Pick the remaining samples as needed
+ while (true)
+ {
+ // Pick the next center in a weighted-random fashion.
+ float summa = 0.0f;
+ float distance_cutoff = distance_sum * cluster_cutoffs[cutoff++];
+ for (sample = 0; sample < texel_count; sample++)
+ {
+ summa += distances[sample];
+ if (summa >= distance_cutoff)
+ {
+ break;
+ }
+ }
+
+ // Clamp to a valid range and store the selected cluster center
+ sample = astc::min(sample, texel_count - 1);
+
+ center_color = blk.texel(sample);
+ cluster_centers[clusters_selected++] = center_color;
+ if (clusters_selected >= partition_count)
+ {
+ break;
+ }
+
+ // Compute the distance to the new cluster center, keep the min dist
+ distance_sum = 0.0f;
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ vfloat4 color = blk.texel(i);
+ vfloat4 diff = color - center_color;
+ float distance = dot_s(diff * diff, blk.channel_weight);
+ distance = astc::min(distance, distances[i]);
+ distance_sum += distance;
+ distances[i] = distance;
+ }
+ }
+}
+
+/**
+ * @brief Assign texels to clusters, based on a set of chosen center points.
+ *
+ * @param blk The image block color data to compress.
+ * @param texel_count The number of texels in the block.
+ * @param partition_count The number of partitions in the block.
+ * @param cluster_centers The partition cluster center colors.
+ * @param[out] partition_of_texel The partition assigned for each texel.
+ */
+static void kmeans_assign(
+ const image_block& blk,
+ unsigned int texel_count,
+ unsigned int partition_count,
+ const vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS],
+ uint8_t partition_of_texel[BLOCK_MAX_TEXELS]
+) {
+ promise(texel_count > 0);
+ promise(partition_count > 0);
+
+ uint8_t partition_texel_count[BLOCK_MAX_PARTITIONS] { 0 };
+
+ // Find the best partition for every texel
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ float best_distance = std::numeric_limits<float>::max();
+ unsigned int best_partition = 0;
+
+ vfloat4 color = blk.texel(i);
+ for (unsigned int j = 0; j < partition_count; j++)
+ {
+ vfloat4 diff = color - cluster_centers[j];
+ float distance = dot_s(diff * diff, blk.channel_weight);
+ if (distance < best_distance)
+ {
+ best_distance = distance;
+ best_partition = j;
+ }
+ }
+
+ partition_of_texel[i] = static_cast<uint8_t>(best_partition);
+ partition_texel_count[best_partition]++;
+ }
+
+ // It is possible to get a situation where a partition ends up without any texels. In this case,
+ // assign texel N to partition N. This is silly, but ensures that every partition retains at
+ // least one texel. Reassigning a texel in this manner may cause another partition to go empty,
+ // so if we actually did a reassignment, run the whole loop over again.
+ bool problem_case;
+ do
+ {
+ problem_case = false;
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ if (partition_texel_count[i] == 0)
+ {
+ partition_texel_count[partition_of_texel[i]]--;
+ partition_texel_count[i]++;
+ partition_of_texel[i] = static_cast<uint8_t>(i);
+ problem_case = true;
+ }
+ }
+ } while (problem_case);
+}
+
+/**
+ * @brief Compute new cluster centers based on their center of gravity.
+ *
+ * @param blk The image block color data to compress.
+ * @param texel_count The number of texels in the block.
+ * @param partition_count The number of partitions in the block.
+ * @param[out] cluster_centers The new cluster center colors.
+ * @param partition_of_texel The partition assigned for each texel.
+ */
+static void kmeans_update(
+ const image_block& blk,
+ unsigned int texel_count,
+ unsigned int partition_count,
+ vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS],
+ const uint8_t partition_of_texel[BLOCK_MAX_TEXELS]
+) {
+ promise(texel_count > 0);
+ promise(partition_count > 0);
+
+ vfloat4 color_sum[BLOCK_MAX_PARTITIONS] {
+ vfloat4::zero(),
+ vfloat4::zero(),
+ vfloat4::zero(),
+ vfloat4::zero()
+ };
+
+ uint8_t partition_texel_count[BLOCK_MAX_PARTITIONS] { 0 };
+
+ // Find the center-of-gravity in each cluster
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ uint8_t partition = partition_of_texel[i];
+ color_sum[partition] += blk.texel(i);
+ partition_texel_count[partition]++;
+ }
+
+ // Set the center of gravity to be the new cluster center
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ float scale = 1.0f / static_cast<float>(partition_texel_count[i]);
+ cluster_centers[i] = color_sum[i] * scale;
+ }
+}
+
+/**
+ * @brief Compute bit-mismatch for partitioning in 2-partition mode.
+ *
+ * @param a The texel assignment bitvector for the block.
+ * @param b The texel assignment bitvector for the partition table.
+ *
+ * @return The number of bit mismatches.
+ */
+static inline unsigned int partition_mismatch2(
+ const uint64_t a[2],
+ const uint64_t b[2]
+) {
+ int v1 = popcount(a[0] ^ b[0]) + popcount(a[1] ^ b[1]);
+ int v2 = popcount(a[0] ^ b[1]) + popcount(a[1] ^ b[0]);
+ return astc::min(v1, v2);
+}
+
+/**
+ * @brief Compute bit-mismatch for partitioning in 3-partition mode.
+ *
+ * @param a The texel assignment bitvector for the block.
+ * @param b The texel assignment bitvector for the partition table.
+ *
+ * @return The number of bit mismatches.
+ */
+static inline unsigned int partition_mismatch3(
+ const uint64_t a[3],
+ const uint64_t b[3]
+) {
+ int p00 = popcount(a[0] ^ b[0]);
+ int p01 = popcount(a[0] ^ b[1]);
+ int p02 = popcount(a[0] ^ b[2]);
+
+ int p10 = popcount(a[1] ^ b[0]);
+ int p11 = popcount(a[1] ^ b[1]);
+ int p12 = popcount(a[1] ^ b[2]);
+
+ int p20 = popcount(a[2] ^ b[0]);
+ int p21 = popcount(a[2] ^ b[1]);
+ int p22 = popcount(a[2] ^ b[2]);
+
+ int s0 = p11 + p22;
+ int s1 = p12 + p21;
+ int v0 = astc::min(s0, s1) + p00;
+
+ int s2 = p10 + p22;
+ int s3 = p12 + p20;
+ int v1 = astc::min(s2, s3) + p01;
+
+ int s4 = p10 + p21;
+ int s5 = p11 + p20;
+ int v2 = astc::min(s4, s5) + p02;
+
+ return astc::min(v0, v1, v2);
+}
+
+/**
+ * @brief Compute bit-mismatch for partitioning in 4-partition mode.
+ *
+ * @param a The texel assignment bitvector for the block.
+ * @param b The texel assignment bitvector for the partition table.
+ *
+ * @return The number of bit mismatches.
+ */
+static inline unsigned int partition_mismatch4(
+ const uint64_t a[4],
+ const uint64_t b[4]
+) {
+ int p00 = popcount(a[0] ^ b[0]);
+ int p01 = popcount(a[0] ^ b[1]);
+ int p02 = popcount(a[0] ^ b[2]);
+ int p03 = popcount(a[0] ^ b[3]);
+
+ int p10 = popcount(a[1] ^ b[0]);
+ int p11 = popcount(a[1] ^ b[1]);
+ int p12 = popcount(a[1] ^ b[2]);
+ int p13 = popcount(a[1] ^ b[3]);
+
+ int p20 = popcount(a[2] ^ b[0]);
+ int p21 = popcount(a[2] ^ b[1]);
+ int p22 = popcount(a[2] ^ b[2]);
+ int p23 = popcount(a[2] ^ b[3]);
+
+ int p30 = popcount(a[3] ^ b[0]);
+ int p31 = popcount(a[3] ^ b[1]);
+ int p32 = popcount(a[3] ^ b[2]);
+ int p33 = popcount(a[3] ^ b[3]);
+
+ int mx23 = astc::min(p22 + p33, p23 + p32);
+ int mx13 = astc::min(p21 + p33, p23 + p31);
+ int mx12 = astc::min(p21 + p32, p22 + p31);
+ int mx03 = astc::min(p20 + p33, p23 + p30);
+ int mx02 = astc::min(p20 + p32, p22 + p30);
+ int mx01 = astc::min(p21 + p30, p20 + p31);
+
+ int v0 = p00 + astc::min(p11 + mx23, p12 + mx13, p13 + mx12);
+ int v1 = p01 + astc::min(p10 + mx23, p12 + mx03, p13 + mx02);
+ int v2 = p02 + astc::min(p11 + mx03, p10 + mx13, p13 + mx01);
+ int v3 = p03 + astc::min(p11 + mx02, p12 + mx01, p10 + mx12);
+
+ return astc::min(v0, v1, v2, v3);
+}
+
+using mismatch_dispatch = unsigned int (*)(const uint64_t*, const uint64_t*);
+
+/**
+ * @brief Count the partition table mismatches vs the data clustering.
+ *
+ * @param bsd The block size information.
+ * @param partition_count The number of partitions in the block.
+ * @param bitmaps The block texel partition assignment patterns.
+ * @param[out] mismatch_counts The array storing per partitioning mismatch counts.
+ */
+static void count_partition_mismatch_bits(
+ const block_size_descriptor& bsd,
+ unsigned int partition_count,
+ const uint64_t bitmaps[BLOCK_MAX_PARTITIONS],
+ unsigned int mismatch_counts[BLOCK_MAX_PARTITIONINGS]
+) {
+ unsigned int active_count = bsd.partitioning_count_selected[partition_count - 1];
+ promise(active_count > 0);
+
+ if (partition_count == 2)
+ {
+ for (unsigned int i = 0; i < active_count; i++)
+ {
+ mismatch_counts[i] = partition_mismatch2(bitmaps, bsd.coverage_bitmaps_2[i]);
+ }
+ }
+ else if (partition_count == 3)
+ {
+ for (unsigned int i = 0; i < active_count; i++)
+ {
+ mismatch_counts[i] = partition_mismatch3(bitmaps, bsd.coverage_bitmaps_3[i]);
+ }
+ }
+ else
+ {
+ for (unsigned int i = 0; i < active_count; i++)
+ {
+ mismatch_counts[i] = partition_mismatch4(bitmaps, bsd.coverage_bitmaps_4[i]);
+ }
+ }
+}
+
+/**
+ * @brief Use counting sort on the mismatch array to sort partition candidates.
+ *
+ * @param partitioning_count The number of packed partitionings.
+ * @param mismatch_count Partitioning mismatch counts, in index order.
+ * @param[out] partition_ordering Partition index values, in mismatch order.
+ *
+ * @return The number of active partitions in this selection.
+ */
+static unsigned int get_partition_ordering_by_mismatch_bits(
+ unsigned int partitioning_count,
+ const unsigned int mismatch_count[BLOCK_MAX_PARTITIONINGS],
+ unsigned int partition_ordering[BLOCK_MAX_PARTITIONINGS]
+) {
+ promise(partitioning_count > 0);
+ unsigned int mscount[256] { 0 };
+
+ // Create the histogram of mismatch counts
+ for (unsigned int i = 0; i < partitioning_count; i++)
+ {
+ mscount[mismatch_count[i]]++;
+ }
+
+ unsigned int active_count = partitioning_count - mscount[255];
+
+ // Create a running sum from the histogram array
+ // Cells store previous values only; i.e. exclude self after sum
+ unsigned int summa = 0;
+ for (unsigned int i = 0; i < 256; i++)
+ {
+ unsigned int cnt = mscount[i];
+ mscount[i] = summa;
+ summa += cnt;
+ }
+
+ // Use the running sum as the index, incrementing after read to allow
+ // sequential entries with the same count
+ for (unsigned int i = 0; i < partitioning_count; i++)
+ {
+ unsigned int idx = mscount[mismatch_count[i]]++;
+ partition_ordering[idx] = i;
+ }
+
+ return active_count;
+}
+
+/**
+ * @brief Use k-means clustering to compute a partition ordering for a block..
+ *
+ * @param bsd The block size information.
+ * @param blk The image block color data to compress.
+ * @param partition_count The desired number of partitions in the block.
+ * @param[out] partition_ordering The list of recommended partition indices, in priority order.
+ *
+ * @return The number of active partitionings in this selection.
+ */
+static unsigned int compute_kmeans_partition_ordering(
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ unsigned int partition_count,
+ unsigned int partition_ordering[BLOCK_MAX_PARTITIONINGS]
+) {
+ vfloat4 cluster_centers[BLOCK_MAX_PARTITIONS];
+ uint8_t texel_partitions[BLOCK_MAX_TEXELS];
+
+ // Use three passes of k-means clustering to partition the block data
+ for (unsigned int i = 0; i < 3; i++)
+ {
+ if (i == 0)
+ {
+ kmeans_init(blk, bsd.texel_count, partition_count, cluster_centers);
+ }
+ else
+ {
+ kmeans_update(blk, bsd.texel_count, partition_count, cluster_centers, texel_partitions);
+ }
+
+ kmeans_assign(blk, bsd.texel_count, partition_count, cluster_centers, texel_partitions);
+ }
+
+ // Construct the block bitmaps of texel assignments to each partition
+ uint64_t bitmaps[BLOCK_MAX_PARTITIONS] { 0 };
+ unsigned int texels_to_process = astc::min(bsd.texel_count, BLOCK_MAX_KMEANS_TEXELS);
+ promise(texels_to_process > 0);
+ for (unsigned int i = 0; i < texels_to_process; i++)
+ {
+ unsigned int idx = bsd.kmeans_texels[i];
+ bitmaps[texel_partitions[idx]] |= 1ULL << i;
+ }
+
+ // Count the mismatch between the block and the format's partition tables
+ unsigned int mismatch_counts[BLOCK_MAX_PARTITIONINGS];
+ count_partition_mismatch_bits(bsd, partition_count, bitmaps, mismatch_counts);
+
+ // Sort the partitions based on the number of mismatched bits
+ return get_partition_ordering_by_mismatch_bits(
+ bsd.partitioning_count_selected[partition_count - 1],
+ mismatch_counts, partition_ordering);
+}
+
+/**
+ * @brief Insert a partitioning into an order list of results, sorted by error.
+ *
+ * @param max_values The max number of entries in the best result arrays.
+ * @param this_error The error of the new entry.
+ * @param this_partition The partition ID of the new entry.
+ * @param[out] best_errors The array of best error values.
+ * @param[out] best_partitions The array of best partition values.
+ */
+static void insert_result(
+ unsigned int max_values,
+ float this_error,
+ unsigned int this_partition,
+ float* best_errors,
+ unsigned int* best_partitions)
+{
+ promise(max_values > 0);
+
+ // Don't bother searching if the current worst error beats the new error
+ if (this_error >= best_errors[max_values - 1])
+ {
+ return;
+ }
+
+ // Else insert into the list in error-order
+ for (unsigned int i = 0; i < max_values; i++)
+ {
+ // Existing result is better - move on ...
+ if (this_error > best_errors[i])
+ {
+ continue;
+ }
+
+ // Move existing results down one
+ for (unsigned int j = max_values - 1; j > i; j--)
+ {
+ best_errors[j] = best_errors[j - 1];
+ best_partitions[j] = best_partitions[j - 1];
+ }
+
+ // Insert new result
+ best_errors[i] = this_error;
+ best_partitions[i] = this_partition;
+ break;
+ }
+}
+
+/* See header for documentation. */
+unsigned int find_best_partition_candidates(
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ unsigned int partition_count,
+ unsigned int partition_search_limit,
+ unsigned int best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES],
+ unsigned int requested_candidates
+) {
+ // Constant used to estimate quantization error for a given partitioning; the optimal value for
+ // this depends on bitrate. These values have been determined empirically.
+ unsigned int texels_per_block = bsd.texel_count;
+ float weight_imprecision_estim = 0.055f;
+ if (texels_per_block <= 20)
+ {
+ weight_imprecision_estim = 0.03f;
+ }
+ else if (texels_per_block <= 31)
+ {
+ weight_imprecision_estim = 0.04f;
+ }
+ else if (texels_per_block <= 41)
+ {
+ weight_imprecision_estim = 0.05f;
+ }
+
+ promise(partition_count > 0);
+ promise(partition_search_limit > 0);
+
+ weight_imprecision_estim = weight_imprecision_estim * weight_imprecision_estim;
+
+ unsigned int partition_sequence[BLOCK_MAX_PARTITIONINGS];
+ unsigned int sequence_len = compute_kmeans_partition_ordering(bsd, blk, partition_count, partition_sequence);
+ partition_search_limit = astc::min(partition_search_limit, sequence_len);
+ requested_candidates = astc::min(partition_search_limit, requested_candidates);
+
+ bool uses_alpha = !blk.is_constant_channel(3);
+
+ // Partitioning errors assuming uncorrelated-chrominance endpoints
+ float uncor_best_errors[TUNE_MAX_PARTITIONING_CANDIDATES];
+ unsigned int uncor_best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES];
+
+ // Partitioning errors assuming same-chrominance endpoints
+ float samec_best_errors[TUNE_MAX_PARTITIONING_CANDIDATES];
+ unsigned int samec_best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES];
+
+ for (unsigned int i = 0; i < requested_candidates; i++)
+ {
+ uncor_best_errors[i] = ERROR_CALC_DEFAULT;
+ samec_best_errors[i] = ERROR_CALC_DEFAULT;
+ }
+
+ if (uses_alpha)
+ {
+ for (unsigned int i = 0; i < partition_search_limit; i++)
+ {
+ unsigned int partition = partition_sequence[i];
+ const auto& pi = bsd.get_raw_partition_info(partition_count, partition);
+
+ // Compute weighting to give to each component in each partition
+ partition_metrics pms[BLOCK_MAX_PARTITIONS];
+
+ compute_avgs_and_dirs_4_comp(pi, blk, pms);
+
+ line4 uncor_lines[BLOCK_MAX_PARTITIONS];
+ line4 samec_lines[BLOCK_MAX_PARTITIONS];
+
+ processed_line4 uncor_plines[BLOCK_MAX_PARTITIONS];
+ processed_line4 samec_plines[BLOCK_MAX_PARTITIONS];
+
+ float uncor_line_lens[BLOCK_MAX_PARTITIONS];
+ float samec_line_lens[BLOCK_MAX_PARTITIONS];
+
+ for (unsigned int j = 0; j < partition_count; j++)
+ {
+ partition_metrics& pm = pms[j];
+
+ uncor_lines[j].a = pm.avg;
+ uncor_lines[j].b = normalize_safe(pm.dir, unit4());
+
+ uncor_plines[j].amod = uncor_lines[j].a - uncor_lines[j].b * dot(uncor_lines[j].a, uncor_lines[j].b);
+ uncor_plines[j].bs = uncor_lines[j].b;
+
+ samec_lines[j].a = vfloat4::zero();
+ samec_lines[j].b = normalize_safe(pm.avg, unit4());
+
+ samec_plines[j].amod = vfloat4::zero();
+ samec_plines[j].bs = samec_lines[j].b;
+ }
+
+ float uncor_error = 0.0f;
+ float samec_error = 0.0f;
+
+ compute_error_squared_rgba(pi,
+ blk,
+ uncor_plines,
+ samec_plines,
+ uncor_line_lens,
+ samec_line_lens,
+ uncor_error,
+ samec_error);
+
+ // Compute an estimate of error introduced by weight quantization imprecision.
+ // This error is computed as follows, for each partition
+ // 1: compute the principal-axis vector (full length) in error-space
+ // 2: convert the principal-axis vector to regular RGB-space
+ // 3: scale the vector by a constant that estimates average quantization error
+ // 4: for each texel, square the vector, then do a dot-product with the texel's
+ // error weight; sum up the results across all texels.
+ // 4(optimized): square the vector once, then do a dot-product with the average
+ // texel error, then multiply by the number of texels.
+
+ for (unsigned int j = 0; j < partition_count; j++)
+ {
+ float tpp = static_cast<float>(pi.partition_texel_count[j]);
+ vfloat4 error_weights(tpp * weight_imprecision_estim);
+
+ vfloat4 uncor_vector = uncor_lines[j].b * uncor_line_lens[j];
+ vfloat4 samec_vector = samec_lines[j].b * samec_line_lens[j];
+
+ uncor_error += dot_s(uncor_vector * uncor_vector, error_weights);
+ samec_error += dot_s(samec_vector * samec_vector, error_weights);
+ }
+
+ insert_result(requested_candidates, uncor_error, partition, uncor_best_errors, uncor_best_partitions);
+ insert_result(requested_candidates, samec_error, partition, samec_best_errors, samec_best_partitions);
+ }
+ }
+ else
+ {
+ for (unsigned int i = 0; i < partition_search_limit; i++)
+ {
+ unsigned int partition = partition_sequence[i];
+ const auto& pi = bsd.get_raw_partition_info(partition_count, partition);
+
+ // Compute weighting to give to each component in each partition
+ partition_metrics pms[BLOCK_MAX_PARTITIONS];
+ compute_avgs_and_dirs_3_comp_rgb(pi, blk, pms);
+
+ partition_lines3 plines[BLOCK_MAX_PARTITIONS];
+
+ for (unsigned int j = 0; j < partition_count; j++)
+ {
+ partition_metrics& pm = pms[j];
+ partition_lines3& pl = plines[j];
+
+ pl.uncor_line.a = pm.avg;
+ pl.uncor_line.b = normalize_safe(pm.dir, unit3());
+
+ pl.samec_line.a = vfloat4::zero();
+ pl.samec_line.b = normalize_safe(pm.avg, unit3());
+
+ pl.uncor_pline.amod = pl.uncor_line.a - pl.uncor_line.b * dot3(pl.uncor_line.a, pl.uncor_line.b);
+ pl.uncor_pline.bs = pl.uncor_line.b;
+
+ pl.samec_pline.amod = vfloat4::zero();
+ pl.samec_pline.bs = pl.samec_line.b;
+ }
+
+ float uncor_error = 0.0f;
+ float samec_error = 0.0f;
+
+ compute_error_squared_rgb(pi,
+ blk,
+ plines,
+ uncor_error,
+ samec_error);
+
+ // Compute an estimate of error introduced by weight quantization imprecision.
+ // This error is computed as follows, for each partition
+ // 1: compute the principal-axis vector (full length) in error-space
+ // 2: convert the principal-axis vector to regular RGB-space
+ // 3: scale the vector by a constant that estimates average quantization error
+ // 4: for each texel, square the vector, then do a dot-product with the texel's
+ // error weight; sum up the results across all texels.
+ // 4(optimized): square the vector once, then do a dot-product with the average
+ // texel error, then multiply by the number of texels.
+
+ for (unsigned int j = 0; j < partition_count; j++)
+ {
+ partition_lines3& pl = plines[j];
+
+ float tpp = static_cast<float>(pi.partition_texel_count[j]);
+ vfloat4 error_weights(tpp * weight_imprecision_estim);
+
+ vfloat4 uncor_vector = pl.uncor_line.b * pl.uncor_line_len;
+ vfloat4 samec_vector = pl.samec_line.b * pl.samec_line_len;
+
+ uncor_error += dot3_s(uncor_vector * uncor_vector, error_weights);
+ samec_error += dot3_s(samec_vector * samec_vector, error_weights);
+ }
+
+ insert_result(requested_candidates, uncor_error, partition, uncor_best_errors, uncor_best_partitions);
+ insert_result(requested_candidates, samec_error, partition, samec_best_errors, samec_best_partitions);
+ }
+ }
+
+ bool best_is_uncor = uncor_best_partitions[0] > samec_best_partitions[0];
+
+ unsigned int interleave[2 * TUNE_MAX_PARTITIONING_CANDIDATES];
+ for (unsigned int i = 0; i < requested_candidates; i++)
+ {
+ if (best_is_uncor)
+ {
+ interleave[2 * i] = bsd.get_raw_partition_info(partition_count, uncor_best_partitions[i]).partition_index;
+ interleave[2 * i + 1] = bsd.get_raw_partition_info(partition_count, samec_best_partitions[i]).partition_index;
+ }
+ else
+ {
+ interleave[2 * i] = bsd.get_raw_partition_info(partition_count, samec_best_partitions[i]).partition_index;
+ interleave[2 * i + 1] = bsd.get_raw_partition_info(partition_count, uncor_best_partitions[i]).partition_index;
+ }
+ }
+
+ uint64_t bitmasks[1024/64] { 0 };
+ unsigned int emitted = 0;
+
+ // Deduplicate the first "requested" entries
+ for (unsigned int i = 0; i < requested_candidates * 2; i++)
+ {
+ unsigned int partition = interleave[i];
+
+ unsigned int word = partition / 64;
+ unsigned int bit = partition % 64;
+
+ bool written = bitmasks[word] & (1ull << bit);
+
+ if (!written)
+ {
+ best_partitions[emitted] = partition;
+ bitmasks[word] |= 1ull << bit;
+ emitted++;
+
+ if (emitted == requested_candidates)
+ {
+ break;
+ }
+ }
+ }
+
+ return emitted;
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_ideal_endpoints_and_weights.cpp b/thirdparty/astcenc/astcenc_ideal_endpoints_and_weights.cpp
new file mode 100644
index 0000000000..5145e08693
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_ideal_endpoints_and_weights.cpp
@@ -0,0 +1,1663 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Functions for computing color endpoints and texel weights.
+ */
+
+#include <cassert>
+
+#include "astcenc_internal.h"
+#include "astcenc_vecmathlib.h"
+
+/**
+ * @brief Compute the infilled weight for N texel indices in a decimated grid.
+ *
+ * @param di The weight grid decimation to use.
+ * @param weights The decimated weight values to use.
+ * @param index The first texel index to interpolate.
+ *
+ * @return The interpolated weight for the given set of SIMD_WIDTH texels.
+ */
+static vfloat bilinear_infill_vla(
+ const decimation_info& di,
+ const float* weights,
+ unsigned int index
+) {
+ // Load the bilinear filter texel weight indexes in the decimated grid
+ vint weight_idx0 = vint(di.texel_weights_tr[0] + index);
+ vint weight_idx1 = vint(di.texel_weights_tr[1] + index);
+ vint weight_idx2 = vint(di.texel_weights_tr[2] + index);
+ vint weight_idx3 = vint(di.texel_weights_tr[3] + index);
+
+ // Load the bilinear filter weights from the decimated grid
+ vfloat weight_val0 = gatherf(weights, weight_idx0);
+ vfloat weight_val1 = gatherf(weights, weight_idx1);
+ vfloat weight_val2 = gatherf(weights, weight_idx2);
+ vfloat weight_val3 = gatherf(weights, weight_idx3);
+
+ // Load the weight contribution factors for each decimated weight
+ vfloat tex_weight_float0 = loada(di.texel_weight_contribs_float_tr[0] + index);
+ vfloat tex_weight_float1 = loada(di.texel_weight_contribs_float_tr[1] + index);
+ vfloat tex_weight_float2 = loada(di.texel_weight_contribs_float_tr[2] + index);
+ vfloat tex_weight_float3 = loada(di.texel_weight_contribs_float_tr[3] + index);
+
+ // Compute the bilinear interpolation to generate the per-texel weight
+ return (weight_val0 * tex_weight_float0 + weight_val1 * tex_weight_float1) +
+ (weight_val2 * tex_weight_float2 + weight_val3 * tex_weight_float3);
+}
+
+/**
+ * @brief Compute the infilled weight for N texel indices in a decimated grid.
+ *
+ * This is specialized version which computes only two weights per texel for
+ * encodings that are only decimated in a single axis.
+ *
+ * @param di The weight grid decimation to use.
+ * @param weights The decimated weight values to use.
+ * @param index The first texel index to interpolate.
+ *
+ * @return The interpolated weight for the given set of SIMD_WIDTH texels.
+ */
+static vfloat bilinear_infill_vla_2(
+ const decimation_info& di,
+ const float* weights,
+ unsigned int index
+) {
+ // Load the bilinear filter texel weight indexes in the decimated grid
+ vint weight_idx0 = vint(di.texel_weights_tr[0] + index);
+ vint weight_idx1 = vint(di.texel_weights_tr[1] + index);
+
+ // Load the bilinear filter weights from the decimated grid
+ vfloat weight_val0 = gatherf(weights, weight_idx0);
+ vfloat weight_val1 = gatherf(weights, weight_idx1);
+
+ // Load the weight contribution factors for each decimated weight
+ vfloat tex_weight_float0 = loada(di.texel_weight_contribs_float_tr[0] + index);
+ vfloat tex_weight_float1 = loada(di.texel_weight_contribs_float_tr[1] + index);
+
+ // Compute the bilinear interpolation to generate the per-texel weight
+ return (weight_val0 * tex_weight_float0 + weight_val1 * tex_weight_float1);
+}
+
+/**
+ * @brief Compute the ideal endpoints and weights for 1 color component.
+ *
+ * @param blk The image block color data to compress.
+ * @param pi The partition info for the current trial.
+ * @param[out] ei The computed ideal endpoints and weights.
+ * @param component The color component to compute.
+ */
+static void compute_ideal_colors_and_weights_1_comp(
+ const image_block& blk,
+ const partition_info& pi,
+ endpoints_and_weights& ei,
+ unsigned int component
+) {
+ unsigned int partition_count = pi.partition_count;
+ ei.ep.partition_count = partition_count;
+ promise(partition_count > 0);
+
+ unsigned int texel_count = blk.texel_count;
+ promise(texel_count > 0);
+
+ float error_weight;
+ const float* data_vr = nullptr;
+
+ assert(component < BLOCK_MAX_COMPONENTS);
+ switch (component)
+ {
+ case 0:
+ error_weight = blk.channel_weight.lane<0>();
+ data_vr = blk.data_r;
+ break;
+ case 1:
+ error_weight = blk.channel_weight.lane<1>();
+ data_vr = blk.data_g;
+ break;
+ case 2:
+ error_weight = blk.channel_weight.lane<2>();
+ data_vr = blk.data_b;
+ break;
+ default:
+ assert(component == 3);
+ error_weight = blk.channel_weight.lane<3>();
+ data_vr = blk.data_a;
+ break;
+ }
+
+ vmask4 sep_mask = vint4::lane_id() == vint4(component);
+ bool is_constant_wes { true };
+ float partition0_len_sq { 0.0f };
+
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ float lowvalue { 1e10f };
+ float highvalue { -1e10f };
+
+ unsigned int partition_texel_count = pi.partition_texel_count[i];
+ for (unsigned int j = 0; j < partition_texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ float value = data_vr[tix];
+ lowvalue = astc::min(value, lowvalue);
+ highvalue = astc::max(value, highvalue);
+ }
+
+ if (highvalue <= lowvalue)
+ {
+ lowvalue = 0.0f;
+ highvalue = 1e-7f;
+ }
+
+ float length = highvalue - lowvalue;
+ float length_squared = length * length;
+ float scale = 1.0f / length;
+
+ if (i == 0)
+ {
+ partition0_len_sq = length_squared;
+ }
+ else
+ {
+ is_constant_wes = is_constant_wes && length_squared == partition0_len_sq;
+ }
+
+ for (unsigned int j = 0; j < partition_texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ float value = (data_vr[tix] - lowvalue) * scale;
+ value = astc::clamp1f(value);
+
+ ei.weights[tix] = value;
+ ei.weight_error_scale[tix] = length_squared * error_weight;
+ assert(!astc::isnan(ei.weight_error_scale[tix]));
+ }
+
+ ei.ep.endpt0[i] = select(blk.data_min, vfloat4(lowvalue), sep_mask);
+ ei.ep.endpt1[i] = select(blk.data_max, vfloat4(highvalue), sep_mask);
+ }
+
+ // Zero initialize any SIMD over-fetch
+ unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count);
+ for (unsigned int i = texel_count; i < texel_count_simd; i++)
+ {
+ ei.weights[i] = 0.0f;
+ ei.weight_error_scale[i] = 0.0f;
+ }
+
+ ei.is_constant_weight_error_scale = is_constant_wes;
+}
+
+/**
+ * @brief Compute the ideal endpoints and weights for 2 color components.
+ *
+ * @param blk The image block color data to compress.
+ * @param pi The partition info for the current trial.
+ * @param[out] ei The computed ideal endpoints and weights.
+ * @param component1 The first color component to compute.
+ * @param component2 The second color component to compute.
+ */
+static void compute_ideal_colors_and_weights_2_comp(
+ const image_block& blk,
+ const partition_info& pi,
+ endpoints_and_weights& ei,
+ int component1,
+ int component2
+) {
+ unsigned int partition_count = pi.partition_count;
+ ei.ep.partition_count = partition_count;
+ promise(partition_count > 0);
+
+ unsigned int texel_count = blk.texel_count;
+ promise(texel_count > 0);
+
+ partition_metrics pms[BLOCK_MAX_PARTITIONS];
+
+ float error_weight;
+ const float* data_vr = nullptr;
+ const float* data_vg = nullptr;
+
+ if (component1 == 0 && component2 == 1)
+ {
+ error_weight = hadd_s(blk.channel_weight.swz<0, 1>()) / 2.0f;
+
+ data_vr = blk.data_r;
+ data_vg = blk.data_g;
+ }
+ else if (component1 == 0 && component2 == 2)
+ {
+ error_weight = hadd_s(blk.channel_weight.swz<0, 2>()) / 2.0f;
+
+ data_vr = blk.data_r;
+ data_vg = blk.data_b;
+ }
+ else // (component1 == 1 && component2 == 2)
+ {
+ assert(component1 == 1 && component2 == 2);
+
+ error_weight = hadd_s(blk.channel_weight.swz<1, 2>()) / 2.0f;
+
+ data_vr = blk.data_g;
+ data_vg = blk.data_b;
+ }
+
+ compute_avgs_and_dirs_2_comp(pi, blk, component1, component2, pms);
+
+ bool is_constant_wes { true };
+ float partition0_len_sq { 0.0f };
+
+ vmask4 comp1_mask = vint4::lane_id() == vint4(component1);
+ vmask4 comp2_mask = vint4::lane_id() == vint4(component2);
+
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ vfloat4 dir = pms[i].dir;
+ if (hadd_s(dir) < 0.0f)
+ {
+ dir = vfloat4::zero() - dir;
+ }
+
+ line2 line { pms[i].avg, normalize_safe(dir, unit2()) };
+ float lowparam { 1e10f };
+ float highparam { -1e10f };
+
+ unsigned int partition_texel_count = pi.partition_texel_count[i];
+ for (unsigned int j = 0; j < partition_texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ vfloat4 point = vfloat2(data_vr[tix], data_vg[tix]);
+ float param = dot_s(point - line.a, line.b);
+ ei.weights[tix] = param;
+
+ lowparam = astc::min(param, lowparam);
+ highparam = astc::max(param, highparam);
+ }
+
+ // It is possible for a uniform-color partition to produce length=0;
+ // this causes NaN issues so set to small value to avoid this problem
+ if (highparam <= lowparam)
+ {
+ lowparam = 0.0f;
+ highparam = 1e-7f;
+ }
+
+ float length = highparam - lowparam;
+ float length_squared = length * length;
+ float scale = 1.0f / length;
+
+ if (i == 0)
+ {
+ partition0_len_sq = length_squared;
+ }
+ else
+ {
+ is_constant_wes = is_constant_wes && length_squared == partition0_len_sq;
+ }
+
+ for (unsigned int j = 0; j < partition_texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ float idx = (ei.weights[tix] - lowparam) * scale;
+ idx = astc::clamp1f(idx);
+
+ ei.weights[tix] = idx;
+ ei.weight_error_scale[tix] = length_squared * error_weight;
+ assert(!astc::isnan(ei.weight_error_scale[tix]));
+ }
+
+ vfloat4 lowvalue = line.a + line.b * lowparam;
+ vfloat4 highvalue = line.a + line.b * highparam;
+
+ vfloat4 ep0 = select(blk.data_min, vfloat4(lowvalue.lane<0>()), comp1_mask);
+ vfloat4 ep1 = select(blk.data_max, vfloat4(highvalue.lane<0>()), comp1_mask);
+
+ ei.ep.endpt0[i] = select(ep0, vfloat4(lowvalue.lane<1>()), comp2_mask);
+ ei.ep.endpt1[i] = select(ep1, vfloat4(highvalue.lane<1>()), comp2_mask);
+ }
+
+ // Zero initialize any SIMD over-fetch
+ unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count);
+ for (unsigned int i = texel_count; i < texel_count_simd; i++)
+ {
+ ei.weights[i] = 0.0f;
+ ei.weight_error_scale[i] = 0.0f;
+ }
+
+ ei.is_constant_weight_error_scale = is_constant_wes;
+}
+
+/**
+ * @brief Compute the ideal endpoints and weights for 3 color components.
+ *
+ * @param blk The image block color data to compress.
+ * @param pi The partition info for the current trial.
+ * @param[out] ei The computed ideal endpoints and weights.
+ * @param omitted_component The color component excluded from the calculation.
+ */
+static void compute_ideal_colors_and_weights_3_comp(
+ const image_block& blk,
+ const partition_info& pi,
+ endpoints_and_weights& ei,
+ unsigned int omitted_component
+) {
+ unsigned int partition_count = pi.partition_count;
+ ei.ep.partition_count = partition_count;
+ promise(partition_count > 0);
+
+ unsigned int texel_count = blk.texel_count;
+ promise(texel_count > 0);
+
+ partition_metrics pms[BLOCK_MAX_PARTITIONS];
+
+ float error_weight;
+ const float* data_vr = nullptr;
+ const float* data_vg = nullptr;
+ const float* data_vb = nullptr;
+ if (omitted_component == 0)
+ {
+ error_weight = hadd_s(blk.channel_weight.swz<0, 1, 2>());
+ data_vr = blk.data_g;
+ data_vg = blk.data_b;
+ data_vb = blk.data_a;
+ }
+ else if (omitted_component == 1)
+ {
+ error_weight = hadd_s(blk.channel_weight.swz<0, 2, 3>());
+ data_vr = blk.data_r;
+ data_vg = blk.data_b;
+ data_vb = blk.data_a;
+ }
+ else if (omitted_component == 2)
+ {
+ error_weight = hadd_s(blk.channel_weight.swz<0, 1, 3>());
+ data_vr = blk.data_r;
+ data_vg = blk.data_g;
+ data_vb = blk.data_a;
+ }
+ else
+ {
+ assert(omitted_component == 3);
+
+ error_weight = hadd_s(blk.channel_weight.swz<0, 1, 2>());
+ data_vr = blk.data_r;
+ data_vg = blk.data_g;
+ data_vb = blk.data_b;
+ }
+
+ error_weight = error_weight * (1.0f / 3.0f);
+
+ if (omitted_component == 3)
+ {
+ compute_avgs_and_dirs_3_comp_rgb(pi, blk, pms);
+ }
+ else
+ {
+ compute_avgs_and_dirs_3_comp(pi, blk, omitted_component, pms);
+ }
+
+ bool is_constant_wes { true };
+ float partition0_len_sq { 0.0f };
+
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ vfloat4 dir = pms[i].dir;
+ if (hadd_rgb_s(dir) < 0.0f)
+ {
+ dir = vfloat4::zero() - dir;
+ }
+
+ line3 line { pms[i].avg, normalize_safe(dir, unit3()) };
+ float lowparam { 1e10f };
+ float highparam { -1e10f };
+
+ unsigned int partition_texel_count = pi.partition_texel_count[i];
+ for (unsigned int j = 0; j < partition_texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ vfloat4 point = vfloat3(data_vr[tix], data_vg[tix], data_vb[tix]);
+ float param = dot3_s(point - line.a, line.b);
+ ei.weights[tix] = param;
+
+ lowparam = astc::min(param, lowparam);
+ highparam = astc::max(param, highparam);
+ }
+
+ // It is possible for a uniform-color partition to produce length=0;
+ // this causes NaN issues so set to small value to avoid this problem
+ if (highparam <= lowparam)
+ {
+ lowparam = 0.0f;
+ highparam = 1e-7f;
+ }
+
+ float length = highparam - lowparam;
+ float length_squared = length * length;
+ float scale = 1.0f / length;
+
+ if (i == 0)
+ {
+ partition0_len_sq = length_squared;
+ }
+ else
+ {
+ is_constant_wes = is_constant_wes && length_squared == partition0_len_sq;
+ }
+
+ for (unsigned int j = 0; j < partition_texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ float idx = (ei.weights[tix] - lowparam) * scale;
+ idx = astc::clamp1f(idx);
+
+ ei.weights[tix] = idx;
+ ei.weight_error_scale[tix] = length_squared * error_weight;
+ assert(!astc::isnan(ei.weight_error_scale[tix]));
+ }
+
+ vfloat4 ep0 = line.a + line.b * lowparam;
+ vfloat4 ep1 = line.a + line.b * highparam;
+
+ vfloat4 bmin = blk.data_min;
+ vfloat4 bmax = blk.data_max;
+
+ assert(omitted_component < BLOCK_MAX_COMPONENTS);
+ switch (omitted_component)
+ {
+ case 0:
+ ei.ep.endpt0[i] = vfloat4(bmin.lane<0>(), ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>());
+ ei.ep.endpt1[i] = vfloat4(bmax.lane<0>(), ep1.lane<0>(), ep1.lane<1>(), ep1.lane<2>());
+ break;
+ case 1:
+ ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), bmin.lane<1>(), ep0.lane<1>(), ep0.lane<2>());
+ ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), bmax.lane<1>(), ep1.lane<1>(), ep1.lane<2>());
+ break;
+ case 2:
+ ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), bmin.lane<2>(), ep0.lane<2>());
+ ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), ep1.lane<1>(), bmax.lane<2>(), ep1.lane<2>());
+ break;
+ default:
+ ei.ep.endpt0[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), bmin.lane<3>());
+ ei.ep.endpt1[i] = vfloat4(ep1.lane<0>(), ep1.lane<1>(), ep1.lane<2>(), bmax.lane<3>());
+ break;
+ }
+ }
+
+ // Zero initialize any SIMD over-fetch
+ unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count);
+ for (unsigned int i = texel_count; i < texel_count_simd; i++)
+ {
+ ei.weights[i] = 0.0f;
+ ei.weight_error_scale[i] = 0.0f;
+ }
+
+ ei.is_constant_weight_error_scale = is_constant_wes;
+}
+
+/**
+ * @brief Compute the ideal endpoints and weights for 4 color components.
+ *
+ * @param blk The image block color data to compress.
+ * @param pi The partition info for the current trial.
+ * @param[out] ei The computed ideal endpoints and weights.
+ */
+static void compute_ideal_colors_and_weights_4_comp(
+ const image_block& blk,
+ const partition_info& pi,
+ endpoints_and_weights& ei
+) {
+ const float error_weight = hadd_s(blk.channel_weight) / 4.0f;
+
+ unsigned int partition_count = pi.partition_count;
+
+ unsigned int texel_count = blk.texel_count;
+ promise(texel_count > 0);
+ promise(partition_count > 0);
+
+ partition_metrics pms[BLOCK_MAX_PARTITIONS];
+
+ compute_avgs_and_dirs_4_comp(pi, blk, pms);
+
+ bool is_constant_wes { true };
+ float partition0_len_sq { 0.0f };
+
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ vfloat4 dir = pms[i].dir;
+ if (hadd_rgb_s(dir) < 0.0f)
+ {
+ dir = vfloat4::zero() - dir;
+ }
+
+ line4 line { pms[i].avg, normalize_safe(dir, unit4()) };
+ float lowparam { 1e10f };
+ float highparam { -1e10f };
+
+ unsigned int partition_texel_count = pi.partition_texel_count[i];
+ for (unsigned int j = 0; j < partition_texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ vfloat4 point = blk.texel(tix);
+ float param = dot_s(point - line.a, line.b);
+ ei.weights[tix] = param;
+
+ lowparam = astc::min(param, lowparam);
+ highparam = astc::max(param, highparam);
+ }
+
+ // It is possible for a uniform-color partition to produce length=0;
+ // this causes NaN issues so set to small value to avoid this problem
+ if (highparam <= lowparam)
+ {
+ lowparam = 0.0f;
+ highparam = 1e-7f;
+ }
+
+ float length = highparam - lowparam;
+ float length_squared = length * length;
+ float scale = 1.0f / length;
+
+ if (i == 0)
+ {
+ partition0_len_sq = length_squared;
+ }
+ else
+ {
+ is_constant_wes = is_constant_wes && length_squared == partition0_len_sq;
+ }
+
+ ei.ep.endpt0[i] = line.a + line.b * lowparam;
+ ei.ep.endpt1[i] = line.a + line.b * highparam;
+
+ for (unsigned int j = 0; j < partition_texel_count; j++)
+ {
+ unsigned int tix = pi.texels_of_partition[i][j];
+ float idx = (ei.weights[tix] - lowparam) * scale;
+ idx = astc::clamp1f(idx);
+
+ ei.weights[tix] = idx;
+ ei.weight_error_scale[tix] = length_squared * error_weight;
+ assert(!astc::isnan(ei.weight_error_scale[tix]));
+ }
+ }
+
+ // Zero initialize any SIMD over-fetch
+ unsigned int texel_count_simd = round_up_to_simd_multiple_vla(texel_count);
+ for (unsigned int i = texel_count; i < texel_count_simd; i++)
+ {
+ ei.weights[i] = 0.0f;
+ ei.weight_error_scale[i] = 0.0f;
+ }
+
+ ei.is_constant_weight_error_scale = is_constant_wes;
+}
+
+/* See header for documentation. */
+void compute_ideal_colors_and_weights_1plane(
+ const image_block& blk,
+ const partition_info& pi,
+ endpoints_and_weights& ei
+) {
+ bool uses_alpha = !blk.is_constant_channel(3);
+
+ if (uses_alpha)
+ {
+ compute_ideal_colors_and_weights_4_comp(blk, pi, ei);
+ }
+ else
+ {
+ compute_ideal_colors_and_weights_3_comp(blk, pi, ei, 3);
+ }
+}
+
+/* See header for documentation. */
+void compute_ideal_colors_and_weights_2planes(
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ unsigned int plane2_component,
+ endpoints_and_weights& ei1,
+ endpoints_and_weights& ei2
+) {
+ const auto& pi = bsd.get_partition_info(1, 0);
+ bool uses_alpha = !blk.is_constant_channel(3);
+
+ assert(plane2_component < BLOCK_MAX_COMPONENTS);
+ switch (plane2_component)
+ {
+ case 0: // Separate weights for red
+ if (uses_alpha)
+ {
+ compute_ideal_colors_and_weights_3_comp(blk, pi, ei1, 0);
+ }
+ else
+ {
+ compute_ideal_colors_and_weights_2_comp(blk, pi, ei1, 1, 2);
+ }
+ compute_ideal_colors_and_weights_1_comp(blk, pi, ei2, 0);
+ break;
+
+ case 1: // Separate weights for green
+ if (uses_alpha)
+ {
+ compute_ideal_colors_and_weights_3_comp(blk, pi, ei1, 1);
+ }
+ else
+ {
+ compute_ideal_colors_and_weights_2_comp(blk, pi, ei1, 0, 2);
+ }
+ compute_ideal_colors_and_weights_1_comp(blk, pi, ei2, 1);
+ break;
+
+ case 2: // Separate weights for blue
+ if (uses_alpha)
+ {
+ compute_ideal_colors_and_weights_3_comp(blk, pi, ei1, 2);
+ }
+ else
+ {
+ compute_ideal_colors_and_weights_2_comp(blk, pi, ei1, 0, 1);
+ }
+ compute_ideal_colors_and_weights_1_comp(blk, pi, ei2, 2);
+ break;
+
+ default: // Separate weights for alpha
+ assert(uses_alpha);
+ compute_ideal_colors_and_weights_3_comp(blk, pi, ei1, 3);
+ compute_ideal_colors_and_weights_1_comp(blk, pi, ei2, 3);
+ break;
+ }
+}
+
+/* See header for documentation. */
+float compute_error_of_weight_set_1plane(
+ const endpoints_and_weights& eai,
+ const decimation_info& di,
+ const float* dec_weight_quant_uvalue
+) {
+ vfloatacc error_summav = vfloatacc::zero();
+ unsigned int texel_count = di.texel_count;
+ promise(texel_count > 0);
+
+ // Process SIMD-width chunks, safe to over-fetch - the extra space is zero initialized
+ if (di.max_texel_weight_count > 2)
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Compute the bilinear interpolation of the decimated weight grid
+ vfloat current_values = bilinear_infill_vla(di, dec_weight_quant_uvalue, i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values = loada(eai.weights + i);
+ vfloat diff = current_values - actual_values;
+ vfloat significance = loada(eai.weight_error_scale + i);
+ vfloat error = diff * diff * significance;
+
+ haccumulate(error_summav, error);
+ }
+ }
+ else if (di.max_texel_weight_count > 1)
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Compute the bilinear interpolation of the decimated weight grid
+ vfloat current_values = bilinear_infill_vla_2(di, dec_weight_quant_uvalue, i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values = loada(eai.weights + i);
+ vfloat diff = current_values - actual_values;
+ vfloat significance = loada(eai.weight_error_scale + i);
+ vfloat error = diff * diff * significance;
+
+ haccumulate(error_summav, error);
+ }
+ }
+ else
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Load the weight set directly, without interpolation
+ vfloat current_values = loada(dec_weight_quant_uvalue + i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values = loada(eai.weights + i);
+ vfloat diff = current_values - actual_values;
+ vfloat significance = loada(eai.weight_error_scale + i);
+ vfloat error = diff * diff * significance;
+
+ haccumulate(error_summav, error);
+ }
+ }
+
+ // Resolve the final scalar accumulator sum
+ return hadd_s(error_summav);
+}
+
+/* See header for documentation. */
+float compute_error_of_weight_set_2planes(
+ const endpoints_and_weights& eai1,
+ const endpoints_and_weights& eai2,
+ const decimation_info& di,
+ const float* dec_weight_quant_uvalue_plane1,
+ const float* dec_weight_quant_uvalue_plane2
+) {
+ vfloatacc error_summav = vfloatacc::zero();
+ unsigned int texel_count = di.texel_count;
+ promise(texel_count > 0);
+
+ // Process SIMD-width chunks, safe to over-fetch - the extra space is zero initialized
+ if (di.max_texel_weight_count > 2)
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Plane 1
+ // Compute the bilinear interpolation of the decimated weight grid
+ vfloat current_values1 = bilinear_infill_vla(di, dec_weight_quant_uvalue_plane1, i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values1 = loada(eai1.weights + i);
+ vfloat diff = current_values1 - actual_values1;
+ vfloat error1 = diff * diff * loada(eai1.weight_error_scale + i);
+
+ // Plane 2
+ // Compute the bilinear interpolation of the decimated weight grid
+ vfloat current_values2 = bilinear_infill_vla(di, dec_weight_quant_uvalue_plane2, i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values2 = loada(eai2.weights + i);
+ diff = current_values2 - actual_values2;
+ vfloat error2 = diff * diff * loada(eai2.weight_error_scale + i);
+
+ haccumulate(error_summav, error1 + error2);
+ }
+ }
+ else if (di.max_texel_weight_count > 1)
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Plane 1
+ // Compute the bilinear interpolation of the decimated weight grid
+ vfloat current_values1 = bilinear_infill_vla_2(di, dec_weight_quant_uvalue_plane1, i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values1 = loada(eai1.weights + i);
+ vfloat diff = current_values1 - actual_values1;
+ vfloat error1 = diff * diff * loada(eai1.weight_error_scale + i);
+
+ // Plane 2
+ // Compute the bilinear interpolation of the decimated weight grid
+ vfloat current_values2 = bilinear_infill_vla_2(di, dec_weight_quant_uvalue_plane2, i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values2 = loada(eai2.weights + i);
+ diff = current_values2 - actual_values2;
+ vfloat error2 = diff * diff * loada(eai2.weight_error_scale + i);
+
+ haccumulate(error_summav, error1 + error2);
+ }
+ }
+ else
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Plane 1
+ // Load the weight set directly, without interpolation
+ vfloat current_values1 = loada(dec_weight_quant_uvalue_plane1 + i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values1 = loada(eai1.weights + i);
+ vfloat diff = current_values1 - actual_values1;
+ vfloat error1 = diff * diff * loada(eai1.weight_error_scale + i);
+
+ // Plane 2
+ // Load the weight set directly, without interpolation
+ vfloat current_values2 = loada(dec_weight_quant_uvalue_plane2 + i);
+
+ // Compute the error between the computed value and the ideal weight
+ vfloat actual_values2 = loada(eai2.weights + i);
+ diff = current_values2 - actual_values2;
+ vfloat error2 = diff * diff * loada(eai2.weight_error_scale + i);
+
+ haccumulate(error_summav, error1 + error2);
+ }
+ }
+
+ // Resolve the final scalar accumulator sum
+ return hadd_s(error_summav);
+}
+
+/* See header for documentation. */
+void compute_ideal_weights_for_decimation(
+ const endpoints_and_weights& ei,
+ const decimation_info& di,
+ float* dec_weight_ideal_value
+) {
+ unsigned int texel_count = di.texel_count;
+ unsigned int weight_count = di.weight_count;
+ bool is_direct = texel_count == weight_count;
+ promise(texel_count > 0);
+ promise(weight_count > 0);
+
+ // Ensure that the end of the output arrays that are used for SIMD paths later are filled so we
+ // can safely run SIMD elsewhere without a loop tail. Note that this is always safe as weight
+ // arrays always contain space for 64 elements
+ unsigned int prev_weight_count_simd = round_down_to_simd_multiple_vla(weight_count - 1);
+ storea(vfloat::zero(), dec_weight_ideal_value + prev_weight_count_simd);
+
+ // If we have a 1:1 mapping just shortcut the computation. Transfer enough to also copy the
+ // zero-initialized SIMD over-fetch region
+ if (is_direct)
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat weight(ei.weights + i);
+ storea(weight, dec_weight_ideal_value + i);
+ }
+
+ return;
+ }
+
+ // Otherwise compute an estimate and perform single refinement iteration
+ alignas(ASTCENC_VECALIGN) float infilled_weights[BLOCK_MAX_TEXELS];
+
+ // Compute an initial average for each decimated weight
+ bool constant_wes = ei.is_constant_weight_error_scale;
+ vfloat weight_error_scale(ei.weight_error_scale[0]);
+
+ // This overshoots - this is OK as we initialize the array tails in the
+ // decimation table structures to safe values ...
+ for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Start with a small value to avoid div-by-zero later
+ vfloat weight_weight(1e-10f);
+ vfloat initial_weight = vfloat::zero();
+
+ // Accumulate error weighting of all the texels using this weight
+ vint weight_texel_count(di.weight_texel_count + i);
+ unsigned int max_texel_count = hmax(weight_texel_count).lane<0>();
+ promise(max_texel_count > 0);
+
+ for (unsigned int j = 0; j < max_texel_count; j++)
+ {
+ vint texel(di.weight_texels_tr[j] + i);
+ vfloat weight = loada(di.weights_texel_contribs_tr[j] + i);
+
+ if (!constant_wes)
+ {
+ weight_error_scale = gatherf(ei.weight_error_scale, texel);
+ }
+
+ vfloat contrib_weight = weight * weight_error_scale;
+
+ weight_weight += contrib_weight;
+ initial_weight += gatherf(ei.weights, texel) * contrib_weight;
+ }
+
+ storea(initial_weight / weight_weight, dec_weight_ideal_value + i);
+ }
+
+ // Populate the interpolated weight grid based on the initial average
+ // Process SIMD-width texel coordinates at at time while we can. Safe to
+ // over-process full SIMD vectors - the tail is zeroed.
+ if (di.max_texel_weight_count <= 2)
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat weight = bilinear_infill_vla_2(di, dec_weight_ideal_value, i);
+ storea(weight, infilled_weights + i);
+ }
+ }
+ else
+ {
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat weight = bilinear_infill_vla(di, dec_weight_ideal_value, i);
+ storea(weight, infilled_weights + i);
+ }
+ }
+
+ // Perform a single iteration of refinement
+ // Empirically determined step size; larger values don't help but smaller drops image quality
+ constexpr float stepsize = 0.25f;
+ constexpr float chd_scale = -WEIGHTS_TEXEL_SUM;
+
+ for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat weight_val = loada(dec_weight_ideal_value + i);
+
+ // Accumulate error weighting of all the texels using this weight
+ // Start with a small value to avoid div-by-zero later
+ vfloat error_change0(1e-10f);
+ vfloat error_change1(0.0f);
+
+ // Accumulate error weighting of all the texels using this weight
+ vint weight_texel_count(di.weight_texel_count + i);
+ unsigned int max_texel_count = hmax(weight_texel_count).lane<0>();
+ promise(max_texel_count > 0);
+
+ for (unsigned int j = 0; j < max_texel_count; j++)
+ {
+ vint texel(di.weight_texels_tr[j] + i);
+ vfloat contrib_weight = loada(di.weights_texel_contribs_tr[j] + i);
+
+ if (!constant_wes)
+ {
+ weight_error_scale = gatherf(ei.weight_error_scale, texel);
+ }
+
+ vfloat scale = weight_error_scale * contrib_weight;
+ vfloat old_weight = gatherf(infilled_weights, texel);
+ vfloat ideal_weight = gatherf(ei.weights, texel);
+
+ error_change0 += contrib_weight * scale;
+ error_change1 += (old_weight - ideal_weight) * scale;
+ }
+
+ vfloat step = (error_change1 * chd_scale) / error_change0;
+ step = clamp(-stepsize, stepsize, step);
+
+ // Update the weight; note this can store negative values
+ storea(weight_val + step, dec_weight_ideal_value + i);
+ }
+}
+
+/* See header for documentation. */
+void compute_quantized_weights_for_decimation(
+ const decimation_info& di,
+ float low_bound,
+ float high_bound,
+ const float* dec_weight_ideal_value,
+ float* weight_set_out,
+ uint8_t* quantized_weight_set,
+ quant_method quant_level
+) {
+ int weight_count = di.weight_count;
+ promise(weight_count > 0);
+ const quant_and_transfer_table& qat = quant_and_xfer_tables[quant_level];
+
+ // The available quant levels, stored with a minus 1 bias
+ static const float quant_levels_m1[12] {
+ 1.0f, 2.0f, 3.0f, 4.0f, 5.0f, 7.0f, 9.0f, 11.0f, 15.0f, 19.0f, 23.0f, 31.0f
+ };
+
+ vint steps_m1(get_quant_level(quant_level) - 1);
+ float quant_level_m1 = quant_levels_m1[quant_level];
+
+ // Quantize the weight set using both the specified low/high bounds and standard 0..1 bounds
+
+ // TODO: Oddity to investigate; triggered by test in issue #265.
+ if (high_bound <= low_bound)
+ {
+ low_bound = 0.0f;
+ high_bound = 1.0f;
+ }
+
+ float rscale = high_bound - low_bound;
+ float scale = 1.0f / rscale;
+
+ float scaled_low_bound = low_bound * scale;
+ rscale *= 1.0f / 64.0f;
+
+ vfloat scalev(scale);
+ vfloat scaled_low_boundv(scaled_low_bound);
+ vfloat quant_level_m1v(quant_level_m1);
+ vfloat rscalev(rscale);
+ vfloat low_boundv(low_bound);
+
+ // This runs to the rounded-up SIMD size, which is safe as the loop tail is filled with known
+ // safe data in compute_ideal_weights_for_decimation and arrays are always 64 elements
+ if (get_quant_level(quant_level) <= 16)
+ {
+ vint4 tab0(reinterpret_cast<const int*>(qat.quant_to_unquant));
+ vint tab0p;
+ vtable_prepare(tab0, tab0p);
+
+ for (int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat ix = loada(dec_weight_ideal_value + i) * scalev - scaled_low_boundv;
+ ix = clampzo(ix);
+
+ // Look up the two closest indexes and return the one that was closest
+ vfloat ix1 = ix * quant_level_m1v;
+
+ vint weightl = float_to_int(ix1);
+ vint weighth = min(weightl + vint(1), steps_m1);
+
+ vint ixli = vtable_8bt_32bi(tab0p, weightl);
+ vint ixhi = vtable_8bt_32bi(tab0p, weighth);
+
+ vfloat ixl = int_to_float(ixli);
+ vfloat ixh = int_to_float(ixhi);
+
+ vmask mask = (ixl + ixh) < (vfloat(128.0f) * ix);
+ vint weight = select(ixli, ixhi, mask);
+ ixl = select(ixl, ixh, mask);
+
+ // Invert the weight-scaling that was done initially
+ storea(ixl * rscalev + low_boundv, weight_set_out + i);
+ vint scn = pack_low_bytes(weight);
+ store_nbytes(scn, quantized_weight_set + i);
+ }
+ }
+ else
+ {
+ vint4 tab0(reinterpret_cast<const int*>(qat.quant_to_unquant));
+ vint4 tab1(reinterpret_cast<const int*>(qat.quant_to_unquant + 16));
+ vint tab0p, tab1p;
+ vtable_prepare(tab0, tab1, tab0p, tab1p);
+
+ for (int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat ix = loada(dec_weight_ideal_value + i) * scalev - scaled_low_boundv;
+ ix = clampzo(ix);
+
+ // Look up the two closest indexes and return the one that was closest
+ vfloat ix1 = ix * quant_level_m1v;
+
+ vint weightl = float_to_int(ix1);
+ vint weighth = min(weightl + vint(1), steps_m1);
+
+ vint ixli = vtable_8bt_32bi(tab0p, tab1p, weightl);
+ vint ixhi = vtable_8bt_32bi(tab0p, tab1p, weighth);
+
+ vfloat ixl = int_to_float(ixli);
+ vfloat ixh = int_to_float(ixhi);
+
+ vmask mask = (ixl + ixh) < (vfloat(128.0f) * ix);
+ vint weight = select(ixli, ixhi, mask);
+ ixl = select(ixl, ixh, mask);
+
+ // Invert the weight-scaling that was done initially
+ storea(ixl * rscalev + low_boundv, weight_set_out + i);
+ vint scn = pack_low_bytes(weight);
+ store_nbytes(scn, quantized_weight_set + i);
+ }
+ }
+}
+
+/**
+ * @brief Compute the RGB + offset for a HDR endpoint mode #7.
+ *
+ * Since the matrix needed has a regular structure we can simplify the inverse calculation. This
+ * gives us ~24 multiplications vs. 96 for a generic inverse.
+ *
+ * mat[0] = vfloat4(rgba_ws.x, 0.0f, 0.0f, wght_ws.x);
+ * mat[1] = vfloat4( 0.0f, rgba_ws.y, 0.0f, wght_ws.y);
+ * mat[2] = vfloat4( 0.0f, 0.0f, rgba_ws.z, wght_ws.z);
+ * mat[3] = vfloat4(wght_ws.x, wght_ws.y, wght_ws.z, psum);
+ * mat = invert(mat);
+ *
+ * @param rgba_weight_sum Sum of partition component error weights.
+ * @param weight_weight_sum Sum of partition component error weights * texel weight.
+ * @param rgbq_sum Sum of partition component error weights * texel weight * color data.
+ * @param psum Sum of RGB color weights * texel weight^2.
+ */
+static inline vfloat4 compute_rgbo_vector(
+ vfloat4 rgba_weight_sum,
+ vfloat4 weight_weight_sum,
+ vfloat4 rgbq_sum,
+ float psum
+) {
+ float X = rgba_weight_sum.lane<0>();
+ float Y = rgba_weight_sum.lane<1>();
+ float Z = rgba_weight_sum.lane<2>();
+ float P = weight_weight_sum.lane<0>();
+ float Q = weight_weight_sum.lane<1>();
+ float R = weight_weight_sum.lane<2>();
+ float S = psum;
+
+ float PP = P * P;
+ float QQ = Q * Q;
+ float RR = R * R;
+
+ float SZmRR = S * Z - RR;
+ float DT = SZmRR * Y - Z * QQ;
+ float YP = Y * P;
+ float QX = Q * X;
+ float YX = Y * X;
+ float mZYP = -Z * YP;
+ float mZQX = -Z * QX;
+ float mRYX = -R * YX;
+ float ZQP = Z * Q * P;
+ float RYP = R * YP;
+ float RQX = R * QX;
+
+ // Compute the reciprocal of matrix determinant
+ float rdet = 1.0f / (DT * X + mZYP * P);
+
+ // Actually compute the adjugate, and then apply 1/det separately
+ vfloat4 mat0(DT, ZQP, RYP, mZYP);
+ vfloat4 mat1(ZQP, SZmRR * X - Z * PP, RQX, mZQX);
+ vfloat4 mat2(RYP, RQX, (S * Y - QQ) * X - Y * PP, mRYX);
+ vfloat4 mat3(mZYP, mZQX, mRYX, Z * YX);
+ vfloat4 vect = rgbq_sum * rdet;
+
+ return vfloat4(dot_s(mat0, vect),
+ dot_s(mat1, vect),
+ dot_s(mat2, vect),
+ dot_s(mat3, vect));
+}
+
+/* See header for documentation. */
+void recompute_ideal_colors_1plane(
+ const image_block& blk,
+ const partition_info& pi,
+ const decimation_info& di,
+ const uint8_t* dec_weights_uquant,
+ endpoints& ep,
+ vfloat4 rgbs_vectors[BLOCK_MAX_PARTITIONS],
+ vfloat4 rgbo_vectors[BLOCK_MAX_PARTITIONS]
+) {
+ unsigned int weight_count = di.weight_count;
+ unsigned int total_texel_count = blk.texel_count;
+ unsigned int partition_count = pi.partition_count;
+
+ promise(weight_count > 0);
+ promise(total_texel_count > 0);
+ promise(partition_count > 0);
+
+ alignas(ASTCENC_VECALIGN) float dec_weight[BLOCK_MAX_WEIGHTS];
+ for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint unquant_value(dec_weights_uquant + i);
+ vfloat unquant_valuef = int_to_float(unquant_value) * vfloat(1.0f / 64.0f);
+ storea(unquant_valuef, dec_weight + i);
+ }
+
+ alignas(ASTCENC_VECALIGN) float undec_weight[BLOCK_MAX_TEXELS];
+ float* undec_weight_ref;
+ if (di.max_texel_weight_count == 1)
+ {
+ undec_weight_ref = dec_weight;
+ }
+ else if (di.max_texel_weight_count <= 2)
+ {
+ for (unsigned int i = 0; i < total_texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat weight = bilinear_infill_vla_2(di, dec_weight, i);
+ storea(weight, undec_weight + i);
+ }
+
+ undec_weight_ref = undec_weight;
+ }
+ else
+ {
+ for (unsigned int i = 0; i < total_texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat weight = bilinear_infill_vla(di, dec_weight, i);
+ storea(weight, undec_weight + i);
+ }
+
+ undec_weight_ref = undec_weight;
+ }
+
+ vfloat4 rgba_sum(blk.data_mean * static_cast<float>(blk.texel_count));
+
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ unsigned int texel_count = pi.partition_texel_count[i];
+ const uint8_t *texel_indexes = pi.texels_of_partition[i];
+
+ // Only compute a partition mean if more than one partition
+ if (partition_count > 1)
+ {
+ rgba_sum = vfloat4::zero();
+ promise(texel_count > 0);
+ for (unsigned int j = 0; j < texel_count; j++)
+ {
+ unsigned int tix = texel_indexes[j];
+ rgba_sum += blk.texel(tix);
+ }
+ }
+
+ rgba_sum = rgba_sum * blk.channel_weight;
+ vfloat4 rgba_weight_sum = max(blk.channel_weight * static_cast<float>(texel_count), 1e-17f);
+ vfloat4 scale_dir = normalize((rgba_sum / rgba_weight_sum).swz<0, 1, 2>());
+
+ float scale_max = 0.0f;
+ float scale_min = 1e10f;
+
+ float wmin1 = 1.0f;
+ float wmax1 = 0.0f;
+
+ float left_sum_s = 0.0f;
+ float middle_sum_s = 0.0f;
+ float right_sum_s = 0.0f;
+
+ vfloat4 color_vec_x = vfloat4::zero();
+ vfloat4 color_vec_y = vfloat4::zero();
+
+ vfloat4 scale_vec = vfloat4::zero();
+
+ float weight_weight_sum_s = 1e-17f;
+
+ vfloat4 color_weight = blk.channel_weight;
+ float ls_weight = hadd_rgb_s(color_weight);
+
+ for (unsigned int j = 0; j < texel_count; j++)
+ {
+ unsigned int tix = texel_indexes[j];
+ vfloat4 rgba = blk.texel(tix);
+
+ float idx0 = undec_weight_ref[tix];
+
+ float om_idx0 = 1.0f - idx0;
+ wmin1 = astc::min(idx0, wmin1);
+ wmax1 = astc::max(idx0, wmax1);
+
+ float scale = dot3_s(scale_dir, rgba);
+ scale_min = astc::min(scale, scale_min);
+ scale_max = astc::max(scale, scale_max);
+
+ left_sum_s += om_idx0 * om_idx0;
+ middle_sum_s += om_idx0 * idx0;
+ right_sum_s += idx0 * idx0;
+ weight_weight_sum_s += idx0;
+
+ vfloat4 color_idx(idx0);
+ vfloat4 cwprod = rgba;
+ vfloat4 cwiprod = cwprod * color_idx;
+
+ color_vec_y += cwiprod;
+ color_vec_x += cwprod - cwiprod;
+
+ scale_vec += vfloat2(om_idx0, idx0) * (scale * ls_weight);
+ }
+
+ vfloat4 left_sum = vfloat4(left_sum_s) * color_weight;
+ vfloat4 middle_sum = vfloat4(middle_sum_s) * color_weight;
+ vfloat4 right_sum = vfloat4(right_sum_s) * color_weight;
+ vfloat4 lmrs_sum = vfloat3(left_sum_s, middle_sum_s, right_sum_s) * ls_weight;
+
+ color_vec_x = color_vec_x * color_weight;
+ color_vec_y = color_vec_y * color_weight;
+
+ // Initialize the luminance and scale vectors with a reasonable default
+ float scalediv = scale_min / astc::max(scale_max, 1e-10f);
+ scalediv = astc::clamp1f(scalediv);
+
+ vfloat4 sds = scale_dir * scale_max;
+
+ rgbs_vectors[i] = vfloat4(sds.lane<0>(), sds.lane<1>(), sds.lane<2>(), scalediv);
+
+ if (wmin1 >= wmax1 * 0.999f)
+ {
+ // If all weights in the partition were equal, then just take average of all colors in
+ // the partition and use that as both endpoint colors
+ vfloat4 avg = (color_vec_x + color_vec_y) / rgba_weight_sum;
+
+ vmask4 notnan_mask = avg == avg;
+ ep.endpt0[i] = select(ep.endpt0[i], avg, notnan_mask);
+ ep.endpt1[i] = select(ep.endpt1[i], avg, notnan_mask);
+
+ rgbs_vectors[i] = vfloat4(sds.lane<0>(), sds.lane<1>(), sds.lane<2>(), 1.0f);
+ }
+ else
+ {
+ // Otherwise, complete the analytic calculation of ideal-endpoint-values for the given
+ // set of texel weights and pixel colors
+ vfloat4 color_det1 = (left_sum * right_sum) - (middle_sum * middle_sum);
+ vfloat4 color_rdet1 = 1.0f / color_det1;
+
+ float ls_det1 = (lmrs_sum.lane<0>() * lmrs_sum.lane<2>()) - (lmrs_sum.lane<1>() * lmrs_sum.lane<1>());
+ float ls_rdet1 = 1.0f / ls_det1;
+
+ vfloat4 color_mss1 = (left_sum * left_sum)
+ + (2.0f * middle_sum * middle_sum)
+ + (right_sum * right_sum);
+
+ float ls_mss1 = (lmrs_sum.lane<0>() * lmrs_sum.lane<0>())
+ + (2.0f * lmrs_sum.lane<1>() * lmrs_sum.lane<1>())
+ + (lmrs_sum.lane<2>() * lmrs_sum.lane<2>());
+
+ vfloat4 ep0 = (right_sum * color_vec_x - middle_sum * color_vec_y) * color_rdet1;
+ vfloat4 ep1 = (left_sum * color_vec_y - middle_sum * color_vec_x) * color_rdet1;
+
+ vmask4 det_mask = abs(color_det1) > (color_mss1 * 1e-4f);
+ vmask4 notnan_mask = (ep0 == ep0) & (ep1 == ep1);
+ vmask4 full_mask = det_mask & notnan_mask;
+
+ ep.endpt0[i] = select(ep.endpt0[i], ep0, full_mask);
+ ep.endpt1[i] = select(ep.endpt1[i], ep1, full_mask);
+
+ float scale_ep0 = (lmrs_sum.lane<2>() * scale_vec.lane<0>() - lmrs_sum.lane<1>() * scale_vec.lane<1>()) * ls_rdet1;
+ float scale_ep1 = (lmrs_sum.lane<0>() * scale_vec.lane<1>() - lmrs_sum.lane<1>() * scale_vec.lane<0>()) * ls_rdet1;
+
+ if (fabsf(ls_det1) > (ls_mss1 * 1e-4f) && scale_ep0 == scale_ep0 && scale_ep1 == scale_ep1 && scale_ep0 < scale_ep1)
+ {
+ float scalediv2 = scale_ep0 / scale_ep1;
+ vfloat4 sdsm = scale_dir * scale_ep1;
+ rgbs_vectors[i] = vfloat4(sdsm.lane<0>(), sdsm.lane<1>(), sdsm.lane<2>(), scalediv2);
+ }
+ }
+
+ // Calculations specific to mode #7, the HDR RGB-scale mode - skip if known LDR
+ if (blk.rgb_lns[0] || blk.alpha_lns[0])
+ {
+ vfloat4 weight_weight_sum = vfloat4(weight_weight_sum_s) * color_weight;
+ float psum = right_sum_s * hadd_rgb_s(color_weight);
+
+ vfloat4 rgbq_sum = color_vec_x + color_vec_y;
+ rgbq_sum.set_lane<3>(hadd_rgb_s(color_vec_y));
+
+ vfloat4 rgbovec = compute_rgbo_vector(rgba_weight_sum, weight_weight_sum, rgbq_sum, psum);
+ rgbo_vectors[i] = rgbovec;
+
+ // We can get a failure due to the use of a singular (non-invertible) matrix
+ // If it failed, compute rgbo_vectors[] with a different method ...
+ if (astc::isnan(dot_s(rgbovec, rgbovec)))
+ {
+ vfloat4 v0 = ep.endpt0[i];
+ vfloat4 v1 = ep.endpt1[i];
+
+ float avgdif = hadd_rgb_s(v1 - v0) * (1.0f / 3.0f);
+ avgdif = astc::max(avgdif, 0.0f);
+
+ vfloat4 avg = (v0 + v1) * 0.5f;
+ vfloat4 ep0 = avg - vfloat4(avgdif) * 0.5f;
+ rgbo_vectors[i] = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), avgdif);
+ }
+ }
+ }
+}
+
+/* See header for documentation. */
+void recompute_ideal_colors_2planes(
+ const image_block& blk,
+ const block_size_descriptor& bsd,
+ const decimation_info& di,
+ const uint8_t* dec_weights_uquant_plane1,
+ const uint8_t* dec_weights_uquant_plane2,
+ endpoints& ep,
+ vfloat4& rgbs_vector,
+ vfloat4& rgbo_vector,
+ int plane2_component
+) {
+ unsigned int weight_count = di.weight_count;
+ unsigned int total_texel_count = blk.texel_count;
+
+ promise(total_texel_count > 0);
+ promise(weight_count > 0);
+
+ alignas(ASTCENC_VECALIGN) float dec_weight_plane1[BLOCK_MAX_WEIGHTS_2PLANE];
+ alignas(ASTCENC_VECALIGN) float dec_weight_plane2[BLOCK_MAX_WEIGHTS_2PLANE];
+
+ assert(weight_count <= BLOCK_MAX_WEIGHTS_2PLANE);
+
+ for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint unquant_value1(dec_weights_uquant_plane1 + i);
+ vfloat unquant_value1f = int_to_float(unquant_value1) * vfloat(1.0f / 64.0f);
+ storea(unquant_value1f, dec_weight_plane1 + i);
+
+ vint unquant_value2(dec_weights_uquant_plane2 + i);
+ vfloat unquant_value2f = int_to_float(unquant_value2) * vfloat(1.0f / 64.0f);
+ storea(unquant_value2f, dec_weight_plane2 + i);
+ }
+
+ alignas(ASTCENC_VECALIGN) float undec_weight_plane1[BLOCK_MAX_TEXELS];
+ alignas(ASTCENC_VECALIGN) float undec_weight_plane2[BLOCK_MAX_TEXELS];
+
+ float* undec_weight_plane1_ref;
+ float* undec_weight_plane2_ref;
+
+ if (di.max_texel_weight_count == 1)
+ {
+ undec_weight_plane1_ref = dec_weight_plane1;
+ undec_weight_plane2_ref = dec_weight_plane2;
+ }
+ else if (di.max_texel_weight_count <= 2)
+ {
+ for (unsigned int i = 0; i < total_texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat weight = bilinear_infill_vla_2(di, dec_weight_plane1, i);
+ storea(weight, undec_weight_plane1 + i);
+
+ weight = bilinear_infill_vla_2(di, dec_weight_plane2, i);
+ storea(weight, undec_weight_plane2 + i);
+ }
+
+ undec_weight_plane1_ref = undec_weight_plane1;
+ undec_weight_plane2_ref = undec_weight_plane2;
+ }
+ else
+ {
+ for (unsigned int i = 0; i < total_texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat weight = bilinear_infill_vla(di, dec_weight_plane1, i);
+ storea(weight, undec_weight_plane1 + i);
+
+ weight = bilinear_infill_vla(di, dec_weight_plane2, i);
+ storea(weight, undec_weight_plane2 + i);
+ }
+
+ undec_weight_plane1_ref = undec_weight_plane1;
+ undec_weight_plane2_ref = undec_weight_plane2;
+ }
+
+ unsigned int texel_count = bsd.texel_count;
+ vfloat4 rgba_weight_sum = max(blk.channel_weight * static_cast<float>(texel_count), 1e-17f);
+ vfloat4 scale_dir = normalize(blk.data_mean.swz<0, 1, 2>());
+
+ float scale_max = 0.0f;
+ float scale_min = 1e10f;
+
+ float wmin1 = 1.0f;
+ float wmax1 = 0.0f;
+
+ float wmin2 = 1.0f;
+ float wmax2 = 0.0f;
+
+ float left1_sum_s = 0.0f;
+ float middle1_sum_s = 0.0f;
+ float right1_sum_s = 0.0f;
+
+ float left2_sum_s = 0.0f;
+ float middle2_sum_s = 0.0f;
+ float right2_sum_s = 0.0f;
+
+ vfloat4 color_vec_x = vfloat4::zero();
+ vfloat4 color_vec_y = vfloat4::zero();
+
+ vfloat4 scale_vec = vfloat4::zero();
+
+ vfloat4 weight_weight_sum = vfloat4(1e-17f);
+
+ vmask4 p2_mask = vint4::lane_id() == vint4(plane2_component);
+ vfloat4 color_weight = blk.channel_weight;
+ float ls_weight = hadd_rgb_s(color_weight);
+
+ for (unsigned int j = 0; j < texel_count; j++)
+ {
+ vfloat4 rgba = blk.texel(j);
+
+ float idx0 = undec_weight_plane1_ref[j];
+
+ float om_idx0 = 1.0f - idx0;
+ wmin1 = astc::min(idx0, wmin1);
+ wmax1 = astc::max(idx0, wmax1);
+
+ float scale = dot3_s(scale_dir, rgba);
+ scale_min = astc::min(scale, scale_min);
+ scale_max = astc::max(scale, scale_max);
+
+ left1_sum_s += om_idx0 * om_idx0;
+ middle1_sum_s += om_idx0 * idx0;
+ right1_sum_s += idx0 * idx0;
+
+ float idx1 = undec_weight_plane2_ref[j];
+
+ float om_idx1 = 1.0f - idx1;
+ wmin2 = astc::min(idx1, wmin2);
+ wmax2 = astc::max(idx1, wmax2);
+
+ left2_sum_s += om_idx1 * om_idx1;
+ middle2_sum_s += om_idx1 * idx1;
+ right2_sum_s += idx1 * idx1;
+
+ vfloat4 color_idx = select(vfloat4(idx0), vfloat4(idx1), p2_mask);
+
+ vfloat4 cwprod = rgba;
+ vfloat4 cwiprod = cwprod * color_idx;
+
+ color_vec_y += cwiprod;
+ color_vec_x += cwprod - cwiprod;
+
+ scale_vec += vfloat2(om_idx0, idx0) * (ls_weight * scale);
+ weight_weight_sum += color_idx;
+ }
+
+ vfloat4 left1_sum = vfloat4(left1_sum_s) * color_weight;
+ vfloat4 middle1_sum = vfloat4(middle1_sum_s) * color_weight;
+ vfloat4 right1_sum = vfloat4(right1_sum_s) * color_weight;
+ vfloat4 lmrs_sum = vfloat3(left1_sum_s, middle1_sum_s, right1_sum_s) * ls_weight;
+
+ vfloat4 left2_sum = vfloat4(left2_sum_s) * color_weight;
+ vfloat4 middle2_sum = vfloat4(middle2_sum_s) * color_weight;
+ vfloat4 right2_sum = vfloat4(right2_sum_s) * color_weight;
+
+ color_vec_x = color_vec_x * color_weight;
+ color_vec_y = color_vec_y * color_weight;
+
+ // Initialize the luminance and scale vectors with a reasonable default
+ float scalediv = scale_min / astc::max(scale_max, 1e-10f);
+ scalediv = astc::clamp1f(scalediv);
+
+ vfloat4 sds = scale_dir * scale_max;
+
+ rgbs_vector = vfloat4(sds.lane<0>(), sds.lane<1>(), sds.lane<2>(), scalediv);
+
+ if (wmin1 >= wmax1 * 0.999f)
+ {
+ // If all weights in the partition were equal, then just take average of all colors in
+ // the partition and use that as both endpoint colors
+ vfloat4 avg = (color_vec_x + color_vec_y) / rgba_weight_sum;
+
+ vmask4 p1_mask = vint4::lane_id() != vint4(plane2_component);
+ vmask4 notnan_mask = avg == avg;
+ vmask4 full_mask = p1_mask & notnan_mask;
+
+ ep.endpt0[0] = select(ep.endpt0[0], avg, full_mask);
+ ep.endpt1[0] = select(ep.endpt1[0], avg, full_mask);
+
+ rgbs_vector = vfloat4(sds.lane<0>(), sds.lane<1>(), sds.lane<2>(), 1.0f);
+ }
+ else
+ {
+ // Otherwise, complete the analytic calculation of ideal-endpoint-values for the given
+ // set of texel weights and pixel colors
+ vfloat4 color_det1 = (left1_sum * right1_sum) - (middle1_sum * middle1_sum);
+ vfloat4 color_rdet1 = 1.0f / color_det1;
+
+ float ls_det1 = (lmrs_sum.lane<0>() * lmrs_sum.lane<2>()) - (lmrs_sum.lane<1>() * lmrs_sum.lane<1>());
+ float ls_rdet1 = 1.0f / ls_det1;
+
+ vfloat4 color_mss1 = (left1_sum * left1_sum)
+ + (2.0f * middle1_sum * middle1_sum)
+ + (right1_sum * right1_sum);
+
+ float ls_mss1 = (lmrs_sum.lane<0>() * lmrs_sum.lane<0>())
+ + (2.0f * lmrs_sum.lane<1>() * lmrs_sum.lane<1>())
+ + (lmrs_sum.lane<2>() * lmrs_sum.lane<2>());
+
+ vfloat4 ep0 = (right1_sum * color_vec_x - middle1_sum * color_vec_y) * color_rdet1;
+ vfloat4 ep1 = (left1_sum * color_vec_y - middle1_sum * color_vec_x) * color_rdet1;
+
+ float scale_ep0 = (lmrs_sum.lane<2>() * scale_vec.lane<0>() - lmrs_sum.lane<1>() * scale_vec.lane<1>()) * ls_rdet1;
+ float scale_ep1 = (lmrs_sum.lane<0>() * scale_vec.lane<1>() - lmrs_sum.lane<1>() * scale_vec.lane<0>()) * ls_rdet1;
+
+ vmask4 p1_mask = vint4::lane_id() != vint4(plane2_component);
+ vmask4 det_mask = abs(color_det1) > (color_mss1 * 1e-4f);
+ vmask4 notnan_mask = (ep0 == ep0) & (ep1 == ep1);
+ vmask4 full_mask = p1_mask & det_mask & notnan_mask;
+
+ ep.endpt0[0] = select(ep.endpt0[0], ep0, full_mask);
+ ep.endpt1[0] = select(ep.endpt1[0], ep1, full_mask);
+
+ if (fabsf(ls_det1) > (ls_mss1 * 1e-4f) && scale_ep0 == scale_ep0 && scale_ep1 == scale_ep1 && scale_ep0 < scale_ep1)
+ {
+ float scalediv2 = scale_ep0 / scale_ep1;
+ vfloat4 sdsm = scale_dir * scale_ep1;
+ rgbs_vector = vfloat4(sdsm.lane<0>(), sdsm.lane<1>(), sdsm.lane<2>(), scalediv2);
+ }
+ }
+
+ if (wmin2 >= wmax2 * 0.999f)
+ {
+ // If all weights in the partition were equal, then just take average of all colors in
+ // the partition and use that as both endpoint colors
+ vfloat4 avg = (color_vec_x + color_vec_y) / rgba_weight_sum;
+
+ vmask4 notnan_mask = avg == avg;
+ vmask4 full_mask = p2_mask & notnan_mask;
+
+ ep.endpt0[0] = select(ep.endpt0[0], avg, full_mask);
+ ep.endpt1[0] = select(ep.endpt1[0], avg, full_mask);
+ }
+ else
+ {
+ // Otherwise, complete the analytic calculation of ideal-endpoint-values for the given
+ // set of texel weights and pixel colors
+ vfloat4 color_det2 = (left2_sum * right2_sum) - (middle2_sum * middle2_sum);
+ vfloat4 color_rdet2 = 1.0f / color_det2;
+
+ vfloat4 color_mss2 = (left2_sum * left2_sum)
+ + (2.0f * middle2_sum * middle2_sum)
+ + (right2_sum * right2_sum);
+
+ vfloat4 ep0 = (right2_sum * color_vec_x - middle2_sum * color_vec_y) * color_rdet2;
+ vfloat4 ep1 = (left2_sum * color_vec_y - middle2_sum * color_vec_x) * color_rdet2;
+
+ vmask4 det_mask = abs(color_det2) > (color_mss2 * 1e-4f);
+ vmask4 notnan_mask = (ep0 == ep0) & (ep1 == ep1);
+ vmask4 full_mask = p2_mask & det_mask & notnan_mask;
+
+ ep.endpt0[0] = select(ep.endpt0[0], ep0, full_mask);
+ ep.endpt1[0] = select(ep.endpt1[0], ep1, full_mask);
+ }
+
+ // Calculations specific to mode #7, the HDR RGB-scale mode - skip if known LDR
+ if (blk.rgb_lns[0] || blk.alpha_lns[0])
+ {
+ weight_weight_sum = weight_weight_sum * color_weight;
+ float psum = dot3_s(select(right1_sum, right2_sum, p2_mask), color_weight);
+
+ vfloat4 rgbq_sum = color_vec_x + color_vec_y;
+ rgbq_sum.set_lane<3>(hadd_rgb_s(color_vec_y));
+
+ rgbo_vector = compute_rgbo_vector(rgba_weight_sum, weight_weight_sum, rgbq_sum, psum);
+
+ // We can get a failure due to the use of a singular (non-invertible) matrix
+ // If it failed, compute rgbo_vectors[] with a different method ...
+ if (astc::isnan(dot_s(rgbo_vector, rgbo_vector)))
+ {
+ vfloat4 v0 = ep.endpt0[0];
+ vfloat4 v1 = ep.endpt1[0];
+
+ float avgdif = hadd_rgb_s(v1 - v0) * (1.0f / 3.0f);
+ avgdif = astc::max(avgdif, 0.0f);
+
+ vfloat4 avg = (v0 + v1) * 0.5f;
+ vfloat4 ep0 = avg - vfloat4(avgdif) * 0.5f;
+
+ rgbo_vector = vfloat4(ep0.lane<0>(), ep0.lane<1>(), ep0.lane<2>(), avgdif);
+ }
+ }
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_image.cpp b/thirdparty/astcenc/astcenc_image.cpp
new file mode 100644
index 0000000000..9c0d6727d0
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_image.cpp
@@ -0,0 +1,558 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for creating in-memory ASTC image structures.
+ */
+
+#include <cassert>
+#include <cstring>
+
+#include "astcenc_internal.h"
+
+/**
+ * @brief Loader pipeline function type for data fetch from memory.
+ */
+using pixel_loader = vfloat4(*)(const void*, int);
+
+/**
+ * @brief Loader pipeline function type for swizzling data in a vector.
+ */
+using pixel_swizzler = vfloat4(*)(vfloat4, const astcenc_swizzle&);
+
+/**
+ * @brief Loader pipeline function type for converting data in a vector to LNS.
+ */
+using pixel_converter = vfloat4(*)(vfloat4, vmask4);
+
+/**
+ * @brief Load a 8-bit UNORM texel from a data array.
+ *
+ * @param data The data pointer.
+ * @param base_offset The index offset to the start of the pixel.
+ */
+static vfloat4 load_texel_u8(
+ const void* data,
+ int base_offset
+) {
+ const uint8_t* data8 = static_cast<const uint8_t*>(data);
+ return int_to_float(vint4(data8 + base_offset)) / 255.0f;
+}
+
+/**
+ * @brief Load a 16-bit fp16 texel from a data array.
+ *
+ * @param data The data pointer.
+ * @param base_offset The index offset to the start of the pixel.
+ */
+static vfloat4 load_texel_f16(
+ const void* data,
+ int base_offset
+) {
+ const uint16_t* data16 = static_cast<const uint16_t*>(data);
+ int r = data16[base_offset ];
+ int g = data16[base_offset + 1];
+ int b = data16[base_offset + 2];
+ int a = data16[base_offset + 3];
+ return float16_to_float(vint4(r, g, b, a));
+}
+
+/**
+ * @brief Load a 32-bit float texel from a data array.
+ *
+ * @param data The data pointer.
+ * @param base_offset The index offset to the start of the pixel.
+ */
+static vfloat4 load_texel_f32(
+ const void* data,
+ int base_offset
+) {
+ const float* data32 = static_cast<const float*>(data);
+ return vfloat4(data32 + base_offset);
+}
+
+/**
+ * @brief Dummy no-op swizzle function.
+ *
+ * @param data The source RGBA vector to swizzle.
+ * @param swz The swizzle to use.
+ */
+static vfloat4 swz_texel_skip(
+ vfloat4 data,
+ const astcenc_swizzle& swz
+) {
+ (void)swz;
+ return data;
+}
+
+/**
+ * @brief Swizzle a texel into a new arrangement.
+ *
+ * @param data The source RGBA vector to swizzle.
+ * @param swz The swizzle to use.
+ */
+static vfloat4 swz_texel(
+ vfloat4 data,
+ const astcenc_swizzle& swz
+) {
+ alignas(16) float datas[6];
+
+ storea(data, datas);
+ datas[ASTCENC_SWZ_0] = 0.0f;
+ datas[ASTCENC_SWZ_1] = 1.0f;
+
+ return vfloat4(datas[swz.r], datas[swz.g], datas[swz.b], datas[swz.a]);
+}
+
+/**
+ * @brief Encode a texel that is entirely LDR linear.
+ *
+ * @param data The RGBA data to encode.
+ * @param lns_mask The mask for the HDR channels than need LNS encoding.
+ */
+static vfloat4 encode_texel_unorm(
+ vfloat4 data,
+ vmask4 lns_mask
+) {
+ (void)lns_mask;
+ return data * 65535.0f;
+}
+
+/**
+ * @brief Encode a texel that includes at least some HDR LNS texels.
+ *
+ * @param data The RGBA data to encode.
+ * @param lns_mask The mask for the HDR channels than need LNS encoding.
+ */
+static vfloat4 encode_texel_lns(
+ vfloat4 data,
+ vmask4 lns_mask
+) {
+ vfloat4 datav_unorm = data * 65535.0f;
+ vfloat4 datav_lns = float_to_lns(data);
+ return select(datav_unorm, datav_lns, lns_mask);
+}
+
+/* See header for documentation. */
+void load_image_block(
+ astcenc_profile decode_mode,
+ const astcenc_image& img,
+ image_block& blk,
+ const block_size_descriptor& bsd,
+ unsigned int xpos,
+ unsigned int ypos,
+ unsigned int zpos,
+ const astcenc_swizzle& swz
+) {
+ unsigned int xsize = img.dim_x;
+ unsigned int ysize = img.dim_y;
+ unsigned int zsize = img.dim_z;
+
+ blk.xpos = xpos;
+ blk.ypos = ypos;
+ blk.zpos = zpos;
+
+ // True if any non-identity swizzle
+ bool needs_swz = (swz.r != ASTCENC_SWZ_R) || (swz.g != ASTCENC_SWZ_G) ||
+ (swz.b != ASTCENC_SWZ_B) || (swz.a != ASTCENC_SWZ_A);
+
+ int idx = 0;
+
+ vfloat4 data_min(1e38f);
+ vfloat4 data_mean(0.0f);
+ vfloat4 data_mean_scale(1.0f / static_cast<float>(bsd.texel_count));
+ vfloat4 data_max(-1e38f);
+ vmask4 grayscalev(true);
+
+ // This works because we impose the same choice everywhere during encode
+ uint8_t rgb_lns = (decode_mode == ASTCENC_PRF_HDR) ||
+ (decode_mode == ASTCENC_PRF_HDR_RGB_LDR_A) ? 1 : 0;
+ uint8_t a_lns = decode_mode == ASTCENC_PRF_HDR ? 1 : 0;
+ vint4 use_lns(rgb_lns, rgb_lns, rgb_lns, a_lns);
+ vmask4 lns_mask = use_lns != vint4::zero();
+
+ // Set up the function pointers for loading pipeline as needed
+ pixel_loader loader = load_texel_u8;
+ if (img.data_type == ASTCENC_TYPE_F16)
+ {
+ loader = load_texel_f16;
+ }
+ else if (img.data_type == ASTCENC_TYPE_F32)
+ {
+ loader = load_texel_f32;
+ }
+
+ pixel_swizzler swizzler = swz_texel_skip;
+ if (needs_swz)
+ {
+ swizzler = swz_texel;
+ }
+
+ pixel_converter converter = encode_texel_unorm;
+ if (any(lns_mask))
+ {
+ converter = encode_texel_lns;
+ }
+
+ for (unsigned int z = 0; z < bsd.zdim; z++)
+ {
+ unsigned int zi = astc::min(zpos + z, zsize - 1);
+ void* plane = img.data[zi];
+
+ for (unsigned int y = 0; y < bsd.ydim; y++)
+ {
+ unsigned int yi = astc::min(ypos + y, ysize - 1);
+
+ for (unsigned int x = 0; x < bsd.xdim; x++)
+ {
+ unsigned int xi = astc::min(xpos + x, xsize - 1);
+
+ vfloat4 datav = loader(plane, (4 * xsize * yi) + (4 * xi));
+ datav = swizzler(datav, swz);
+ datav = converter(datav, lns_mask);
+
+ // Compute block metadata
+ data_min = min(data_min, datav);
+ data_mean += datav * data_mean_scale;
+ data_max = max(data_max, datav);
+
+ grayscalev = grayscalev & (datav.swz<0,0,0,0>() == datav.swz<1,1,2,2>());
+
+ blk.data_r[idx] = datav.lane<0>();
+ blk.data_g[idx] = datav.lane<1>();
+ blk.data_b[idx] = datav.lane<2>();
+ blk.data_a[idx] = datav.lane<3>();
+
+ blk.rgb_lns[idx] = rgb_lns;
+ blk.alpha_lns[idx] = a_lns;
+
+ idx++;
+ }
+ }
+ }
+
+ // Reverse the encoding so we store origin block in the original format
+ vfloat4 data_enc = blk.texel(0);
+ vfloat4 data_enc_unorm = data_enc / 65535.0f;
+ vfloat4 data_enc_lns = vfloat4::zero();
+
+ if (rgb_lns || a_lns)
+ {
+ data_enc_lns = float16_to_float(lns_to_sf16(float_to_int(data_enc)));
+ }
+
+ blk.origin_texel = select(data_enc_unorm, data_enc_lns, lns_mask);
+
+ // Store block metadata
+ blk.data_min = data_min;
+ blk.data_mean = data_mean;
+ blk.data_max = data_max;
+ blk.grayscale = all(grayscalev);
+}
+
+/* See header for documentation. */
+void load_image_block_fast_ldr(
+ astcenc_profile decode_mode,
+ const astcenc_image& img,
+ image_block& blk,
+ const block_size_descriptor& bsd,
+ unsigned int xpos,
+ unsigned int ypos,
+ unsigned int zpos,
+ const astcenc_swizzle& swz
+) {
+ (void)swz;
+ (void)decode_mode;
+
+ unsigned int xsize = img.dim_x;
+ unsigned int ysize = img.dim_y;
+
+ blk.xpos = xpos;
+ blk.ypos = ypos;
+ blk.zpos = zpos;
+
+ vfloat4 data_min(1e38f);
+ vfloat4 data_mean = vfloat4::zero();
+ vfloat4 data_max(-1e38f);
+ vmask4 grayscalev(true);
+ int idx = 0;
+
+ const uint8_t* plane = static_cast<const uint8_t*>(img.data[0]);
+ for (unsigned int y = ypos; y < ypos + bsd.ydim; y++)
+ {
+ unsigned int yi = astc::min(y, ysize - 1);
+
+ for (unsigned int x = xpos; x < xpos + bsd.xdim; x++)
+ {
+ unsigned int xi = astc::min(x, xsize - 1);
+
+ vint4 datavi = vint4(plane + (4 * xsize * yi) + (4 * xi));
+ vfloat4 datav = int_to_float(datavi) * (65535.0f / 255.0f);
+
+ // Compute block metadata
+ data_min = min(data_min, datav);
+ data_mean += datav;
+ data_max = max(data_max, datav);
+
+ grayscalev = grayscalev & (datav.swz<0,0,0,0>() == datav.swz<1,1,2,2>());
+
+ blk.data_r[idx] = datav.lane<0>();
+ blk.data_g[idx] = datav.lane<1>();
+ blk.data_b[idx] = datav.lane<2>();
+ blk.data_a[idx] = datav.lane<3>();
+
+ idx++;
+ }
+ }
+
+ // Reverse the encoding so we store origin block in the original format
+ blk.origin_texel = blk.texel(0) / 65535.0f;
+
+ // Store block metadata
+ blk.rgb_lns[0] = 0;
+ blk.alpha_lns[0] = 0;
+ blk.data_min = data_min;
+ blk.data_mean = data_mean / static_cast<float>(bsd.texel_count);
+ blk.data_max = data_max;
+ blk.grayscale = all(grayscalev);
+}
+
+/* See header for documentation. */
+void store_image_block(
+ astcenc_image& img,
+ const image_block& blk,
+ const block_size_descriptor& bsd,
+ unsigned int xpos,
+ unsigned int ypos,
+ unsigned int zpos,
+ const astcenc_swizzle& swz
+) {
+ unsigned int x_size = img.dim_x;
+ unsigned int x_start = xpos;
+ unsigned int x_end = astc::min(x_size, xpos + bsd.xdim);
+ unsigned int x_count = x_end - x_start;
+ unsigned int x_nudge = bsd.xdim - x_count;
+
+ unsigned int y_size = img.dim_y;
+ unsigned int y_start = ypos;
+ unsigned int y_end = astc::min(y_size, ypos + bsd.ydim);
+ unsigned int y_count = y_end - y_start;
+ unsigned int y_nudge = (bsd.ydim - y_count) * bsd.xdim;
+
+ unsigned int z_size = img.dim_z;
+ unsigned int z_start = zpos;
+ unsigned int z_end = astc::min(z_size, zpos + bsd.zdim);
+
+ // True if any non-identity swizzle
+ bool needs_swz = (swz.r != ASTCENC_SWZ_R) || (swz.g != ASTCENC_SWZ_G) ||
+ (swz.b != ASTCENC_SWZ_B) || (swz.a != ASTCENC_SWZ_A);
+
+ // True if any swizzle uses Z reconstruct
+ bool needs_z = (swz.r == ASTCENC_SWZ_Z) || (swz.g == ASTCENC_SWZ_Z) ||
+ (swz.b == ASTCENC_SWZ_Z) || (swz.a == ASTCENC_SWZ_Z);
+
+ int idx = 0;
+ if (img.data_type == ASTCENC_TYPE_U8)
+ {
+ for (unsigned int z = z_start; z < z_end; z++)
+ {
+ // Fetch the image plane
+ uint8_t* data8 = static_cast<uint8_t*>(img.data[z]);
+
+ for (unsigned int y = y_start; y < y_end; y++)
+ {
+ uint8_t* data8_row = data8 + (4 * x_size * y) + (4 * x_start);
+
+ for (unsigned int x = 0; x < x_count; x += ASTCENC_SIMD_WIDTH)
+ {
+ unsigned int max_texels = ASTCENC_SIMD_WIDTH;
+ unsigned int used_texels = astc::min(x_count - x, max_texels);
+
+ // Unaligned load as rows are not always SIMD_WIDTH long
+ vfloat data_r(blk.data_r + idx);
+ vfloat data_g(blk.data_g + idx);
+ vfloat data_b(blk.data_b + idx);
+ vfloat data_a(blk.data_a + idx);
+
+ vint data_ri = float_to_int_rtn(min(data_r, 1.0f) * 255.0f);
+ vint data_gi = float_to_int_rtn(min(data_g, 1.0f) * 255.0f);
+ vint data_bi = float_to_int_rtn(min(data_b, 1.0f) * 255.0f);
+ vint data_ai = float_to_int_rtn(min(data_a, 1.0f) * 255.0f);
+
+ if (needs_swz)
+ {
+ vint swizzle_table[7];
+ swizzle_table[ASTCENC_SWZ_0] = vint(0);
+ swizzle_table[ASTCENC_SWZ_1] = vint(255);
+ swizzle_table[ASTCENC_SWZ_R] = data_ri;
+ swizzle_table[ASTCENC_SWZ_G] = data_gi;
+ swizzle_table[ASTCENC_SWZ_B] = data_bi;
+ swizzle_table[ASTCENC_SWZ_A] = data_ai;
+
+ if (needs_z)
+ {
+ vfloat data_x = (data_r * vfloat(2.0f)) - vfloat(1.0f);
+ vfloat data_y = (data_a * vfloat(2.0f)) - vfloat(1.0f);
+ vfloat data_z = vfloat(1.0f) - (data_x * data_x) - (data_y * data_y);
+ data_z = max(data_z, 0.0f);
+ data_z = (sqrt(data_z) * vfloat(0.5f)) + vfloat(0.5f);
+
+ swizzle_table[ASTCENC_SWZ_Z] = float_to_int_rtn(min(data_z, 1.0f) * 255.0f);
+ }
+
+ data_ri = swizzle_table[swz.r];
+ data_gi = swizzle_table[swz.g];
+ data_bi = swizzle_table[swz.b];
+ data_ai = swizzle_table[swz.a];
+ }
+
+ // Errors are NaN encoded - convert to magenta error color
+ // Branch is OK here - it is almost never true so predicts well
+ vmask nan_mask = data_r != data_r;
+ if (any(nan_mask))
+ {
+ data_ri = select(data_ri, vint(0xFF), nan_mask);
+ data_gi = select(data_gi, vint(0x00), nan_mask);
+ data_bi = select(data_bi, vint(0xFF), nan_mask);
+ data_ai = select(data_ai, vint(0xFF), nan_mask);
+ }
+
+ vint data_rgbai = interleave_rgba8(data_ri, data_gi, data_bi, data_ai);
+ vmask store_mask = vint::lane_id() < vint(used_texels);
+ store_lanes_masked(reinterpret_cast<int*>(data8_row), data_rgbai, store_mask);
+
+ data8_row += ASTCENC_SIMD_WIDTH * 4;
+ idx += used_texels;
+ }
+ idx += x_nudge;
+ }
+ idx += y_nudge;
+ }
+ }
+ else if (img.data_type == ASTCENC_TYPE_F16)
+ {
+ for (unsigned int z = z_start; z < z_end; z++)
+ {
+ // Fetch the image plane
+ uint16_t* data16 = static_cast<uint16_t*>(img.data[z]);
+
+ for (unsigned int y = y_start; y < y_end; y++)
+ {
+ uint16_t* data16_row = data16 + (4 * x_size * y) + (4 * x_start);
+
+ for (unsigned int x = 0; x < x_count; x++)
+ {
+ vint4 color;
+
+ // NaNs are handled inline - no need to special case
+ if (needs_swz)
+ {
+ float data[7];
+ data[ASTCENC_SWZ_0] = 0.0f;
+ data[ASTCENC_SWZ_1] = 1.0f;
+ data[ASTCENC_SWZ_R] = blk.data_r[idx];
+ data[ASTCENC_SWZ_G] = blk.data_g[idx];
+ data[ASTCENC_SWZ_B] = blk.data_b[idx];
+ data[ASTCENC_SWZ_A] = blk.data_a[idx];
+
+ if (needs_z)
+ {
+ float xN = (data[0] * 2.0f) - 1.0f;
+ float yN = (data[3] * 2.0f) - 1.0f;
+ float zN = 1.0f - xN * xN - yN * yN;
+ if (zN < 0.0f)
+ {
+ zN = 0.0f;
+ }
+ data[ASTCENC_SWZ_Z] = (astc::sqrt(zN) * 0.5f) + 0.5f;
+ }
+
+ vfloat4 colorf(data[swz.r], data[swz.g], data[swz.b], data[swz.a]);
+ color = float_to_float16(colorf);
+ }
+ else
+ {
+ vfloat4 colorf = blk.texel(idx);
+ color = float_to_float16(colorf);
+ }
+
+ // TODO: Vectorize with store N shorts?
+ data16_row[0] = static_cast<uint16_t>(color.lane<0>());
+ data16_row[1] = static_cast<uint16_t>(color.lane<1>());
+ data16_row[2] = static_cast<uint16_t>(color.lane<2>());
+ data16_row[3] = static_cast<uint16_t>(color.lane<3>());
+ data16_row += 4;
+ idx++;
+ }
+ idx += x_nudge;
+ }
+ idx += y_nudge;
+ }
+ }
+ else // if (img.data_type == ASTCENC_TYPE_F32)
+ {
+ assert(img.data_type == ASTCENC_TYPE_F32);
+
+ for (unsigned int z = z_start; z < z_end; z++)
+ {
+ // Fetch the image plane
+ float* data32 = static_cast<float*>(img.data[z]);
+
+ for (unsigned int y = y_start; y < y_end; y++)
+ {
+ float* data32_row = data32 + (4 * x_size * y) + (4 * x_start);
+
+ for (unsigned int x = 0; x < x_count; x++)
+ {
+ vfloat4 color = blk.texel(idx);
+
+ // NaNs are handled inline - no need to special case
+ if (needs_swz)
+ {
+ float data[7];
+ data[ASTCENC_SWZ_0] = 0.0f;
+ data[ASTCENC_SWZ_1] = 1.0f;
+ data[ASTCENC_SWZ_R] = color.lane<0>();
+ data[ASTCENC_SWZ_G] = color.lane<1>();
+ data[ASTCENC_SWZ_B] = color.lane<2>();
+ data[ASTCENC_SWZ_A] = color.lane<3>();
+
+ if (needs_z)
+ {
+ float xN = (data[0] * 2.0f) - 1.0f;
+ float yN = (data[3] * 2.0f) - 1.0f;
+ float zN = 1.0f - xN * xN - yN * yN;
+ if (zN < 0.0f)
+ {
+ zN = 0.0f;
+ }
+ data[ASTCENC_SWZ_Z] = (astc::sqrt(zN) * 0.5f) + 0.5f;
+ }
+
+ color = vfloat4(data[swz.r], data[swz.g], data[swz.b], data[swz.a]);
+ }
+
+ store(color, data32_row);
+ data32_row += 4;
+ idx++;
+ }
+ idx += x_nudge;
+ }
+ idx += y_nudge;
+ }
+ }
+}
diff --git a/thirdparty/astcenc/astcenc_integer_sequence.cpp b/thirdparty/astcenc/astcenc_integer_sequence.cpp
new file mode 100644
index 0000000000..416750374d
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_integer_sequence.cpp
@@ -0,0 +1,739 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for encoding/decoding Bounded Integer Sequence Encoding.
+ */
+
+#include "astcenc_internal.h"
+
+#include <array>
+
+/** @brief Unpacked quint triplets <low,middle,high> for each packed value */
+// TODO: Bitpack these into a uint16_t?
+static const uint8_t quints_of_integer[128][3] {
+ {0, 0, 0}, {1, 0, 0}, {2, 0, 0}, {3, 0, 0},
+ {4, 0, 0}, {0, 4, 0}, {4, 4, 0}, {4, 4, 4},
+ {0, 1, 0}, {1, 1, 0}, {2, 1, 0}, {3, 1, 0},
+ {4, 1, 0}, {1, 4, 0}, {4, 4, 1}, {4, 4, 4},
+ {0, 2, 0}, {1, 2, 0}, {2, 2, 0}, {3, 2, 0},
+ {4, 2, 0}, {2, 4, 0}, {4, 4, 2}, {4, 4, 4},
+ {0, 3, 0}, {1, 3, 0}, {2, 3, 0}, {3, 3, 0},
+ {4, 3, 0}, {3, 4, 0}, {4, 4, 3}, {4, 4, 4},
+ {0, 0, 1}, {1, 0, 1}, {2, 0, 1}, {3, 0, 1},
+ {4, 0, 1}, {0, 4, 1}, {4, 0, 4}, {0, 4, 4},
+ {0, 1, 1}, {1, 1, 1}, {2, 1, 1}, {3, 1, 1},
+ {4, 1, 1}, {1, 4, 1}, {4, 1, 4}, {1, 4, 4},
+ {0, 2, 1}, {1, 2, 1}, {2, 2, 1}, {3, 2, 1},
+ {4, 2, 1}, {2, 4, 1}, {4, 2, 4}, {2, 4, 4},
+ {0, 3, 1}, {1, 3, 1}, {2, 3, 1}, {3, 3, 1},
+ {4, 3, 1}, {3, 4, 1}, {4, 3, 4}, {3, 4, 4},
+ {0, 0, 2}, {1, 0, 2}, {2, 0, 2}, {3, 0, 2},
+ {4, 0, 2}, {0, 4, 2}, {2, 0, 4}, {3, 0, 4},
+ {0, 1, 2}, {1, 1, 2}, {2, 1, 2}, {3, 1, 2},
+ {4, 1, 2}, {1, 4, 2}, {2, 1, 4}, {3, 1, 4},
+ {0, 2, 2}, {1, 2, 2}, {2, 2, 2}, {3, 2, 2},
+ {4, 2, 2}, {2, 4, 2}, {2, 2, 4}, {3, 2, 4},
+ {0, 3, 2}, {1, 3, 2}, {2, 3, 2}, {3, 3, 2},
+ {4, 3, 2}, {3, 4, 2}, {2, 3, 4}, {3, 3, 4},
+ {0, 0, 3}, {1, 0, 3}, {2, 0, 3}, {3, 0, 3},
+ {4, 0, 3}, {0, 4, 3}, {0, 0, 4}, {1, 0, 4},
+ {0, 1, 3}, {1, 1, 3}, {2, 1, 3}, {3, 1, 3},
+ {4, 1, 3}, {1, 4, 3}, {0, 1, 4}, {1, 1, 4},
+ {0, 2, 3}, {1, 2, 3}, {2, 2, 3}, {3, 2, 3},
+ {4, 2, 3}, {2, 4, 3}, {0, 2, 4}, {1, 2, 4},
+ {0, 3, 3}, {1, 3, 3}, {2, 3, 3}, {3, 3, 3},
+ {4, 3, 3}, {3, 4, 3}, {0, 3, 4}, {1, 3, 4}
+};
+
+/** @brief Packed quint values for each unpacked value, indexed [hi][mid][lo]. */
+static const uint8_t integer_of_quints[5][5][5] {
+ {
+ {0, 1, 2, 3, 4},
+ {8, 9, 10, 11, 12},
+ {16, 17, 18, 19, 20},
+ {24, 25, 26, 27, 28},
+ {5, 13, 21, 29, 6}
+ },
+ {
+ {32, 33, 34, 35, 36},
+ {40, 41, 42, 43, 44},
+ {48, 49, 50, 51, 52},
+ {56, 57, 58, 59, 60},
+ {37, 45, 53, 61, 14}
+ },
+ {
+ {64, 65, 66, 67, 68},
+ {72, 73, 74, 75, 76},
+ {80, 81, 82, 83, 84},
+ {88, 89, 90, 91, 92},
+ {69, 77, 85, 93, 22}
+ },
+ {
+ {96, 97, 98, 99, 100},
+ {104, 105, 106, 107, 108},
+ {112, 113, 114, 115, 116},
+ {120, 121, 122, 123, 124},
+ {101, 109, 117, 125, 30}
+ },
+ {
+ {102, 103, 70, 71, 38},
+ {110, 111, 78, 79, 46},
+ {118, 119, 86, 87, 54},
+ {126, 127, 94, 95, 62},
+ {39, 47, 55, 63, 31}
+ }
+};
+
+/** @brief Unpacked trit quintuplets <low,...,high> for each packed value */
+// TODO: Bitpack these into a uint16_t?
+static const uint8_t trits_of_integer[256][5] {
+ {0, 0, 0, 0, 0}, {1, 0, 0, 0, 0}, {2, 0, 0, 0, 0}, {0, 0, 2, 0, 0},
+ {0, 1, 0, 0, 0}, {1, 1, 0, 0, 0}, {2, 1, 0, 0, 0}, {1, 0, 2, 0, 0},
+ {0, 2, 0, 0, 0}, {1, 2, 0, 0, 0}, {2, 2, 0, 0, 0}, {2, 0, 2, 0, 0},
+ {0, 2, 2, 0, 0}, {1, 2, 2, 0, 0}, {2, 2, 2, 0, 0}, {2, 0, 2, 0, 0},
+ {0, 0, 1, 0, 0}, {1, 0, 1, 0, 0}, {2, 0, 1, 0, 0}, {0, 1, 2, 0, 0},
+ {0, 1, 1, 0, 0}, {1, 1, 1, 0, 0}, {2, 1, 1, 0, 0}, {1, 1, 2, 0, 0},
+ {0, 2, 1, 0, 0}, {1, 2, 1, 0, 0}, {2, 2, 1, 0, 0}, {2, 1, 2, 0, 0},
+ {0, 0, 0, 2, 2}, {1, 0, 0, 2, 2}, {2, 0, 0, 2, 2}, {0, 0, 2, 2, 2},
+ {0, 0, 0, 1, 0}, {1, 0, 0, 1, 0}, {2, 0, 0, 1, 0}, {0, 0, 2, 1, 0},
+ {0, 1, 0, 1, 0}, {1, 1, 0, 1, 0}, {2, 1, 0, 1, 0}, {1, 0, 2, 1, 0},
+ {0, 2, 0, 1, 0}, {1, 2, 0, 1, 0}, {2, 2, 0, 1, 0}, {2, 0, 2, 1, 0},
+ {0, 2, 2, 1, 0}, {1, 2, 2, 1, 0}, {2, 2, 2, 1, 0}, {2, 0, 2, 1, 0},
+ {0, 0, 1, 1, 0}, {1, 0, 1, 1, 0}, {2, 0, 1, 1, 0}, {0, 1, 2, 1, 0},
+ {0, 1, 1, 1, 0}, {1, 1, 1, 1, 0}, {2, 1, 1, 1, 0}, {1, 1, 2, 1, 0},
+ {0, 2, 1, 1, 0}, {1, 2, 1, 1, 0}, {2, 2, 1, 1, 0}, {2, 1, 2, 1, 0},
+ {0, 1, 0, 2, 2}, {1, 1, 0, 2, 2}, {2, 1, 0, 2, 2}, {1, 0, 2, 2, 2},
+ {0, 0, 0, 2, 0}, {1, 0, 0, 2, 0}, {2, 0, 0, 2, 0}, {0, 0, 2, 2, 0},
+ {0, 1, 0, 2, 0}, {1, 1, 0, 2, 0}, {2, 1, 0, 2, 0}, {1, 0, 2, 2, 0},
+ {0, 2, 0, 2, 0}, {1, 2, 0, 2, 0}, {2, 2, 0, 2, 0}, {2, 0, 2, 2, 0},
+ {0, 2, 2, 2, 0}, {1, 2, 2, 2, 0}, {2, 2, 2, 2, 0}, {2, 0, 2, 2, 0},
+ {0, 0, 1, 2, 0}, {1, 0, 1, 2, 0}, {2, 0, 1, 2, 0}, {0, 1, 2, 2, 0},
+ {0, 1, 1, 2, 0}, {1, 1, 1, 2, 0}, {2, 1, 1, 2, 0}, {1, 1, 2, 2, 0},
+ {0, 2, 1, 2, 0}, {1, 2, 1, 2, 0}, {2, 2, 1, 2, 0}, {2, 1, 2, 2, 0},
+ {0, 2, 0, 2, 2}, {1, 2, 0, 2, 2}, {2, 2, 0, 2, 2}, {2, 0, 2, 2, 2},
+ {0, 0, 0, 0, 2}, {1, 0, 0, 0, 2}, {2, 0, 0, 0, 2}, {0, 0, 2, 0, 2},
+ {0, 1, 0, 0, 2}, {1, 1, 0, 0, 2}, {2, 1, 0, 0, 2}, {1, 0, 2, 0, 2},
+ {0, 2, 0, 0, 2}, {1, 2, 0, 0, 2}, {2, 2, 0, 0, 2}, {2, 0, 2, 0, 2},
+ {0, 2, 2, 0, 2}, {1, 2, 2, 0, 2}, {2, 2, 2, 0, 2}, {2, 0, 2, 0, 2},
+ {0, 0, 1, 0, 2}, {1, 0, 1, 0, 2}, {2, 0, 1, 0, 2}, {0, 1, 2, 0, 2},
+ {0, 1, 1, 0, 2}, {1, 1, 1, 0, 2}, {2, 1, 1, 0, 2}, {1, 1, 2, 0, 2},
+ {0, 2, 1, 0, 2}, {1, 2, 1, 0, 2}, {2, 2, 1, 0, 2}, {2, 1, 2, 0, 2},
+ {0, 2, 2, 2, 2}, {1, 2, 2, 2, 2}, {2, 2, 2, 2, 2}, {2, 0, 2, 2, 2},
+ {0, 0, 0, 0, 1}, {1, 0, 0, 0, 1}, {2, 0, 0, 0, 1}, {0, 0, 2, 0, 1},
+ {0, 1, 0, 0, 1}, {1, 1, 0, 0, 1}, {2, 1, 0, 0, 1}, {1, 0, 2, 0, 1},
+ {0, 2, 0, 0, 1}, {1, 2, 0, 0, 1}, {2, 2, 0, 0, 1}, {2, 0, 2, 0, 1},
+ {0, 2, 2, 0, 1}, {1, 2, 2, 0, 1}, {2, 2, 2, 0, 1}, {2, 0, 2, 0, 1},
+ {0, 0, 1, 0, 1}, {1, 0, 1, 0, 1}, {2, 0, 1, 0, 1}, {0, 1, 2, 0, 1},
+ {0, 1, 1, 0, 1}, {1, 1, 1, 0, 1}, {2, 1, 1, 0, 1}, {1, 1, 2, 0, 1},
+ {0, 2, 1, 0, 1}, {1, 2, 1, 0, 1}, {2, 2, 1, 0, 1}, {2, 1, 2, 0, 1},
+ {0, 0, 1, 2, 2}, {1, 0, 1, 2, 2}, {2, 0, 1, 2, 2}, {0, 1, 2, 2, 2},
+ {0, 0, 0, 1, 1}, {1, 0, 0, 1, 1}, {2, 0, 0, 1, 1}, {0, 0, 2, 1, 1},
+ {0, 1, 0, 1, 1}, {1, 1, 0, 1, 1}, {2, 1, 0, 1, 1}, {1, 0, 2, 1, 1},
+ {0, 2, 0, 1, 1}, {1, 2, 0, 1, 1}, {2, 2, 0, 1, 1}, {2, 0, 2, 1, 1},
+ {0, 2, 2, 1, 1}, {1, 2, 2, 1, 1}, {2, 2, 2, 1, 1}, {2, 0, 2, 1, 1},
+ {0, 0, 1, 1, 1}, {1, 0, 1, 1, 1}, {2, 0, 1, 1, 1}, {0, 1, 2, 1, 1},
+ {0, 1, 1, 1, 1}, {1, 1, 1, 1, 1}, {2, 1, 1, 1, 1}, {1, 1, 2, 1, 1},
+ {0, 2, 1, 1, 1}, {1, 2, 1, 1, 1}, {2, 2, 1, 1, 1}, {2, 1, 2, 1, 1},
+ {0, 1, 1, 2, 2}, {1, 1, 1, 2, 2}, {2, 1, 1, 2, 2}, {1, 1, 2, 2, 2},
+ {0, 0, 0, 2, 1}, {1, 0, 0, 2, 1}, {2, 0, 0, 2, 1}, {0, 0, 2, 2, 1},
+ {0, 1, 0, 2, 1}, {1, 1, 0, 2, 1}, {2, 1, 0, 2, 1}, {1, 0, 2, 2, 1},
+ {0, 2, 0, 2, 1}, {1, 2, 0, 2, 1}, {2, 2, 0, 2, 1}, {2, 0, 2, 2, 1},
+ {0, 2, 2, 2, 1}, {1, 2, 2, 2, 1}, {2, 2, 2, 2, 1}, {2, 0, 2, 2, 1},
+ {0, 0, 1, 2, 1}, {1, 0, 1, 2, 1}, {2, 0, 1, 2, 1}, {0, 1, 2, 2, 1},
+ {0, 1, 1, 2, 1}, {1, 1, 1, 2, 1}, {2, 1, 1, 2, 1}, {1, 1, 2, 2, 1},
+ {0, 2, 1, 2, 1}, {1, 2, 1, 2, 1}, {2, 2, 1, 2, 1}, {2, 1, 2, 2, 1},
+ {0, 2, 1, 2, 2}, {1, 2, 1, 2, 2}, {2, 2, 1, 2, 2}, {2, 1, 2, 2, 2},
+ {0, 0, 0, 1, 2}, {1, 0, 0, 1, 2}, {2, 0, 0, 1, 2}, {0, 0, 2, 1, 2},
+ {0, 1, 0, 1, 2}, {1, 1, 0, 1, 2}, {2, 1, 0, 1, 2}, {1, 0, 2, 1, 2},
+ {0, 2, 0, 1, 2}, {1, 2, 0, 1, 2}, {2, 2, 0, 1, 2}, {2, 0, 2, 1, 2},
+ {0, 2, 2, 1, 2}, {1, 2, 2, 1, 2}, {2, 2, 2, 1, 2}, {2, 0, 2, 1, 2},
+ {0, 0, 1, 1, 2}, {1, 0, 1, 1, 2}, {2, 0, 1, 1, 2}, {0, 1, 2, 1, 2},
+ {0, 1, 1, 1, 2}, {1, 1, 1, 1, 2}, {2, 1, 1, 1, 2}, {1, 1, 2, 1, 2},
+ {0, 2, 1, 1, 2}, {1, 2, 1, 1, 2}, {2, 2, 1, 1, 2}, {2, 1, 2, 1, 2},
+ {0, 2, 2, 2, 2}, {1, 2, 2, 2, 2}, {2, 2, 2, 2, 2}, {2, 1, 2, 2, 2}
+};
+
+/** @brief Packed trit values for each unpacked value, indexed [hi][][][][lo]. */
+static const uint8_t integer_of_trits[3][3][3][3][3] {
+ {
+ {
+ {
+ {0, 1, 2},
+ {4, 5, 6},
+ {8, 9, 10}
+ },
+ {
+ {16, 17, 18},
+ {20, 21, 22},
+ {24, 25, 26}
+ },
+ {
+ {3, 7, 15},
+ {19, 23, 27},
+ {12, 13, 14}
+ }
+ },
+ {
+ {
+ {32, 33, 34},
+ {36, 37, 38},
+ {40, 41, 42}
+ },
+ {
+ {48, 49, 50},
+ {52, 53, 54},
+ {56, 57, 58}
+ },
+ {
+ {35, 39, 47},
+ {51, 55, 59},
+ {44, 45, 46}
+ }
+ },
+ {
+ {
+ {64, 65, 66},
+ {68, 69, 70},
+ {72, 73, 74}
+ },
+ {
+ {80, 81, 82},
+ {84, 85, 86},
+ {88, 89, 90}
+ },
+ {
+ {67, 71, 79},
+ {83, 87, 91},
+ {76, 77, 78}
+ }
+ }
+ },
+ {
+ {
+ {
+ {128, 129, 130},
+ {132, 133, 134},
+ {136, 137, 138}
+ },
+ {
+ {144, 145, 146},
+ {148, 149, 150},
+ {152, 153, 154}
+ },
+ {
+ {131, 135, 143},
+ {147, 151, 155},
+ {140, 141, 142}
+ }
+ },
+ {
+ {
+ {160, 161, 162},
+ {164, 165, 166},
+ {168, 169, 170}
+ },
+ {
+ {176, 177, 178},
+ {180, 181, 182},
+ {184, 185, 186}
+ },
+ {
+ {163, 167, 175},
+ {179, 183, 187},
+ {172, 173, 174}
+ }
+ },
+ {
+ {
+ {192, 193, 194},
+ {196, 197, 198},
+ {200, 201, 202}
+ },
+ {
+ {208, 209, 210},
+ {212, 213, 214},
+ {216, 217, 218}
+ },
+ {
+ {195, 199, 207},
+ {211, 215, 219},
+ {204, 205, 206}
+ }
+ }
+ },
+ {
+ {
+ {
+ {96, 97, 98},
+ {100, 101, 102},
+ {104, 105, 106}
+ },
+ {
+ {112, 113, 114},
+ {116, 117, 118},
+ {120, 121, 122}
+ },
+ {
+ {99, 103, 111},
+ {115, 119, 123},
+ {108, 109, 110}
+ }
+ },
+ {
+ {
+ {224, 225, 226},
+ {228, 229, 230},
+ {232, 233, 234}
+ },
+ {
+ {240, 241, 242},
+ {244, 245, 246},
+ {248, 249, 250}
+ },
+ {
+ {227, 231, 239},
+ {243, 247, 251},
+ {236, 237, 238}
+ }
+ },
+ {
+ {
+ {28, 29, 30},
+ {60, 61, 62},
+ {92, 93, 94}
+ },
+ {
+ {156, 157, 158},
+ {188, 189, 190},
+ {220, 221, 222}
+ },
+ {
+ {31, 63, 127},
+ {159, 191, 255},
+ {252, 253, 254}
+ }
+ }
+ }
+};
+
+/**
+ * @brief The number of bits, trits, and quints needed for a quant level.
+ */
+struct btq_count
+{
+ /** @brief The number of bits. */
+ uint8_t bits:6;
+
+ /** @brief The number of trits. */
+ uint8_t trits:1;
+
+ /** @brief The number of quints. */
+ uint8_t quints:1;
+};
+
+/**
+ * @brief The table of bits, trits, and quints needed for a quant encode.
+ */
+static const std::array<btq_count, 21> btq_counts {{
+ { 1, 0, 0 }, // QUANT_2
+ { 0, 1, 0 }, // QUANT_3
+ { 2, 0, 0 }, // QUANT_4
+ { 0, 0, 1 }, // QUANT_5
+ { 1, 1, 0 }, // QUANT_6
+ { 3, 0, 0 }, // QUANT_8
+ { 1, 0, 1 }, // QUANT_10
+ { 2, 1, 0 }, // QUANT_12
+ { 4, 0, 0 }, // QUANT_16
+ { 2, 0, 1 }, // QUANT_20
+ { 3, 1, 0 }, // QUANT_24
+ { 5, 0, 0 }, // QUANT_32
+ { 3, 0, 1 }, // QUANT_40
+ { 4, 1, 0 }, // QUANT_48
+ { 6, 0, 0 }, // QUANT_64
+ { 4, 0, 1 }, // QUANT_80
+ { 5, 1, 0 }, // QUANT_96
+ { 7, 0, 0 }, // QUANT_128
+ { 5, 0, 1 }, // QUANT_160
+ { 6, 1, 0 }, // QUANT_192
+ { 8, 0, 0 } // QUANT_256
+}};
+
+/**
+ * @brief The sequence scale, round, and divisors needed to compute sizing.
+ *
+ * The length of a quantized sequence in bits is:
+ * (scale * <sequence_len> + round) / divisor
+ */
+struct ise_size
+{
+ /** @brief The scaling parameter. */
+ uint8_t scale:6;
+
+ /** @brief The divisor parameter. */
+ uint8_t divisor:2;
+};
+
+/**
+ * @brief The table of scale, round, and divisors needed for quant sizing.
+ */
+static const std::array<ise_size, 21> ise_sizes {{
+ { 1, 0 }, // QUANT_2
+ { 8, 2 }, // QUANT_3
+ { 2, 0 }, // QUANT_4
+ { 7, 1 }, // QUANT_5
+ { 13, 2 }, // QUANT_6
+ { 3, 0 }, // QUANT_8
+ { 10, 1 }, // QUANT_10
+ { 18, 2 }, // QUANT_12
+ { 4, 0 }, // QUANT_16
+ { 13, 1 }, // QUANT_20
+ { 23, 2 }, // QUANT_24
+ { 5, 0 }, // QUANT_32
+ { 16, 1 }, // QUANT_40
+ { 28, 2 }, // QUANT_48
+ { 6, 0 }, // QUANT_64
+ { 19, 1 }, // QUANT_80
+ { 33, 2 }, // QUANT_96
+ { 7, 0 }, // QUANT_128
+ { 22, 1 }, // QUANT_160
+ { 38, 2 }, // QUANT_192
+ { 8, 0 } // QUANT_256
+}};
+
+/* See header for documentation. */
+unsigned int get_ise_sequence_bitcount(
+ unsigned int character_count,
+ quant_method quant_level
+) {
+ // Cope with out-of bounds values - input might be invalid
+ if (static_cast<size_t>(quant_level) >= ise_sizes.size())
+ {
+ // Arbitrary large number that's more than an ASTC block can hold
+ return 1024;
+ }
+
+ auto& entry = ise_sizes[quant_level];
+ unsigned int divisor = (entry.divisor << 1) + 1;
+ return (entry.scale * character_count + divisor - 1) / divisor;
+}
+
+/**
+ * @brief Write up to 8 bits at an arbitrary bit offset.
+ *
+ * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so may
+ * span two separate bytes in memory.
+ *
+ * @param value The value to write.
+ * @param bitcount The number of bits to write, starting from LSB.
+ * @param bitoffset The bit offset to store at, between 0 and 7.
+ * @param[in,out] ptr The data pointer to write to.
+ */
+static inline void write_bits(
+ unsigned int value,
+ unsigned int bitcount,
+ unsigned int bitoffset,
+ uint8_t ptr[2]
+) {
+ unsigned int mask = (1 << bitcount) - 1;
+ value &= mask;
+ ptr += bitoffset >> 3;
+ bitoffset &= 7;
+ value <<= bitoffset;
+ mask <<= bitoffset;
+ mask = ~mask;
+
+ ptr[0] &= mask;
+ ptr[0] |= value;
+ ptr[1] &= mask >> 8;
+ ptr[1] |= value >> 8;
+}
+
+/**
+ * @brief Read up to 8 bits at an arbitrary bit offset.
+ *
+ * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so may
+ * span two separate bytes in memory.
+ *
+ * @param bitcount The number of bits to read.
+ * @param bitoffset The bit offset to read from, between 0 and 7.
+ * @param[in,out] ptr The data pointer to read from.
+ *
+ * @return The read value.
+ */
+static inline unsigned int read_bits(
+ unsigned int bitcount,
+ unsigned int bitoffset,
+ const uint8_t* ptr
+) {
+ unsigned int mask = (1 << bitcount) - 1;
+ ptr += bitoffset >> 3;
+ bitoffset &= 7;
+ unsigned int value = ptr[0] | (ptr[1] << 8);
+ value >>= bitoffset;
+ value &= mask;
+ return value;
+}
+
+/* See header for documentation. */
+void encode_ise(
+ quant_method quant_level,
+ unsigned int character_count,
+ const uint8_t* input_data,
+ uint8_t* output_data,
+ unsigned int bit_offset
+) {
+ promise(character_count > 0);
+
+ unsigned int bits = btq_counts[quant_level].bits;
+ unsigned int trits = btq_counts[quant_level].trits;
+ unsigned int quints = btq_counts[quant_level].quints;
+ unsigned int mask = (1 << bits) - 1;
+
+ // Write out trits and bits
+ if (trits)
+ {
+ unsigned int i = 0;
+ unsigned int full_trit_blocks = character_count / 5;
+
+ for (unsigned int j = 0; j < full_trit_blocks; j++)
+ {
+ unsigned int i4 = input_data[i + 4] >> bits;
+ unsigned int i3 = input_data[i + 3] >> bits;
+ unsigned int i2 = input_data[i + 2] >> bits;
+ unsigned int i1 = input_data[i + 1] >> bits;
+ unsigned int i0 = input_data[i + 0] >> bits;
+
+ uint8_t T = integer_of_trits[i4][i3][i2][i1][i0];
+
+ // The max size of a trit bit count is 6, so we can always safely
+ // pack a single MX value with the following 1 or 2 T bits.
+ uint8_t pack;
+
+ // Element 0 + T0 + T1
+ pack = (input_data[i++] & mask) | (((T >> 0) & 0x3) << bits);
+ write_bits(pack, bits + 2, bit_offset, output_data);
+ bit_offset += bits + 2;
+
+ // Element 1 + T2 + T3
+ pack = (input_data[i++] & mask) | (((T >> 2) & 0x3) << bits);
+ write_bits(pack, bits + 2, bit_offset, output_data);
+ bit_offset += bits + 2;
+
+ // Element 2 + T4
+ pack = (input_data[i++] & mask) | (((T >> 4) & 0x1) << bits);
+ write_bits(pack, bits + 1, bit_offset, output_data);
+ bit_offset += bits + 1;
+
+ // Element 3 + T5 + T6
+ pack = (input_data[i++] & mask) | (((T >> 5) & 0x3) << bits);
+ write_bits(pack, bits + 2, bit_offset, output_data);
+ bit_offset += bits + 2;
+
+ // Element 4 + T7
+ pack = (input_data[i++] & mask) | (((T >> 7) & 0x1) << bits);
+ write_bits(pack, bits + 1, bit_offset, output_data);
+ bit_offset += bits + 1;
+ }
+
+ // Loop tail for a partial block
+ if (i != character_count)
+ {
+ // i4 cannot be present - we know the block is partial
+ // i0 must be present - we know the block isn't empty
+ unsigned int i4 = 0;
+ unsigned int i3 = i + 3 >= character_count ? 0 : input_data[i + 3] >> bits;
+ unsigned int i2 = i + 2 >= character_count ? 0 : input_data[i + 2] >> bits;
+ unsigned int i1 = i + 1 >= character_count ? 0 : input_data[i + 1] >> bits;
+ unsigned int i0 = input_data[i + 0] >> bits;
+
+ uint8_t T = integer_of_trits[i4][i3][i2][i1][i0];
+
+ for (unsigned int j = 0; i < character_count; i++, j++)
+ {
+ // Truncated table as this iteration is always partital
+ static const uint8_t tbits[4] { 2, 2, 1, 2 };
+ static const uint8_t tshift[4] { 0, 2, 4, 5 };
+
+ uint8_t pack = (input_data[i] & mask) |
+ (((T >> tshift[j]) & ((1 << tbits[j]) - 1)) << bits);
+
+ write_bits(pack, bits + tbits[j], bit_offset, output_data);
+ bit_offset += bits + tbits[j];
+ }
+ }
+ }
+ // Write out quints and bits
+ else if (quints)
+ {
+ unsigned int i = 0;
+ unsigned int full_quint_blocks = character_count / 3;
+
+ for (unsigned int j = 0; j < full_quint_blocks; j++)
+ {
+ unsigned int i2 = input_data[i + 2] >> bits;
+ unsigned int i1 = input_data[i + 1] >> bits;
+ unsigned int i0 = input_data[i + 0] >> bits;
+
+ uint8_t T = integer_of_quints[i2][i1][i0];
+
+ // The max size of a quint bit count is 5, so we can always safely
+ // pack a single M value with the following 2 or 3 T bits.
+ uint8_t pack;
+
+ // Element 0
+ pack = (input_data[i++] & mask) | (((T >> 0) & 0x7) << bits);
+ write_bits(pack, bits + 3, bit_offset, output_data);
+ bit_offset += bits + 3;
+
+ // Element 1
+ pack = (input_data[i++] & mask) | (((T >> 3) & 0x3) << bits);
+ write_bits(pack, bits + 2, bit_offset, output_data);
+ bit_offset += bits + 2;
+
+ // Element 2
+ pack = (input_data[i++] & mask) | (((T >> 5) & 0x3) << bits);
+ write_bits(pack, bits + 2, bit_offset, output_data);
+ bit_offset += bits + 2;
+ }
+
+ // Loop tail for a partial block
+ if (i != character_count)
+ {
+ // i2 cannot be present - we know the block is partial
+ // i0 must be present - we know the block isn't empty
+ unsigned int i2 = 0;
+ unsigned int i1 = i + 1 >= character_count ? 0 : input_data[i + 1] >> bits;
+ unsigned int i0 = input_data[i + 0] >> bits;
+
+ uint8_t T = integer_of_quints[i2][i1][i0];
+
+ for (unsigned int j = 0; i < character_count; i++, j++)
+ {
+ // Truncated table as this iteration is always partital
+ static const uint8_t tbits[2] { 3, 2 };
+ static const uint8_t tshift[2] { 0, 3 };
+
+ uint8_t pack = (input_data[i] & mask) |
+ (((T >> tshift[j]) & ((1 << tbits[j]) - 1)) << bits);
+
+ write_bits(pack, bits + tbits[j], bit_offset, output_data);
+ bit_offset += bits + tbits[j];
+ }
+ }
+ }
+ // Write out just bits
+ else
+ {
+ for (unsigned int i = 0; i < character_count; i++)
+ {
+ write_bits(input_data[i], bits, bit_offset, output_data);
+ bit_offset += bits;
+ }
+ }
+}
+
+/* See header for documentation. */
+void decode_ise(
+ quant_method quant_level,
+ unsigned int character_count,
+ const uint8_t* input_data,
+ uint8_t* output_data,
+ unsigned int bit_offset
+) {
+ promise(character_count > 0);
+
+ // Note: due to how the trit/quint-block unpacking is done in this function, we may write more
+ // temporary results than the number of outputs. The maximum actual number of results is 64 bit,
+ // but we keep 4 additional character_count of padding.
+ uint8_t results[68];
+ uint8_t tq_blocks[22] { 0 }; // Trit-blocks or quint-blocks, must be zeroed
+
+ unsigned int bits = btq_counts[quant_level].bits;
+ unsigned int trits = btq_counts[quant_level].trits;
+ unsigned int quints = btq_counts[quant_level].quints;
+
+ unsigned int lcounter = 0;
+ unsigned int hcounter = 0;
+
+ // Collect bits for each element, as well as bits for any trit-blocks and quint-blocks.
+ for (unsigned int i = 0; i < character_count; i++)
+ {
+ results[i] = static_cast<uint8_t>(read_bits(bits, bit_offset, input_data));
+ bit_offset += bits;
+
+ if (trits)
+ {
+ static const uint8_t bits_to_read[5] { 2, 2, 1, 2, 1 };
+ static const uint8_t block_shift[5] { 0, 2, 4, 5, 7 };
+ static const uint8_t next_lcounter[5] { 1, 2, 3, 4, 0 };
+ static const uint8_t hcounter_incr[5] { 0, 0, 0, 0, 1 };
+ unsigned int tdata = read_bits(bits_to_read[lcounter], bit_offset, input_data);
+ bit_offset += bits_to_read[lcounter];
+ tq_blocks[hcounter] |= tdata << block_shift[lcounter];
+ hcounter += hcounter_incr[lcounter];
+ lcounter = next_lcounter[lcounter];
+ }
+
+ if (quints)
+ {
+ static const uint8_t bits_to_read[3] { 3, 2, 2 };
+ static const uint8_t block_shift[3] { 0, 3, 5 };
+ static const uint8_t next_lcounter[3] { 1, 2, 0 };
+ static const uint8_t hcounter_incr[3] { 0, 0, 1 };
+ unsigned int tdata = read_bits(bits_to_read[lcounter], bit_offset, input_data);
+ bit_offset += bits_to_read[lcounter];
+ tq_blocks[hcounter] |= tdata << block_shift[lcounter];
+ hcounter += hcounter_incr[lcounter];
+ lcounter = next_lcounter[lcounter];
+ }
+ }
+
+ // Unpack trit-blocks or quint-blocks as needed
+ if (trits)
+ {
+ unsigned int trit_blocks = (character_count + 4) / 5;
+ promise(trit_blocks > 0);
+ for (unsigned int i = 0; i < trit_blocks; i++)
+ {
+ const uint8_t *tritptr = trits_of_integer[tq_blocks[i]];
+ results[5 * i ] |= tritptr[0] << bits;
+ results[5 * i + 1] |= tritptr[1] << bits;
+ results[5 * i + 2] |= tritptr[2] << bits;
+ results[5 * i + 3] |= tritptr[3] << bits;
+ results[5 * i + 4] |= tritptr[4] << bits;
+ }
+ }
+
+ if (quints)
+ {
+ unsigned int quint_blocks = (character_count + 2) / 3;
+ promise(quint_blocks > 0);
+ for (unsigned int i = 0; i < quint_blocks; i++)
+ {
+ const uint8_t *quintptr = quints_of_integer[tq_blocks[i]];
+ results[3 * i ] |= quintptr[0] << bits;
+ results[3 * i + 1] |= quintptr[1] << bits;
+ results[3 * i + 2] |= quintptr[2] << bits;
+ }
+ }
+
+ for (unsigned int i = 0; i < character_count; i++)
+ {
+ output_data[i] = results[i];
+ }
+}
diff --git a/thirdparty/astcenc/astcenc_internal.h b/thirdparty/astcenc/astcenc_internal.h
new file mode 100644
index 0000000000..0aa8fa0f81
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_internal.h
@@ -0,0 +1,2196 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions and data declarations.
+ */
+
+#ifndef ASTCENC_INTERNAL_INCLUDED
+#define ASTCENC_INTERNAL_INCLUDED
+
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+#if defined(ASTCENC_DIAGNOSTICS)
+ #include <cstdio>
+#endif
+#include <cstdlib>
+
+#include "astcenc.h"
+#include "astcenc_mathlib.h"
+#include "astcenc_vecmathlib.h"
+
+/**
+ * @brief Make a promise to the compiler's optimizer.
+ *
+ * A promise is an expression that the optimizer is can assume is true for to help it generate
+ * faster code. Common use cases for this are to promise that a for loop will iterate more than
+ * once, or that the loop iteration count is a multiple of a vector length, which avoids pre-loop
+ * checks and can avoid loop tails if loops are unrolled by the auto-vectorizer.
+ */
+#if defined(NDEBUG)
+ #if !defined(__clang__) && defined(_MSC_VER)
+ #define promise(cond) __assume(cond)
+ #elif defined(__clang__)
+ #if __has_builtin(__builtin_assume)
+ #define promise(cond) __builtin_assume(cond)
+ #elif __has_builtin(__builtin_unreachable)
+ #define promise(cond) if (!(cond)) { __builtin_unreachable(); }
+ #else
+ #define promise(cond)
+ #endif
+ #else // Assume GCC
+ #define promise(cond) if (!(cond)) { __builtin_unreachable(); }
+ #endif
+#else
+ #define promise(cond) assert(cond)
+#endif
+
+/* ============================================================================
+ Constants
+============================================================================ */
+#if !defined(ASTCENC_BLOCK_MAX_TEXELS)
+ #define ASTCENC_BLOCK_MAX_TEXELS 216 // A 3D 6x6x6 block
+#endif
+
+/** @brief The maximum number of texels a block can support (6x6x6 block). */
+static constexpr unsigned int BLOCK_MAX_TEXELS { ASTCENC_BLOCK_MAX_TEXELS };
+
+/** @brief The maximum number of components a block can support. */
+static constexpr unsigned int BLOCK_MAX_COMPONENTS { 4 };
+
+/** @brief The maximum number of partitions a block can support. */
+static constexpr unsigned int BLOCK_MAX_PARTITIONS { 4 };
+
+/** @brief The number of partitionings, per partition count, suported by the ASTC format. */
+static constexpr unsigned int BLOCK_MAX_PARTITIONINGS { 1024 };
+
+/** @brief The maximum number of weights used during partition selection for texel clustering. */
+static constexpr uint8_t BLOCK_MAX_KMEANS_TEXELS { 64 };
+
+/** @brief The maximum number of weights a block can support. */
+static constexpr unsigned int BLOCK_MAX_WEIGHTS { 64 };
+
+/** @brief The maximum number of weights a block can support per plane in 2 plane mode. */
+static constexpr unsigned int BLOCK_MAX_WEIGHTS_2PLANE { BLOCK_MAX_WEIGHTS / 2 };
+
+/** @brief The minimum number of weight bits a candidate encoding must encode. */
+static constexpr unsigned int BLOCK_MIN_WEIGHT_BITS { 24 };
+
+/** @brief The maximum number of weight bits a candidate encoding can encode. */
+static constexpr unsigned int BLOCK_MAX_WEIGHT_BITS { 96 };
+
+/** @brief The index indicating a bad (unused) block mode in the remap array. */
+static constexpr uint16_t BLOCK_BAD_BLOCK_MODE { 0xFFFFu };
+
+/** @brief The index indicating a bad (unused) partitioning in the remap array. */
+static constexpr uint16_t BLOCK_BAD_PARTITIONING { 0xFFFFu };
+
+/** @brief The number of partition index bits supported by the ASTC format . */
+static constexpr unsigned int PARTITION_INDEX_BITS { 10 };
+
+/** @brief The offset of the plane 2 weights in shared weight arrays. */
+static constexpr unsigned int WEIGHTS_PLANE2_OFFSET { BLOCK_MAX_WEIGHTS_2PLANE };
+
+/** @brief The sum of quantized weights for one texel. */
+static constexpr float WEIGHTS_TEXEL_SUM { 16.0f };
+
+/** @brief The number of block modes supported by the ASTC format. */
+static constexpr unsigned int WEIGHTS_MAX_BLOCK_MODES { 2048 };
+
+/** @brief The number of weight grid decimation modes supported by the ASTC format. */
+static constexpr unsigned int WEIGHTS_MAX_DECIMATION_MODES { 87 };
+
+/** @brief The high default error used to initialize error trackers. */
+static constexpr float ERROR_CALC_DEFAULT { 1e30f };
+
+/**
+ * @brief The minimum texel count for a block to use the one partition fast path.
+ *
+ * This setting skips 4x4 and 5x4 block sizes.
+ */
+static constexpr unsigned int TUNE_MIN_TEXELS_MODE0_FASTPATH { 24 };
+
+/**
+ * @brief The maximum number of candidate encodings tested for each encoding mode.
+ *
+ * This can be dynamically reduced by the compression quality preset.
+ */
+static constexpr unsigned int TUNE_MAX_TRIAL_CANDIDATES { 8 };
+
+/**
+ * @brief The maximum number of candidate partitionings tested for each encoding mode.
+ *
+ * This can be dynamically reduced by the compression quality preset.
+ */
+static constexpr unsigned int TUNE_MAX_PARTITIONING_CANDIDATES { 32 };
+
+/**
+ * @brief The maximum quant level using full angular endpoint search method.
+ *
+ * The angular endpoint search is used to find the min/max weight that should
+ * be used for a given quantization level. It is effective but expensive, so
+ * we only use it where it has the most value - low quant levels with wide
+ * spacing. It is used below TUNE_MAX_ANGULAR_QUANT (inclusive). Above this we
+ * assume the min weight is 0.0f, and the max weight is 1.0f.
+ *
+ * Note the angular algorithm is vectorized, and using QUANT_12 exactly fills
+ * one 8-wide vector. Decreasing by one doesn't buy much performance, and
+ * increasing by one is disproportionately expensive.
+ */
+static constexpr unsigned int TUNE_MAX_ANGULAR_QUANT { 7 }; /* QUANT_12 */
+
+static_assert((BLOCK_MAX_TEXELS % ASTCENC_SIMD_WIDTH) == 0,
+ "BLOCK_MAX_TEXELS must be multiple of ASTCENC_SIMD_WIDTH");
+
+static_assert(BLOCK_MAX_TEXELS <= 216,
+ "BLOCK_MAX_TEXELS must not be greater than 216");
+
+static_assert((BLOCK_MAX_WEIGHTS % ASTCENC_SIMD_WIDTH) == 0,
+ "BLOCK_MAX_WEIGHTS must be multiple of ASTCENC_SIMD_WIDTH");
+
+static_assert((WEIGHTS_MAX_BLOCK_MODES % ASTCENC_SIMD_WIDTH) == 0,
+ "WEIGHTS_MAX_BLOCK_MODES must be multiple of ASTCENC_SIMD_WIDTH");
+
+
+/* ============================================================================
+ Commonly used data structures
+============================================================================ */
+
+/**
+ * @brief The ASTC endpoint formats.
+ *
+ * Note, the values here are used directly in the encoding in the format so do not rearrange.
+ */
+enum endpoint_formats
+{
+ FMT_LUMINANCE = 0,
+ FMT_LUMINANCE_DELTA = 1,
+ FMT_HDR_LUMINANCE_LARGE_RANGE = 2,
+ FMT_HDR_LUMINANCE_SMALL_RANGE = 3,
+ FMT_LUMINANCE_ALPHA = 4,
+ FMT_LUMINANCE_ALPHA_DELTA = 5,
+ FMT_RGB_SCALE = 6,
+ FMT_HDR_RGB_SCALE = 7,
+ FMT_RGB = 8,
+ FMT_RGB_DELTA = 9,
+ FMT_RGB_SCALE_ALPHA = 10,
+ FMT_HDR_RGB = 11,
+ FMT_RGBA = 12,
+ FMT_RGBA_DELTA = 13,
+ FMT_HDR_RGB_LDR_ALPHA = 14,
+ FMT_HDR_RGBA = 15
+};
+
+/**
+ * @brief The ASTC quantization methods.
+ *
+ * Note, the values here are used directly in the encoding in the format so do not rearrange.
+ */
+enum quant_method
+{
+ QUANT_2 = 0,
+ QUANT_3 = 1,
+ QUANT_4 = 2,
+ QUANT_5 = 3,
+ QUANT_6 = 4,
+ QUANT_8 = 5,
+ QUANT_10 = 6,
+ QUANT_12 = 7,
+ QUANT_16 = 8,
+ QUANT_20 = 9,
+ QUANT_24 = 10,
+ QUANT_32 = 11,
+ QUANT_40 = 12,
+ QUANT_48 = 13,
+ QUANT_64 = 14,
+ QUANT_80 = 15,
+ QUANT_96 = 16,
+ QUANT_128 = 17,
+ QUANT_160 = 18,
+ QUANT_192 = 19,
+ QUANT_256 = 20
+};
+
+/**
+ * @brief The number of levels use by an ASTC quantization method.
+ *
+ * @param method The quantization method
+ *
+ * @return The number of levels used by @c method.
+ */
+static inline unsigned int get_quant_level(quant_method method)
+{
+ switch (method)
+ {
+ case QUANT_2: return 2;
+ case QUANT_3: return 3;
+ case QUANT_4: return 4;
+ case QUANT_5: return 5;
+ case QUANT_6: return 6;
+ case QUANT_8: return 8;
+ case QUANT_10: return 10;
+ case QUANT_12: return 12;
+ case QUANT_16: return 16;
+ case QUANT_20: return 20;
+ case QUANT_24: return 24;
+ case QUANT_32: return 32;
+ case QUANT_40: return 40;
+ case QUANT_48: return 48;
+ case QUANT_64: return 64;
+ case QUANT_80: return 80;
+ case QUANT_96: return 96;
+ case QUANT_128: return 128;
+ case QUANT_160: return 160;
+ case QUANT_192: return 192;
+ case QUANT_256: return 256;
+ }
+
+ // Unreachable - the enum is fully described
+ return 0;
+}
+
+/**
+ * @brief Computed metrics about a partition in a block.
+ */
+struct partition_metrics
+{
+ /** @brief The error-weighted average color in the partition. */
+ vfloat4 avg;
+
+ /** @brief The dominant error-weighted direction in the partition. */
+ vfloat4 dir;
+};
+
+/**
+ * @brief Computed lines for a a three component analysis.
+ */
+struct partition_lines3
+{
+ /** @brief Line for uncorrelated chroma. */
+ line3 uncor_line;
+
+ /** @brief Line for correlated chroma, passing though the origin. */
+ line3 samec_line;
+
+ /** @brief Post-processed line for uncorrelated chroma. */
+ processed_line3 uncor_pline;
+
+ /** @brief Post-processed line for correlated chroma, passing though the origin. */
+ processed_line3 samec_pline;
+
+ /** @brief The length of the line for uncorrelated chroma. */
+ float uncor_line_len;
+
+ /** @brief The length of the line for correlated chroma. */
+ float samec_line_len;
+};
+
+/**
+ * @brief The partition information for a single partition.
+ *
+ * ASTC has a total of 1024 candidate partitions for each of 2/3/4 partition counts, although this
+ * 1024 includes seeds that generate duplicates of other seeds and seeds that generate completely
+ * empty partitions. These are both valid encodings, but astcenc will skip both during compression
+ * as they are not useful.
+ */
+struct partition_info
+{
+ /** @brief The number of partitions in this partitioning. */
+ uint16_t partition_count;
+
+ /** @brief The index (seed) of this partitioning. */
+ uint16_t partition_index;
+
+ /**
+ * @brief The number of texels in each partition.
+ *
+ * Note that some seeds result in zero texels assigned to a partition are valid, but are skipped
+ * by this compressor as there is no point spending bits encoding an unused color endpoint.
+ */
+ uint8_t partition_texel_count[BLOCK_MAX_PARTITIONS];
+
+ /** @brief The partition of each texel in the block. */
+ uint8_t partition_of_texel[BLOCK_MAX_TEXELS];
+
+ /** @brief The list of texels in each partition. */
+ uint8_t texels_of_partition[BLOCK_MAX_PARTITIONS][BLOCK_MAX_TEXELS];
+};
+
+/**
+ * @brief The weight grid information for a single decimation pattern.
+ *
+ * ASTC can store one weight per texel, but is also capable of storing lower resolution weight grids
+ * that are interpolated during decompression to assign a with to a texel. Storing fewer weights
+ * can free up a substantial amount of bits that we can then spend on more useful things, such as
+ * more accurate endpoints and weights, or additional partitions.
+ *
+ * This data structure is used to store information about a single weight grid decimation pattern,
+ * for a single block size.
+ */
+struct decimation_info
+{
+ /** @brief The total number of texels in the block. */
+ uint8_t texel_count;
+
+ /** @brief The maximum number of stored weights that contribute to each texel, between 1 and 4. */
+ uint8_t max_texel_weight_count;
+
+ /** @brief The total number of weights stored. */
+ uint8_t weight_count;
+
+ /** @brief The number of stored weights in the X dimension. */
+ uint8_t weight_x;
+
+ /** @brief The number of stored weights in the Y dimension. */
+ uint8_t weight_y;
+
+ /** @brief The number of stored weights in the Z dimension. */
+ uint8_t weight_z;
+
+ /**
+ * @brief The number of weights that contribute to each texel.
+ * Value is between 1 and 4.
+ */
+ uint8_t texel_weight_count[BLOCK_MAX_TEXELS];
+
+ /**
+ * @brief The weight index of the N weights that are interpolated for each texel.
+ * Stored transposed to improve vectorization.
+ */
+ uint8_t texel_weights_tr[4][BLOCK_MAX_TEXELS];
+
+ /**
+ * @brief The bilinear contribution of the N weights that are interpolated for each texel.
+ * Value is between 0 and 16, stored transposed to improve vectorization.
+ */
+ uint8_t texel_weight_contribs_int_tr[4][BLOCK_MAX_TEXELS];
+
+ /**
+ * @brief The bilinear contribution of the N weights that are interpolated for each texel.
+ * Value is between 0 and 1, stored transposed to improve vectorization.
+ */
+ alignas(ASTCENC_VECALIGN) float texel_weight_contribs_float_tr[4][BLOCK_MAX_TEXELS];
+
+ /** @brief The number of texels that each stored weight contributes to. */
+ uint8_t weight_texel_count[BLOCK_MAX_WEIGHTS];
+
+ /**
+ * @brief The list of texels that use a specific weight index.
+ * Stored transposed to improve vectorization.
+ */
+ uint8_t weight_texels_tr[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS];
+
+ /**
+ * @brief The bilinear contribution to the N texels that use each weight.
+ * Value is between 0 and 1, stored transposed to improve vectorization.
+ */
+ alignas(ASTCENC_VECALIGN) float weights_texel_contribs_tr[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS];
+
+ /**
+ * @brief The bilinear contribution to the Nth texel that uses each weight.
+ * Value is between 0 and 1, stored transposed to improve vectorization.
+ */
+ float texel_contrib_for_weight[BLOCK_MAX_TEXELS][BLOCK_MAX_WEIGHTS];
+};
+
+/**
+ * @brief Metadata for single block mode for a specific block size.
+ */
+struct block_mode
+{
+ /** @brief The block mode index in the ASTC encoded form. */
+ uint16_t mode_index;
+
+ /** @brief The decimation mode index in the compressor reindexed list. */
+ uint8_t decimation_mode;
+
+ /** @brief The weight quantization used by this block mode. */
+ uint8_t quant_mode;
+
+ /** @brief The weight quantization used by this block mode. */
+ uint8_t weight_bits;
+
+ /** @brief Is a dual weight plane used by this block mode? */
+ uint8_t is_dual_plane : 1;
+
+ /**
+ * @brief Get the weight quantization used by this block mode.
+ *
+ * @return The quantization level.
+ */
+ inline quant_method get_weight_quant_mode() const
+ {
+ return static_cast<quant_method>(this->quant_mode);
+ }
+};
+
+/**
+ * @brief Metadata for single decimation mode for a specific block size.
+ */
+struct decimation_mode
+{
+ /** @brief The max weight precision for 1 plane, or -1 if not supported. */
+ int8_t maxprec_1plane;
+
+ /** @brief The max weight precision for 2 planes, or -1 if not supported. */
+ int8_t maxprec_2planes;
+
+ /**
+ * @brief Bitvector indicating weight quant modes used by active 1 plane block modes.
+ *
+ * Bit 0 = QUANT_2, Bit 1 = QUANT_3, etc.
+ */
+ uint16_t refprec_1_plane;
+
+ /**
+ * @brief Bitvector indicating weight quant methods used by active 2 plane block modes.
+ *
+ * Bit 0 = QUANT_2, Bit 1 = QUANT_3, etc.
+ */
+ uint16_t refprec_2_planes;
+
+ /**
+ * @brief Set a 1 plane weight quant as active.
+ *
+ * @param weight_quant The quant method to set.
+ */
+ void set_ref_1_plane(quant_method weight_quant)
+ {
+ refprec_1_plane |= (1 << weight_quant);
+ }
+
+ /**
+ * @brief Test if this mode is active below a given 1 plane weight quant (inclusive).
+ *
+ * @param max_weight_quant The max quant method to test.
+ */
+ bool is_ref_1_plane(quant_method max_weight_quant) const
+ {
+ uint16_t mask = static_cast<uint16_t>((1 << (max_weight_quant + 1)) - 1);
+ return (refprec_1_plane & mask) != 0;
+ }
+
+ /**
+ * @brief Set a 2 plane weight quant as active.
+ *
+ * @param weight_quant The quant method to set.
+ */
+ void set_ref_2_plane(quant_method weight_quant)
+ {
+ refprec_2_planes |= static_cast<uint16_t>(1 << weight_quant);
+ }
+
+ /**
+ * @brief Test if this mode is active below a given 2 plane weight quant (inclusive).
+ *
+ * @param max_weight_quant The max quant method to test.
+ */
+ bool is_ref_2_plane(quant_method max_weight_quant) const
+ {
+ uint16_t mask = static_cast<uint16_t>((1 << (max_weight_quant + 1)) - 1);
+ return (refprec_2_planes & mask) != 0;
+ }
+};
+
+/**
+ * @brief Data tables for a single block size.
+ *
+ * The decimation tables store the information to apply weight grid dimension reductions. We only
+ * store the decimation modes that are actually needed by the current context; many of the possible
+ * modes will be unused (too many weights for the current block size or disabled by heuristics). The
+ * actual number of weights stored is @c decimation_mode_count, and the @c decimation_modes and
+ * @c decimation_tables arrays store the active modes contiguously at the start of the array. These
+ * entries are not stored in any particular order.
+ *
+ * The block mode tables store the unpacked block mode settings. Block modes are stored in the
+ * compressed block as an 11 bit field, but for any given block size and set of compressor
+ * heuristics, only a subset of the block modes will be used. The actual number of block modes
+ * stored is indicated in @c block_mode_count, and the @c block_modes array store the active modes
+ * contiguously at the start of the array. These entries are stored in incrementing "packed" value
+ * order, which doesn't mean much once unpacked. To allow decompressors to reference the packed data
+ * efficiently the @c block_mode_packed_index array stores the mapping between physical ID and the
+ * actual remapped array index.
+ */
+struct block_size_descriptor
+{
+ /** @brief The block X dimension, in texels. */
+ uint8_t xdim;
+
+ /** @brief The block Y dimension, in texels. */
+ uint8_t ydim;
+
+ /** @brief The block Z dimension, in texels. */
+ uint8_t zdim;
+
+ /** @brief The block total texel count. */
+ uint8_t texel_count;
+
+ /**
+ * @brief The number of stored decimation modes which are "always" modes.
+ *
+ * Always modes are stored at the start of the decimation_modes list.
+ */
+ unsigned int decimation_mode_count_always;
+
+ /** @brief The number of stored decimation modes for selected encodings. */
+ unsigned int decimation_mode_count_selected;
+
+ /** @brief The number of stored decimation modes for any encoding. */
+ unsigned int decimation_mode_count_all;
+
+ /**
+ * @brief The number of stored block modes which are "always" modes.
+ *
+ * Always modes are stored at the start of the block_modes list.
+ */
+ unsigned int block_mode_count_1plane_always;
+
+ /** @brief The number of stored block modes for active 1 plane encodings. */
+ unsigned int block_mode_count_1plane_selected;
+
+ /** @brief The number of stored block modes for active 1 and 2 plane encodings. */
+ unsigned int block_mode_count_1plane_2plane_selected;
+
+ /** @brief The number of stored block modes for any encoding. */
+ unsigned int block_mode_count_all;
+
+ /** @brief The number of selected partitionings for 1/2/3/4 partitionings. */
+ unsigned int partitioning_count_selected[BLOCK_MAX_PARTITIONS];
+
+ /** @brief The number of partitionings for 1/2/3/4 partitionings. */
+ unsigned int partitioning_count_all[BLOCK_MAX_PARTITIONS];
+
+ /** @brief The active decimation modes, stored in low indices. */
+ decimation_mode decimation_modes[WEIGHTS_MAX_DECIMATION_MODES];
+
+ /** @brief The active decimation tables, stored in low indices. */
+ alignas(ASTCENC_VECALIGN) decimation_info decimation_tables[WEIGHTS_MAX_DECIMATION_MODES];
+
+ /** @brief The packed block mode array index, or @c BLOCK_BAD_BLOCK_MODE if not active. */
+ uint16_t block_mode_packed_index[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The active block modes, stored in low indices. */
+ block_mode block_modes[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The active partition tables, stored in low indices per-count. */
+ partition_info partitionings[(3 * BLOCK_MAX_PARTITIONINGS) + 1];
+
+ /**
+ * @brief The packed partition table array index, or @c BLOCK_BAD_PARTITIONING if not active.
+ *
+ * Indexed by partition_count - 2, containing 2, 3 and 4 partitions.
+ */
+ uint16_t partitioning_packed_index[3][BLOCK_MAX_PARTITIONINGS];
+
+ /** @brief The active texels for k-means partition selection. */
+ uint8_t kmeans_texels[BLOCK_MAX_KMEANS_TEXELS];
+
+ /**
+ * @brief The canonical 2-partition coverage pattern used during block partition search.
+ *
+ * Indexed by remapped index, not physical index.
+ */
+ uint64_t coverage_bitmaps_2[BLOCK_MAX_PARTITIONINGS][2];
+
+ /**
+ * @brief The canonical 3-partition coverage pattern used during block partition search.
+ *
+ * Indexed by remapped index, not physical index.
+ */
+ uint64_t coverage_bitmaps_3[BLOCK_MAX_PARTITIONINGS][3];
+
+ /**
+ * @brief The canonical 4-partition coverage pattern used during block partition search.
+ *
+ * Indexed by remapped index, not physical index.
+ */
+ uint64_t coverage_bitmaps_4[BLOCK_MAX_PARTITIONINGS][4];
+
+ /**
+ * @brief Get the block mode structure for index @c block_mode.
+ *
+ * This function can only return block modes that are enabled by the current compressor config.
+ * Decompression from an arbitrary source should not use this without first checking that the
+ * packed block mode index is not @c BLOCK_BAD_BLOCK_MODE.
+ *
+ * @param block_mode The packed block mode index.
+ *
+ * @return The block mode structure.
+ */
+ const block_mode& get_block_mode(unsigned int block_mode) const
+ {
+ unsigned int packed_index = this->block_mode_packed_index[block_mode];
+ assert(packed_index != BLOCK_BAD_BLOCK_MODE && packed_index < this->block_mode_count_all);
+ return this->block_modes[packed_index];
+ }
+
+ /**
+ * @brief Get the decimation mode structure for index @c decimation_mode.
+ *
+ * This function can only return decimation modes that are enabled by the current compressor
+ * config. The mode array is stored packed, but this is only ever indexed by the packed index
+ * stored in the @c block_mode and never exists in an unpacked form.
+ *
+ * @param decimation_mode The packed decimation mode index.
+ *
+ * @return The decimation mode structure.
+ */
+ const decimation_mode& get_decimation_mode(unsigned int decimation_mode) const
+ {
+ return this->decimation_modes[decimation_mode];
+ }
+
+ /**
+ * @brief Get the decimation info structure for index @c decimation_mode.
+ *
+ * This function can only return decimation modes that are enabled by the current compressor
+ * config. The mode array is stored packed, but this is only ever indexed by the packed index
+ * stored in the @c block_mode and never exists in an unpacked form.
+ *
+ * @param decimation_mode The packed decimation mode index.
+ *
+ * @return The decimation info structure.
+ */
+ const decimation_info& get_decimation_info(unsigned int decimation_mode) const
+ {
+ return this->decimation_tables[decimation_mode];
+ }
+
+ /**
+ * @brief Get the partition info table for a given partition count.
+ *
+ * @param partition_count The number of partitions we want the table for.
+ *
+ * @return The pointer to the table of 1024 entries (for 2/3/4 parts) or 1 entry (for 1 part).
+ */
+ const partition_info* get_partition_table(unsigned int partition_count) const
+ {
+ if (partition_count == 1)
+ {
+ partition_count = 5;
+ }
+ unsigned int index = (partition_count - 2) * BLOCK_MAX_PARTITIONINGS;
+ return this->partitionings + index;
+ }
+
+ /**
+ * @brief Get the partition info structure for a given partition count and seed.
+ *
+ * @param partition_count The number of partitions we want the info for.
+ * @param index The partition seed (between 0 and 1023).
+ *
+ * @return The partition info structure.
+ */
+ const partition_info& get_partition_info(unsigned int partition_count, unsigned int index) const
+ {
+ unsigned int packed_index = 0;
+ if (partition_count >= 2)
+ {
+ packed_index = this->partitioning_packed_index[partition_count - 2][index];
+ }
+
+ assert(packed_index != BLOCK_BAD_PARTITIONING && packed_index < this->partitioning_count_all[partition_count - 1]);
+ auto& result = get_partition_table(partition_count)[packed_index];
+ assert(index == result.partition_index);
+ return result;
+ }
+
+ /**
+ * @brief Get the partition info structure for a given partition count and seed.
+ *
+ * @param partition_count The number of partitions we want the info for.
+ * @param packed_index The raw array offset.
+ *
+ * @return The partition info structure.
+ */
+ const partition_info& get_raw_partition_info(unsigned int partition_count, unsigned int packed_index) const
+ {
+ assert(packed_index != BLOCK_BAD_PARTITIONING && packed_index < this->partitioning_count_all[partition_count - 1]);
+ auto& result = get_partition_table(partition_count)[packed_index];
+ return result;
+ }
+};
+
+/**
+ * @brief The image data for a single block.
+ *
+ * The @c data_[rgba] fields store the image data in an encoded SoA float form designed for easy
+ * vectorization. Input data is converted to float and stored as values between 0 and 65535. LDR
+ * data is stored as direct UNORM data, HDR data is stored as LNS data.
+ *
+ * The @c rgb_lns and @c alpha_lns fields that assigned a per-texel use of HDR are only used during
+ * decompression. The current compressor will always use HDR endpoint formats when in HDR mode.
+ */
+struct image_block
+{
+ /** @brief The input (compress) or output (decompress) data for the red color component. */
+ alignas(ASTCENC_VECALIGN) float data_r[BLOCK_MAX_TEXELS];
+
+ /** @brief The input (compress) or output (decompress) data for the green color component. */
+ alignas(ASTCENC_VECALIGN) float data_g[BLOCK_MAX_TEXELS];
+
+ /** @brief The input (compress) or output (decompress) data for the blue color component. */
+ alignas(ASTCENC_VECALIGN) float data_b[BLOCK_MAX_TEXELS];
+
+ /** @brief The input (compress) or output (decompress) data for the alpha color component. */
+ alignas(ASTCENC_VECALIGN) float data_a[BLOCK_MAX_TEXELS];
+
+ /** @brief The number of texels in the block. */
+ uint8_t texel_count;
+
+ /** @brief The original data for texel 0 for constant color block encoding. */
+ vfloat4 origin_texel;
+
+ /** @brief The min component value of all texels in the block. */
+ vfloat4 data_min;
+
+ /** @brief The mean component value of all texels in the block. */
+ vfloat4 data_mean;
+
+ /** @brief The max component value of all texels in the block. */
+ vfloat4 data_max;
+
+ /** @brief The relative error significance of the color channels. */
+ vfloat4 channel_weight;
+
+ /** @brief Is this grayscale block where R == G == B for all texels? */
+ bool grayscale;
+
+ /** @brief Set to 1 if a texel is using HDR RGB endpoints (decompression only). */
+ uint8_t rgb_lns[BLOCK_MAX_TEXELS];
+
+ /** @brief Set to 1 if a texel is using HDR alpha endpoints (decompression only). */
+ uint8_t alpha_lns[BLOCK_MAX_TEXELS];
+
+ /** @brief The X position of this block in the input or output image. */
+ unsigned int xpos;
+
+ /** @brief The Y position of this block in the input or output image. */
+ unsigned int ypos;
+
+ /** @brief The Z position of this block in the input or output image. */
+ unsigned int zpos;
+
+ /**
+ * @brief Get an RGBA texel value from the data.
+ *
+ * @param index The texel index.
+ *
+ * @return The texel in RGBA component ordering.
+ */
+ inline vfloat4 texel(unsigned int index) const
+ {
+ return vfloat4(data_r[index],
+ data_g[index],
+ data_b[index],
+ data_a[index]);
+ }
+
+ /**
+ * @brief Get an RGB texel value from the data.
+ *
+ * @param index The texel index.
+ *
+ * @return The texel in RGB0 component ordering.
+ */
+ inline vfloat4 texel3(unsigned int index) const
+ {
+ return vfloat3(data_r[index],
+ data_g[index],
+ data_b[index]);
+ }
+
+ /**
+ * @brief Get the default alpha value for endpoints that don't store it.
+ *
+ * The default depends on whether the alpha endpoint is LDR or HDR.
+ *
+ * @return The alpha value in the scaled range used by the compressor.
+ */
+ inline float get_default_alpha() const
+ {
+ return this->alpha_lns[0] ? static_cast<float>(0x7800) : static_cast<float>(0xFFFF);
+ }
+
+ /**
+ * @brief Test if a single color channel is constant across the block.
+ *
+ * Constant color channels are easier to compress as interpolating between two identical colors
+ * always returns the same value, irrespective of the weight used. They therefore can be ignored
+ * for the purposes of weight selection and use of a second weight plane.
+ *
+ * @return @c true if the channel is constant across the block, @c false otherwise.
+ */
+ inline bool is_constant_channel(int channel) const
+ {
+ vmask4 lane_mask = vint4::lane_id() == vint4(channel);
+ vmask4 color_mask = this->data_min == this->data_max;
+ return any(lane_mask & color_mask);
+ }
+
+ /**
+ * @brief Test if this block is a luminance block with constant 1.0 alpha.
+ *
+ * @return @c true if the block is a luminance block , @c false otherwise.
+ */
+ inline bool is_luminance() const
+ {
+ float default_alpha = this->get_default_alpha();
+ bool alpha1 = (this->data_min.lane<3>() == default_alpha) &&
+ (this->data_max.lane<3>() == default_alpha);
+ return this->grayscale && alpha1;
+ }
+
+ /**
+ * @brief Test if this block is a luminance block with variable alpha.
+ *
+ * @return @c true if the block is a luminance + alpha block , @c false otherwise.
+ */
+ inline bool is_luminancealpha() const
+ {
+ float default_alpha = this->get_default_alpha();
+ bool alpha1 = (this->data_min.lane<3>() == default_alpha) &&
+ (this->data_max.lane<3>() == default_alpha);
+ return this->grayscale && !alpha1;
+ }
+};
+
+/**
+ * @brief Data structure storing the color endpoints for a block.
+ */
+struct endpoints
+{
+ /** @brief The number of partition endpoints stored. */
+ unsigned int partition_count;
+
+ /** @brief The colors for endpoint 0. */
+ vfloat4 endpt0[BLOCK_MAX_PARTITIONS];
+
+ /** @brief The colors for endpoint 1. */
+ vfloat4 endpt1[BLOCK_MAX_PARTITIONS];
+};
+
+/**
+ * @brief Data structure storing the color endpoints and weights.
+ */
+struct endpoints_and_weights
+{
+ /** @brief True if all active values in weight_error_scale are the same. */
+ bool is_constant_weight_error_scale;
+
+ /** @brief The color endpoints. */
+ endpoints ep;
+
+ /** @brief The ideal weight for each texel; may be undecimated or decimated. */
+ alignas(ASTCENC_VECALIGN) float weights[BLOCK_MAX_TEXELS];
+
+ /** @brief The ideal weight error scaling for each texel; may be undecimated or decimated. */
+ alignas(ASTCENC_VECALIGN) float weight_error_scale[BLOCK_MAX_TEXELS];
+};
+
+/**
+ * @brief Utility storing estimated errors from choosing particular endpoint encodings.
+ */
+struct encoding_choice_errors
+{
+ /** @brief Error of using LDR RGB-scale instead of complete endpoints. */
+ float rgb_scale_error;
+
+ /** @brief Error of using HDR RGB-scale instead of complete endpoints. */
+ float rgb_luma_error;
+
+ /** @brief Error of using luminance instead of RGB. */
+ float luminance_error;
+
+ /** @brief Error of discarding alpha and using a constant 1.0 alpha. */
+ float alpha_drop_error;
+
+ /** @brief Can we use delta offset encoding? */
+ bool can_offset_encode;
+
+ /** @brief Can we use blue contraction encoding? */
+ bool can_blue_contract;
+};
+
+/**
+ * @brief Preallocated working buffers, allocated per thread during context creation.
+ */
+struct alignas(ASTCENC_VECALIGN) compression_working_buffers
+{
+ /** @brief Ideal endpoints and weights for plane 1. */
+ endpoints_and_weights ei1;
+
+ /** @brief Ideal endpoints and weights for plane 2. */
+ endpoints_and_weights ei2;
+
+ /**
+ * @brief Decimated ideal weight values in the ~0-1 range.
+ *
+ * Note that values can be slightly below zero or higher than one due to
+ * endpoint extents being inside the ideal color representation.
+ *
+ * For two planes, second plane starts at @c WEIGHTS_PLANE2_OFFSET offsets.
+ */
+ alignas(ASTCENC_VECALIGN) float dec_weights_ideal[WEIGHTS_MAX_DECIMATION_MODES * BLOCK_MAX_WEIGHTS];
+
+ /**
+ * @brief Decimated quantized weight values in the unquantized 0-64 range.
+ *
+ * For two planes, second plane starts at @c WEIGHTS_PLANE2_OFFSET offsets.
+ */
+ uint8_t dec_weights_uquant[WEIGHTS_MAX_BLOCK_MODES * BLOCK_MAX_WEIGHTS];
+
+ /** @brief Error of the best encoding combination for each block mode. */
+ alignas(ASTCENC_VECALIGN) float errors_of_best_combination[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The best color quant for each block mode. */
+ uint8_t best_quant_levels[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The best color quant for each block mode if modes are the same and we have spare bits. */
+ uint8_t best_quant_levels_mod[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The best endpoint format for each partition. */
+ uint8_t best_ep_formats[WEIGHTS_MAX_BLOCK_MODES][BLOCK_MAX_PARTITIONS];
+
+ /** @brief The total bit storage needed for quantized weights for each block mode. */
+ int8_t qwt_bitcounts[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The cumulative error for quantized weights for each block mode. */
+ float qwt_errors[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The low weight value in plane 1 for each block mode. */
+ float weight_low_value1[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The high weight value in plane 1 for each block mode. */
+ float weight_high_value1[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The low weight value in plane 1 for each quant level and decimation mode. */
+ float weight_low_values1[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1];
+
+ /** @brief The high weight value in plane 1 for each quant level and decimation mode. */
+ float weight_high_values1[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1];
+
+ /** @brief The low weight value in plane 2 for each block mode. */
+ float weight_low_value2[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The high weight value in plane 2 for each block mode. */
+ float weight_high_value2[WEIGHTS_MAX_BLOCK_MODES];
+
+ /** @brief The low weight value in plane 2 for each quant level and decimation mode. */
+ float weight_low_values2[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1];
+
+ /** @brief The high weight value in plane 2 for each quant level and decimation mode. */
+ float weight_high_values2[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1];
+};
+
+struct dt_init_working_buffers
+{
+ uint8_t weight_count_of_texel[BLOCK_MAX_TEXELS];
+ uint8_t grid_weights_of_texel[BLOCK_MAX_TEXELS][4];
+ uint8_t weights_of_texel[BLOCK_MAX_TEXELS][4];
+
+ uint8_t texel_count_of_weight[BLOCK_MAX_WEIGHTS];
+ uint8_t texels_of_weight[BLOCK_MAX_WEIGHTS][BLOCK_MAX_TEXELS];
+ uint8_t texel_weights_of_weight[BLOCK_MAX_WEIGHTS][BLOCK_MAX_TEXELS];
+};
+
+/**
+ * @brief Weight quantization transfer table.
+ *
+ * ASTC can store texel weights at many quantization levels, so for performance we store essential
+ * information about each level as a precomputed data structure. Unquantized weights are integers
+ * or floats in the range [0, 64].
+ *
+ * This structure provides a table, used to estimate the closest quantized weight for a given
+ * floating-point weight. For each quantized weight, the corresponding unquantized values. For each
+ * quantized weight, a previous-value and a next-value.
+*/
+struct quant_and_transfer_table
+{
+ /** @brief The unscrambled unquantized value. */
+ int8_t quant_to_unquant[32];
+
+ /** @brief The scrambling order: scrambled_quant = map[unscrambled_quant]. */
+ int8_t scramble_map[32];
+
+ /** @brief The unscrambling order: unscrambled_unquant = map[scrambled_quant]. */
+ int8_t unscramble_and_unquant_map[32];
+
+ /**
+ * @brief A table of previous-and-next weights, indexed by the current unquantized value.
+ * * bits 7:0 = previous-index, unquantized
+ * * bits 15:8 = next-index, unquantized
+ */
+ uint16_t prev_next_values[65];
+};
+
+/** @brief The precomputed quant and transfer table. */
+extern const quant_and_transfer_table quant_and_xfer_tables[12];
+
+/** @brief The block is an error block, and will return error color or NaN. */
+static constexpr uint8_t SYM_BTYPE_ERROR { 0 };
+
+/** @brief The block is a constant color block using FP16 colors. */
+static constexpr uint8_t SYM_BTYPE_CONST_F16 { 1 };
+
+/** @brief The block is a constant color block using UNORM16 colors. */
+static constexpr uint8_t SYM_BTYPE_CONST_U16 { 2 };
+
+/** @brief The block is a normal non-constant color block. */
+static constexpr uint8_t SYM_BTYPE_NONCONST { 3 };
+
+/**
+ * @brief A symbolic representation of a compressed block.
+ *
+ * The symbolic representation stores the unpacked content of a single
+ * @c physical_compressed_block, in a form which is much easier to access for
+ * the rest of the compressor code.
+ */
+struct symbolic_compressed_block
+{
+ /** @brief The block type, one of the @c SYM_BTYPE_* constants. */
+ uint8_t block_type;
+
+ /** @brief The number of partitions; valid for @c NONCONST blocks. */
+ uint8_t partition_count;
+
+ /** @brief Non-zero if the color formats matched; valid for @c NONCONST blocks. */
+ uint8_t color_formats_matched;
+
+ /** @brief The plane 2 color component, or -1 if single plane; valid for @c NONCONST blocks. */
+ int8_t plane2_component;
+
+ /** @brief The block mode; valid for @c NONCONST blocks. */
+ uint16_t block_mode;
+
+ /** @brief The partition index; valid for @c NONCONST blocks if 2 or more partitions. */
+ uint16_t partition_index;
+
+ /** @brief The endpoint color formats for each partition; valid for @c NONCONST blocks. */
+ uint8_t color_formats[BLOCK_MAX_PARTITIONS];
+
+ /** @brief The endpoint color quant mode; valid for @c NONCONST blocks. */
+ quant_method quant_mode;
+
+ /** @brief The error of the current encoding; valid for @c NONCONST blocks. */
+ float errorval;
+
+ // We can't have both of these at the same time
+ union {
+ /** @brief The constant color; valid for @c CONST blocks. */
+ int constant_color[BLOCK_MAX_COMPONENTS];
+
+ /** @brief The quantized endpoint color pairs; valid for @c NONCONST blocks. */
+ uint8_t color_values[BLOCK_MAX_PARTITIONS][8];
+ };
+
+ /** @brief The quantized and decimated weights.
+ *
+ * Weights are stored in the 0-64 unpacked range allowing them to be used
+ * directly in encoding passes without per-use unpacking. Packing happens
+ * when converting to/from the physical bitstream encoding.
+ *
+ * If dual plane, the second plane starts at @c weights[WEIGHTS_PLANE2_OFFSET].
+ */
+ uint8_t weights[BLOCK_MAX_WEIGHTS];
+
+ /**
+ * @brief Get the weight quantization used by this block mode.
+ *
+ * @return The quantization level.
+ */
+ inline quant_method get_color_quant_mode() const
+ {
+ return this->quant_mode;
+ }
+};
+
+/**
+ * @brief A physical representation of a compressed block.
+ *
+ * The physical representation stores the raw bytes of the format in memory.
+ */
+struct physical_compressed_block
+{
+ /** @brief The ASTC encoded data for a single block. */
+ uint8_t data[16];
+};
+
+
+/**
+ * @brief Parameter structure for @c compute_pixel_region_variance().
+ *
+ * This function takes a structure to avoid spilling arguments to the stack on every function
+ * invocation, as there are a lot of parameters.
+ */
+struct pixel_region_args
+{
+ /** @brief The image to analyze. */
+ const astcenc_image* img;
+
+ /** @brief The component swizzle pattern. */
+ astcenc_swizzle swz;
+
+ /** @brief Should the algorithm bother with Z axis processing? */
+ bool have_z;
+
+ /** @brief The kernel radius for alpha processing. */
+ unsigned int alpha_kernel_radius;
+
+ /** @brief The X dimension of the working data to process. */
+ unsigned int size_x;
+
+ /** @brief The Y dimension of the working data to process. */
+ unsigned int size_y;
+
+ /** @brief The Z dimension of the working data to process. */
+ unsigned int size_z;
+
+ /** @brief The X position of first src and dst data in the data set. */
+ unsigned int offset_x;
+
+ /** @brief The Y position of first src and dst data in the data set. */
+ unsigned int offset_y;
+
+ /** @brief The Z position of first src and dst data in the data set. */
+ unsigned int offset_z;
+
+ /** @brief The working memory buffer. */
+ vfloat4 *work_memory;
+};
+
+/**
+ * @brief Parameter structure for @c compute_averages_proc().
+ */
+struct avg_args
+{
+ /** @brief The arguments for the nested variance computation. */
+ pixel_region_args arg;
+
+ /** @brief The image X dimensions. */
+ unsigned int img_size_x;
+
+ /** @brief The image Y dimensions. */
+ unsigned int img_size_y;
+
+ /** @brief The image Z dimensions. */
+ unsigned int img_size_z;
+
+ /** @brief The maximum working block dimensions in X and Y dimensions. */
+ unsigned int blk_size_xy;
+
+ /** @brief The maximum working block dimensions in Z dimensions. */
+ unsigned int blk_size_z;
+
+ /** @brief The working block memory size. */
+ unsigned int work_memory_size;
+};
+
+#if defined(ASTCENC_DIAGNOSTICS)
+/* See astcenc_diagnostic_trace header for details. */
+class TraceLog;
+#endif
+
+/**
+ * @brief The astcenc compression context.
+ */
+struct astcenc_contexti
+{
+ /** @brief The configuration this context was created with. */
+ astcenc_config config;
+
+ /** @brief The thread count supported by this context. */
+ unsigned int thread_count;
+
+ /** @brief The block size descriptor this context was created with. */
+ block_size_descriptor* bsd;
+
+ /*
+ * Fields below here are not needed in a decompress-only build, but some remain as they are
+ * small and it avoids littering the code with #ifdefs. The most significant contributors to
+ * large structure size are omitted.
+ */
+
+ /** @brief The input image alpha channel averages table, may be @c nullptr if not needed. */
+ float* input_alpha_averages;
+
+ /** @brief The scratch working buffers, one per thread (see @c thread_count). */
+ compression_working_buffers* working_buffers;
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+ /** @brief The pixel region and variance worker arguments. */
+ avg_args avg_preprocess_args;
+#endif
+
+#if defined(ASTCENC_DIAGNOSTICS)
+ /**
+ * @brief The diagnostic trace logger.
+ *
+ * Note that this is a singleton, so can only be used in single threaded mode. It only exists
+ * here so we have a reference to close the file at the end of the capture.
+ */
+ TraceLog* trace_log;
+#endif
+};
+
+/* ============================================================================
+ Functionality for managing block sizes and partition tables.
+============================================================================ */
+
+/**
+ * @brief Populate the block size descriptor for the target block size.
+ *
+ * This will also initialize the partition table metadata, which is stored as part of the BSD
+ * structure.
+ *
+ * @param x_texels The number of texels in the block X dimension.
+ * @param y_texels The number of texels in the block Y dimension.
+ * @param z_texels The number of texels in the block Z dimension.
+ * @param can_omit_modes Can we discard modes and partitionings that astcenc won't use?
+ * @param partition_count_cutoff The partition count cutoff to use, if we can omit partitionings.
+ * @param mode_cutoff The block mode percentile cutoff [0-1].
+ * @param[out] bsd The descriptor to initialize.
+ */
+void init_block_size_descriptor(
+ unsigned int x_texels,
+ unsigned int y_texels,
+ unsigned int z_texels,
+ bool can_omit_modes,
+ unsigned int partition_count_cutoff,
+ float mode_cutoff,
+ block_size_descriptor& bsd);
+
+/**
+ * @brief Populate the partition tables for the target block size.
+ *
+ * Note the @c bsd descriptor must be initialized by calling @c init_block_size_descriptor() before
+ * calling this function.
+ *
+ * @param[out] bsd The block size information structure to populate.
+ * @param can_omit_partitionings True if we can we drop partitionings that astcenc won't use.
+ * @param partition_count_cutoff The partition count cutoff to use, if we can omit partitionings.
+ */
+void init_partition_tables(
+ block_size_descriptor& bsd,
+ bool can_omit_partitionings,
+ unsigned int partition_count_cutoff);
+
+/**
+ * @brief Get the percentile table for 2D block modes.
+ *
+ * This is an empirically determined prioritization of which block modes to use in the search in
+ * terms of their centile (lower centiles = more useful).
+ *
+ * Returns a dynamically allocated array; caller must free with delete[].
+ *
+ * @param xdim The block x size.
+ * @param ydim The block y size.
+ *
+ * @return The unpacked table.
+ */
+const float* get_2d_percentile_table(
+ unsigned int xdim,
+ unsigned int ydim);
+
+/**
+ * @brief Query if a 2D block size is legal.
+ *
+ * @return True if legal, false otherwise.
+ */
+bool is_legal_2d_block_size(
+ unsigned int xdim,
+ unsigned int ydim);
+
+/**
+ * @brief Query if a 3D block size is legal.
+ *
+ * @return True if legal, false otherwise.
+ */
+bool is_legal_3d_block_size(
+ unsigned int xdim,
+ unsigned int ydim,
+ unsigned int zdim);
+
+/* ============================================================================
+ Functionality for managing BISE quantization and unquantization.
+============================================================================ */
+
+/**
+ * @brief The precomputed table for quantizing color values.
+ *
+ * Converts unquant value in 0-255 range into quant value in 0-255 range.
+ * No BISE scrambling is applied at this stage.
+ *
+ * Indexed by [quant_mode - 4][data_value].
+ */
+extern const uint8_t color_unquant_to_uquant_tables[17][256];
+
+/**
+ * @brief The precomputed table for packing quantized color values.
+ *
+ * Converts quant value in 0-255 range into packed quant value in 0-N range,
+ * with BISE scrambling applied.
+ *
+ * Indexed by [quant_mode - 4][data_value].
+ */
+extern const uint8_t color_uquant_to_scrambled_pquant_tables[17][256];
+
+/**
+ * @brief The precomputed table for unpacking color values.
+ *
+ * Converts quant value in 0-N range into unpacked value in 0-255 range,
+ * with BISE unscrambling applied.
+ *
+ * Indexed by [quant_mode - 4][data_value].
+ */
+extern const uint8_t* color_scrambled_pquant_to_uquant_tables[17];
+
+/**
+ * @brief The precomputed quant mode storage table.
+ *
+ * Indexing by [integer_count/2][bits] gives us the quantization level for a given integer count and
+ * number of compressed storage bits. Returns -1 for cases where the requested integer count cannot
+ * ever fit in the supplied storage size.
+ */
+extern const int8_t quant_mode_table[10][128];
+
+/**
+ * @brief Encode a packed string using BISE.
+ *
+ * Note that BISE can return strings that are not a whole number of bytes in length, and ASTC can
+ * start storing strings in a block at arbitrary bit offsets in the encoded data.
+ *
+ * @param quant_level The BISE alphabet size.
+ * @param character_count The number of characters in the string.
+ * @param input_data The unpacked string, one byte per character.
+ * @param[in,out] output_data The output packed string.
+ * @param bit_offset The starting offset in the output storage.
+ */
+void encode_ise(
+ quant_method quant_level,
+ unsigned int character_count,
+ const uint8_t* input_data,
+ uint8_t* output_data,
+ unsigned int bit_offset);
+
+/**
+ * @brief Decode a packed string using BISE.
+ *
+ * Note that BISE input strings are not a whole number of bytes in length, and ASTC can start
+ * strings at arbitrary bit offsets in the encoded data.
+ *
+ * @param quant_level The BISE alphabet size.
+ * @param character_count The number of characters in the string.
+ * @param input_data The packed string.
+ * @param[in,out] output_data The output storage, one byte per character.
+ * @param bit_offset The starting offset in the output storage.
+ */
+void decode_ise(
+ quant_method quant_level,
+ unsigned int character_count,
+ const uint8_t* input_data,
+ uint8_t* output_data,
+ unsigned int bit_offset);
+
+/**
+ * @brief Return the number of bits needed to encode an ISE sequence.
+ *
+ * This implementation assumes that the @c quant level is untrusted, given it may come from random
+ * data being decompressed, so we return an arbitrary unencodable size if that is the case.
+ *
+ * @param character_count The number of items in the sequence.
+ * @param quant_level The desired quantization level.
+ *
+ * @return The number of bits needed to encode the BISE string.
+ */
+unsigned int get_ise_sequence_bitcount(
+ unsigned int character_count,
+ quant_method quant_level);
+
+/* ============================================================================
+ Functionality for managing color partitioning.
+============================================================================ */
+
+/**
+ * @brief Compute averages and dominant directions for each partition in a 2 component texture.
+ *
+ * @param pi The partition info for the current trial.
+ * @param blk The image block color data to be compressed.
+ * @param component1 The first component included in the analysis.
+ * @param component2 The second component included in the analysis.
+ * @param[out] pm The output partition metrics.
+ * - Only pi.partition_count array entries actually get initialized.
+ * - Direction vectors @c pm.dir are not normalized.
+ */
+void compute_avgs_and_dirs_2_comp(
+ const partition_info& pi,
+ const image_block& blk,
+ unsigned int component1,
+ unsigned int component2,
+ partition_metrics pm[BLOCK_MAX_PARTITIONS]);
+
+/**
+ * @brief Compute averages and dominant directions for each partition in a 3 component texture.
+ *
+ * @param pi The partition info for the current trial.
+ * @param blk The image block color data to be compressed.
+ * @param omitted_component The component excluded from the analysis.
+ * @param[out] pm The output partition metrics.
+ * - Only pi.partition_count array entries actually get initialized.
+ * - Direction vectors @c pm.dir are not normalized.
+ */
+void compute_avgs_and_dirs_3_comp(
+ const partition_info& pi,
+ const image_block& blk,
+ unsigned int omitted_component,
+ partition_metrics pm[BLOCK_MAX_PARTITIONS]);
+
+/**
+ * @brief Compute averages and dominant directions for each partition in a 3 component texture.
+ *
+ * This is a specialization of @c compute_avgs_and_dirs_3_comp where the omitted component is
+ * always alpha, a common case during partition search.
+ *
+ * @param pi The partition info for the current trial.
+ * @param blk The image block color data to be compressed.
+ * @param[out] pm The output partition metrics.
+ * - Only pi.partition_count array entries actually get initialized.
+ * - Direction vectors @c pm.dir are not normalized.
+ */
+void compute_avgs_and_dirs_3_comp_rgb(
+ const partition_info& pi,
+ const image_block& blk,
+ partition_metrics pm[BLOCK_MAX_PARTITIONS]);
+
+/**
+ * @brief Compute averages and dominant directions for each partition in a 4 component texture.
+ *
+ * @param pi The partition info for the current trial.
+ * @param blk The image block color data to be compressed.
+ * @param[out] pm The output partition metrics.
+ * - Only pi.partition_count array entries actually get initialized.
+ * - Direction vectors @c pm.dir are not normalized.
+ */
+void compute_avgs_and_dirs_4_comp(
+ const partition_info& pi,
+ const image_block& blk,
+ partition_metrics pm[BLOCK_MAX_PARTITIONS]);
+
+/**
+ * @brief Compute the RGB error for uncorrelated and same chroma projections.
+ *
+ * The output of compute averages and dirs is post processed to define two lines, both of which go
+ * through the mean-color-value. One line has a direction defined by the dominant direction; this
+ * is used to assess the error from using an uncorrelated color representation. The other line goes
+ * through (0,0,0) and is used to assess the error from using an RGBS color representation.
+ *
+ * This function computes the squared error when using these two representations.
+ *
+ * @param pi The partition info for the current trial.
+ * @param blk The image block color data to be compressed.
+ * @param[in,out] plines Processed line inputs, and line length outputs.
+ * @param[out] uncor_error The cumulative error for using the uncorrelated line.
+ * @param[out] samec_error The cumulative error for using the same chroma line.
+ */
+void compute_error_squared_rgb(
+ const partition_info& pi,
+ const image_block& blk,
+ partition_lines3 plines[BLOCK_MAX_PARTITIONS],
+ float& uncor_error,
+ float& samec_error);
+
+/**
+ * @brief Compute the RGBA error for uncorrelated and same chroma projections.
+ *
+ * The output of compute averages and dirs is post processed to define two lines, both of which go
+ * through the mean-color-value. One line has a direction defined by the dominant direction; this
+ * is used to assess the error from using an uncorrelated color representation. The other line goes
+ * through (0,0,0,1) and is used to assess the error from using an RGBS color representation.
+ *
+ * This function computes the squared error when using these two representations.
+ *
+ * @param pi The partition info for the current trial.
+ * @param blk The image block color data to be compressed.
+ * @param uncor_plines Processed uncorrelated partition lines for each partition.
+ * @param samec_plines Processed same chroma partition lines for each partition.
+ * @param[out] uncor_lengths The length of each components deviation from the line.
+ * @param[out] samec_lengths The length of each components deviation from the line.
+ * @param[out] uncor_error The cumulative error for using the uncorrelated line.
+ * @param[out] samec_error The cumulative error for using the same chroma line.
+ */
+void compute_error_squared_rgba(
+ const partition_info& pi,
+ const image_block& blk,
+ const processed_line4 uncor_plines[BLOCK_MAX_PARTITIONS],
+ const processed_line4 samec_plines[BLOCK_MAX_PARTITIONS],
+ float uncor_lengths[BLOCK_MAX_PARTITIONS],
+ float samec_lengths[BLOCK_MAX_PARTITIONS],
+ float& uncor_error,
+ float& samec_error);
+
+/**
+ * @brief Find the best set of partitions to trial for a given block.
+ *
+ * On return the @c best_partitions list will contain the two best partition
+ * candidates; one assuming data has uncorrelated chroma and one assuming the
+ * data has correlated chroma. The best candidate is returned first in the list.
+ *
+ * @param bsd The block size information.
+ * @param blk The image block color data to compress.
+ * @param partition_count The number of partitions in the block.
+ * @param partition_search_limit The number of candidate partition encodings to trial.
+ * @param[out] best_partitions The best partition candidates.
+ * @param requested_candidates The number of requested partitionings. May return fewer if
+ * candidates are not available.
+ *
+ * @return The actual number of candidates returned.
+ */
+unsigned int find_best_partition_candidates(
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ unsigned int partition_count,
+ unsigned int partition_search_limit,
+ unsigned int best_partitions[TUNE_MAX_PARTITIONING_CANDIDATES],
+ unsigned int requested_candidates);
+
+/* ============================================================================
+ Functionality for managing images and image related data.
+============================================================================ */
+
+/**
+ * @brief Setup computation of regional averages in an image.
+ *
+ * This must be done by only a single thread per image, before any thread calls
+ * @c compute_averages().
+ *
+ * Results are written back into @c img->input_alpha_averages.
+ *
+ * @param img The input image data, also holds output data.
+ * @param alpha_kernel_radius The kernel radius (in pixels) for alpha mods.
+ * @param swz Input data component swizzle.
+ * @param[out] ag The average variance arguments to init.
+ *
+ * @return The number of tasks in the processing stage.
+ */
+unsigned int init_compute_averages(
+ const astcenc_image& img,
+ unsigned int alpha_kernel_radius,
+ const astcenc_swizzle& swz,
+ avg_args& ag);
+
+/**
+ * @brief Compute averages for a pixel region.
+ *
+ * The routine computes both in a single pass, using a summed-area table to decouple the running
+ * time from the averaging/variance kernel size.
+ *
+ * @param[out] ctx The compressor context storing the output data.
+ * @param arg The input parameter structure.
+ */
+void compute_pixel_region_variance(
+ astcenc_contexti& ctx,
+ const pixel_region_args& arg);
+/**
+ * @brief Load a single image block from the input image.
+ *
+ * @param decode_mode The compression color profile.
+ * @param img The input image data.
+ * @param[out] blk The image block to populate.
+ * @param bsd The block size information.
+ * @param xpos The block X coordinate in the input image.
+ * @param ypos The block Y coordinate in the input image.
+ * @param zpos The block Z coordinate in the input image.
+ * @param swz The swizzle to apply on load.
+ */
+void load_image_block(
+ astcenc_profile decode_mode,
+ const astcenc_image& img,
+ image_block& blk,
+ const block_size_descriptor& bsd,
+ unsigned int xpos,
+ unsigned int ypos,
+ unsigned int zpos,
+ const astcenc_swizzle& swz);
+
+/**
+ * @brief Load a single image block from the input image.
+ *
+ * This specialized variant can be used only if the block is 2D LDR U8 data,
+ * with no swizzle.
+ *
+ * @param decode_mode The compression color profile.
+ * @param img The input image data.
+ * @param[out] blk The image block to populate.
+ * @param bsd The block size information.
+ * @param xpos The block X coordinate in the input image.
+ * @param ypos The block Y coordinate in the input image.
+ * @param zpos The block Z coordinate in the input image.
+ * @param swz The swizzle to apply on load.
+ */
+void load_image_block_fast_ldr(
+ astcenc_profile decode_mode,
+ const astcenc_image& img,
+ image_block& blk,
+ const block_size_descriptor& bsd,
+ unsigned int xpos,
+ unsigned int ypos,
+ unsigned int zpos,
+ const astcenc_swizzle& swz);
+
+/**
+ * @brief Store a single image block to the output image.
+ *
+ * @param[out] img The output image data.
+ * @param blk The image block to export.
+ * @param bsd The block size information.
+ * @param xpos The block X coordinate in the input image.
+ * @param ypos The block Y coordinate in the input image.
+ * @param zpos The block Z coordinate in the input image.
+ * @param swz The swizzle to apply on store.
+ */
+void store_image_block(
+ astcenc_image& img,
+ const image_block& blk,
+ const block_size_descriptor& bsd,
+ unsigned int xpos,
+ unsigned int ypos,
+ unsigned int zpos,
+ const astcenc_swizzle& swz);
+
+/* ============================================================================
+ Functionality for computing endpoint colors and weights for a block.
+============================================================================ */
+
+/**
+ * @brief Compute ideal endpoint colors and weights for 1 plane of weights.
+ *
+ * The ideal endpoints define a color line for the partition. For each texel the ideal weight
+ * defines an exact position on the partition color line. We can then use these to assess the error
+ * introduced by removing and quantizing the weight grid.
+ *
+ * @param blk The image block color data to compress.
+ * @param pi The partition info for the current trial.
+ * @param[out] ei The endpoint and weight values.
+ */
+void compute_ideal_colors_and_weights_1plane(
+ const image_block& blk,
+ const partition_info& pi,
+ endpoints_and_weights& ei);
+
+/**
+ * @brief Compute ideal endpoint colors and weights for 2 planes of weights.
+ *
+ * The ideal endpoints define a color line for the partition. For each texel the ideal weight
+ * defines an exact position on the partition color line. We can then use these to assess the error
+ * introduced by removing and quantizing the weight grid.
+ *
+ * @param bsd The block size information.
+ * @param blk The image block color data to compress.
+ * @param plane2_component The component assigned to plane 2.
+ * @param[out] ei1 The endpoint and weight values for plane 1.
+ * @param[out] ei2 The endpoint and weight values for plane 2.
+ */
+void compute_ideal_colors_and_weights_2planes(
+ const block_size_descriptor& bsd,
+ const image_block& blk,
+ unsigned int plane2_component,
+ endpoints_and_weights& ei1,
+ endpoints_and_weights& ei2);
+
+/**
+ * @brief Compute the optimal unquantized weights for a decimation table.
+ *
+ * After computing ideal weights for the case for a complete weight grid, we we want to compute the
+ * ideal weights for the case where weights exist only for some texels. We do this with a
+ * steepest-descent grid solver which works as follows:
+ *
+ * First, for each actual weight, perform a weighted averaging of the texels affected by the weight.
+ * Then, set step size to <some initial value> and attempt one step towards the original ideal
+ * weight if it helps to reduce error.
+ *
+ * @param ei The non-decimated endpoints and weights.
+ * @param di The selected weight decimation.
+ * @param[out] dec_weight_ideal_value The ideal values for the decimated weight set.
+ */
+void compute_ideal_weights_for_decimation(
+ const endpoints_and_weights& ei,
+ const decimation_info& di,
+ float* dec_weight_ideal_value);
+
+/**
+ * @brief Compute the optimal quantized weights for a decimation table.
+ *
+ * We test the two closest weight indices in the allowed quantization range and keep the weight that
+ * is the closest match.
+ *
+ * @param di The selected weight decimation.
+ * @param low_bound The lowest weight allowed.
+ * @param high_bound The highest weight allowed.
+ * @param dec_weight_ideal_value The ideal weight set.
+ * @param[out] dec_weight_quant_uvalue The output quantized weight as a float.
+ * @param[out] dec_weight_uquant The output quantized weight as encoded int.
+ * @param quant_level The desired weight quant level.
+ */
+void compute_quantized_weights_for_decimation(
+ const decimation_info& di,
+ float low_bound,
+ float high_bound,
+ const float* dec_weight_ideal_value,
+ float* dec_weight_quant_uvalue,
+ uint8_t* dec_weight_uquant,
+ quant_method quant_level);
+
+/**
+ * @brief Compute the error of a decimated weight set for 1 plane.
+ *
+ * After computing ideal weights for the case with one weight per texel, we want to compute the
+ * error for decimated weight grids where weights are stored at a lower resolution. This function
+ * computes the error of the reduced grid, compared to the full grid.
+ *
+ * @param eai The ideal weights for the full grid.
+ * @param di The selected weight decimation.
+ * @param dec_weight_quant_uvalue The quantized weights for the decimated grid.
+ *
+ * @return The accumulated error.
+ */
+float compute_error_of_weight_set_1plane(
+ const endpoints_and_weights& eai,
+ const decimation_info& di,
+ const float* dec_weight_quant_uvalue);
+
+/**
+ * @brief Compute the error of a decimated weight set for 2 planes.
+ *
+ * After computing ideal weights for the case with one weight per texel, we want to compute the
+ * error for decimated weight grids where weights are stored at a lower resolution. This function
+ * computes the error of the reduced grid, compared to the full grid.
+ *
+ * @param eai1 The ideal weights for the full grid and plane 1.
+ * @param eai2 The ideal weights for the full grid and plane 2.
+ * @param di The selected weight decimation.
+ * @param dec_weight_quant_uvalue_plane1 The quantized weights for the decimated grid plane 1.
+ * @param dec_weight_quant_uvalue_plane2 The quantized weights for the decimated grid plane 2.
+ *
+ * @return The accumulated error.
+ */
+float compute_error_of_weight_set_2planes(
+ const endpoints_and_weights& eai1,
+ const endpoints_and_weights& eai2,
+ const decimation_info& di,
+ const float* dec_weight_quant_uvalue_plane1,
+ const float* dec_weight_quant_uvalue_plane2);
+
+/**
+ * @brief Pack a single pair of color endpoints as effectively as possible.
+ *
+ * The user requests a base color endpoint mode in @c format, but the quantizer may choose a
+ * delta-based representation. It will report back the format variant it actually used.
+ *
+ * @param color0 The input unquantized color0 endpoint for absolute endpoint pairs.
+ * @param color1 The input unquantized color1 endpoint for absolute endpoint pairs.
+ * @param rgbs_color The input unquantized RGBS variant endpoint for same chroma endpoints.
+ * @param rgbo_color The input unquantized RGBS variant endpoint for HDR endpoints.
+ * @param format The desired base format.
+ * @param[out] output The output storage for the quantized colors/
+ * @param quant_level The quantization level requested.
+ *
+ * @return The actual endpoint mode used.
+ */
+uint8_t pack_color_endpoints(
+ vfloat4 color0,
+ vfloat4 color1,
+ vfloat4 rgbs_color,
+ vfloat4 rgbo_color,
+ int format,
+ uint8_t* output,
+ quant_method quant_level);
+
+/**
+ * @brief Unpack a single pair of encoded endpoints.
+ *
+ * Endpoints must be unscrambled and converted into the 0-255 range before calling this functions.
+ *
+ * @param decode_mode The decode mode (LDR, HDR).
+ * @param format The color endpoint mode used.
+ * @param input The raw array of encoded input integers. The length of this array
+ * depends on @c format; it can be safely assumed to be large enough.
+ * @param[out] rgb_hdr Is the endpoint using HDR for the RGB channels?
+ * @param[out] alpha_hdr Is the endpoint using HDR for the A channel?
+ * @param[out] output0 The output color for endpoint 0.
+ * @param[out] output1 The output color for endpoint 1.
+ */
+void unpack_color_endpoints(
+ astcenc_profile decode_mode,
+ int format,
+ const uint8_t* input,
+ bool& rgb_hdr,
+ bool& alpha_hdr,
+ vint4& output0,
+ vint4& output1);
+
+/**
+ * @brief Unpack a set of quantized and decimated weights.
+ *
+ * TODO: Can we skip this for non-decimated weights now that the @c scb is
+ * already storing unquantized weights?
+ *
+ * @param bsd The block size information.
+ * @param scb The symbolic compressed encoding.
+ * @param di The weight grid decimation table.
+ * @param is_dual_plane @c true if this is a dual plane block, @c false otherwise.
+ * @param[out] weights_plane1 The output array for storing the plane 1 weights.
+ * @param[out] weights_plane2 The output array for storing the plane 2 weights.
+ */
+void unpack_weights(
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ const decimation_info& di,
+ bool is_dual_plane,
+ int weights_plane1[BLOCK_MAX_TEXELS],
+ int weights_plane2[BLOCK_MAX_TEXELS]);
+
+/**
+ * @brief Identify, for each mode, which set of color endpoint produces the best result.
+ *
+ * Returns the best @c tune_candidate_limit best looking modes, along with the ideal color encoding
+ * combination for each. The modified quantization level can be used when all formats are the same,
+ * as this frees up two additional bits of storage.
+ *
+ * @param pi The partition info for the current trial.
+ * @param blk The image block color data to compress.
+ * @param ep The ideal endpoints.
+ * @param qwt_bitcounts Bit counts for different quantization methods.
+ * @param qwt_errors Errors for different quantization methods.
+ * @param tune_candidate_limit The max number of candidates to return, may be less.
+ * @param start_block_mode The first block mode to inspect.
+ * @param end_block_mode The last block mode to inspect.
+ * @param[out] partition_format_specifiers The best formats per partition.
+ * @param[out] block_mode The best packed block mode indexes.
+ * @param[out] quant_level The best color quant level.
+ * @param[out] quant_level_mod The best color quant level if endpoints are the same.
+ * @param[out] tmpbuf Preallocated scratch buffers for the compressor.
+ *
+ * @return The actual number of candidate matches returned.
+ */
+unsigned int compute_ideal_endpoint_formats(
+ const partition_info& pi,
+ const image_block& blk,
+ const endpoints& ep,
+ const int8_t* qwt_bitcounts,
+ const float* qwt_errors,
+ unsigned int tune_candidate_limit,
+ unsigned int start_block_mode,
+ unsigned int end_block_mode,
+ uint8_t partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS],
+ int block_mode[TUNE_MAX_TRIAL_CANDIDATES],
+ quant_method quant_level[TUNE_MAX_TRIAL_CANDIDATES],
+ quant_method quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES],
+ compression_working_buffers& tmpbuf);
+
+/**
+ * @brief For a given 1 plane weight set recompute the endpoint colors.
+ *
+ * As we quantize and decimate weights the optimal endpoint colors may change slightly, so we must
+ * recompute the ideal colors for a specific weight set.
+ *
+ * @param blk The image block color data to compress.
+ * @param pi The partition info for the current trial.
+ * @param di The weight grid decimation table.
+ * @param dec_weights_uquant The quantized weight set.
+ * @param[in,out] ep The color endpoints (modifed in place).
+ * @param[out] rgbs_vectors The RGB+scale vectors for LDR blocks.
+ * @param[out] rgbo_vectors The RGB+offset vectors for HDR blocks.
+ */
+void recompute_ideal_colors_1plane(
+ const image_block& blk,
+ const partition_info& pi,
+ const decimation_info& di,
+ const uint8_t* dec_weights_uquant,
+ endpoints& ep,
+ vfloat4 rgbs_vectors[BLOCK_MAX_PARTITIONS],
+ vfloat4 rgbo_vectors[BLOCK_MAX_PARTITIONS]);
+
+/**
+ * @brief For a given 2 plane weight set recompute the endpoint colors.
+ *
+ * As we quantize and decimate weights the optimal endpoint colors may change slightly, so we must
+ * recompute the ideal colors for a specific weight set.
+ *
+ * @param blk The image block color data to compress.
+ * @param bsd The block_size descriptor.
+ * @param di The weight grid decimation table.
+ * @param dec_weights_uquant_plane1 The quantized weight set for plane 1.
+ * @param dec_weights_uquant_plane2 The quantized weight set for plane 2.
+ * @param[in,out] ep The color endpoints (modifed in place).
+ * @param[out] rgbs_vector The RGB+scale color for LDR blocks.
+ * @param[out] rgbo_vector The RGB+offset color for HDR blocks.
+ * @param plane2_component The component assigned to plane 2.
+ */
+void recompute_ideal_colors_2planes(
+ const image_block& blk,
+ const block_size_descriptor& bsd,
+ const decimation_info& di,
+ const uint8_t* dec_weights_uquant_plane1,
+ const uint8_t* dec_weights_uquant_plane2,
+ endpoints& ep,
+ vfloat4& rgbs_vector,
+ vfloat4& rgbo_vector,
+ int plane2_component);
+
+/**
+ * @brief Expand the angular tables needed for the alternative to PCA that we use.
+ */
+void prepare_angular_tables();
+
+/**
+ * @brief Compute the angular endpoints for one plane for each block mode.
+ *
+ * @param only_always Only consider block modes that are always enabled.
+ * @param bsd The block size descriptor for the current trial.
+ * @param dec_weight_ideal_value The ideal decimated unquantized weight values.
+ * @param max_weight_quant The maximum block mode weight quantization allowed.
+ * @param[out] tmpbuf Preallocated scratch buffers for the compressor.
+ */
+void compute_angular_endpoints_1plane(
+ bool only_always,
+ const block_size_descriptor& bsd,
+ const float* dec_weight_ideal_value,
+ unsigned int max_weight_quant,
+ compression_working_buffers& tmpbuf);
+
+/**
+ * @brief Compute the angular endpoints for two planes for each block mode.
+ *
+ * @param bsd The block size descriptor for the current trial.
+ * @param dec_weight_ideal_value The ideal decimated unquantized weight values.
+ * @param max_weight_quant The maximum block mode weight quantization allowed.
+ * @param[out] tmpbuf Preallocated scratch buffers for the compressor.
+ */
+void compute_angular_endpoints_2planes(
+ const block_size_descriptor& bsd,
+ const float* dec_weight_ideal_value,
+ unsigned int max_weight_quant,
+ compression_working_buffers& tmpbuf);
+
+/* ============================================================================
+ Functionality for high level compression and decompression access.
+============================================================================ */
+
+/**
+ * @brief Compress an image block into a physical block.
+ *
+ * @param ctx The compressor context and configuration.
+ * @param blk The image block color data to compress.
+ * @param[out] pcb The physical compressed block output.
+ * @param[out] tmpbuf Preallocated scratch buffers for the compressor.
+ */
+void compress_block(
+ const astcenc_contexti& ctx,
+ const image_block& blk,
+ physical_compressed_block& pcb,
+ compression_working_buffers& tmpbuf);
+
+/**
+ * @brief Decompress a symbolic block in to an image block.
+ *
+ * @param decode_mode The decode mode (LDR, HDR, etc).
+ * @param bsd The block size information.
+ * @param xpos The X coordinate of the block in the overall image.
+ * @param ypos The Y coordinate of the block in the overall image.
+ * @param zpos The Z coordinate of the block in the overall image.
+ * @param[out] blk The decompressed image block color data.
+ */
+void decompress_symbolic_block(
+ astcenc_profile decode_mode,
+ const block_size_descriptor& bsd,
+ int xpos,
+ int ypos,
+ int zpos,
+ const symbolic_compressed_block& scb,
+ image_block& blk);
+
+/**
+ * @brief Compute the error between a symbolic block and the original input data.
+ *
+ * This function is specialized for 2 plane and 1 partition search.
+ *
+ * In RGBM mode this will reject blocks that attempt to encode a zero M value.
+ *
+ * @param config The compressor config.
+ * @param bsd The block size information.
+ * @param scb The symbolic compressed encoding.
+ * @param blk The original image block color data.
+ *
+ * @return Returns the computed error, or a negative value if the encoding
+ * should be rejected for any reason.
+ */
+float compute_symbolic_block_difference_2plane(
+ const astcenc_config& config,
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ const image_block& blk);
+
+/**
+ * @brief Compute the error between a symbolic block and the original input data.
+ *
+ * This function is specialized for 1 plane and N partition search.
+ *
+ * In RGBM mode this will reject blocks that attempt to encode a zero M value.
+ *
+ * @param config The compressor config.
+ * @param bsd The block size information.
+ * @param scb The symbolic compressed encoding.
+ * @param blk The original image block color data.
+ *
+ * @return Returns the computed error, or a negative value if the encoding
+ * should be rejected for any reason.
+ */
+float compute_symbolic_block_difference_1plane(
+ const astcenc_config& config,
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ const image_block& blk);
+
+/**
+ * @brief Compute the error between a symbolic block and the original input data.
+ *
+ * This function is specialized for 1 plane and 1 partition search.
+ *
+ * In RGBM mode this will reject blocks that attempt to encode a zero M value.
+ *
+ * @param config The compressor config.
+ * @param bsd The block size information.
+ * @param scb The symbolic compressed encoding.
+ * @param blk The original image block color data.
+ *
+ * @return Returns the computed error, or a negative value if the encoding
+ * should be rejected for any reason.
+ */
+float compute_symbolic_block_difference_1plane_1partition(
+ const astcenc_config& config,
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ const image_block& blk);
+
+/**
+ * @brief Convert a symbolic representation into a binary physical encoding.
+ *
+ * It is assumed that the symbolic encoding is valid and encodable, or
+ * previously flagged as an error block if an error color it to be encoded.
+ *
+ * @param bsd The block size information.
+ * @param scb The symbolic representation.
+ * @param[out] pcb The binary encoded data.
+ */
+void symbolic_to_physical(
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ physical_compressed_block& pcb);
+
+/**
+ * @brief Convert a binary physical encoding into a symbolic representation.
+ *
+ * This function can cope with arbitrary input data; output blocks will be
+ * flagged as an error block if the encoding is invalid.
+ *
+ * @param bsd The block size information.
+ * @param pcb The binary encoded data.
+ * @param[out] scb The output symbolic representation.
+ */
+void physical_to_symbolic(
+ const block_size_descriptor& bsd,
+ const physical_compressed_block& pcb,
+ symbolic_compressed_block& scb);
+
+/* ============================================================================
+Platform-specific functions.
+============================================================================ */
+/**
+ * @brief Run-time detection if the host CPU supports the POPCNT extension.
+ *
+ * @return @c true if supported, @c false if not.
+ */
+bool cpu_supports_popcnt();
+
+/**
+ * @brief Run-time detection if the host CPU supports F16C extension.
+ *
+ * @return @c true if supported, @c false if not.
+ */
+bool cpu_supports_f16c();
+
+/**
+ * @brief Run-time detection if the host CPU supports SSE 4.1 extension.
+ *
+ * @return @c true if supported, @c false if not.
+ */
+bool cpu_supports_sse41();
+
+/**
+ * @brief Run-time detection if the host CPU supports AVX 2 extension.
+ *
+ * @return @c true if supported, @c false if not.
+ */
+bool cpu_supports_avx2();
+
+/**
+ * @brief Allocate an aligned memory buffer.
+ *
+ * Allocated memory must be freed by aligned_free;
+ *
+ * @param size The desired buffer size.
+ * @param align The desired buffer alignment; must be 2^N.
+ *
+ * @return The memory buffer pointer or nullptr on allocation failure.
+ */
+template<typename T>
+T* aligned_malloc(size_t size, size_t align)
+{
+ void* ptr;
+ int error = 0;
+
+#if defined(_WIN32)
+ ptr = _aligned_malloc(size, align);
+#else
+ error = posix_memalign(&ptr, align, size);
+#endif
+
+ if (error || (!ptr))
+ {
+ return nullptr;
+ }
+
+ return static_cast<T*>(ptr);
+}
+
+/**
+ * @brief Free an aligned memory buffer.
+ *
+ * @param ptr The buffer to free.
+ */
+template<typename T>
+void aligned_free(T* ptr)
+{
+#if defined(_WIN32)
+ _aligned_free(reinterpret_cast<void*>(ptr));
+#else
+ free(reinterpret_cast<void*>(ptr));
+#endif
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_internal_entry.h b/thirdparty/astcenc/astcenc_internal_entry.h
new file mode 100644
index 0000000000..4e8794547a
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_internal_entry.h
@@ -0,0 +1,273 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions and data declarations for the outer context.
+ *
+ * The outer context includes thread-pool management, which is slower to
+ * compile due to increased use of C++ stdlib. The inner context used in the
+ * majority of the codec library does not include this.
+ */
+
+#ifndef ASTCENC_INTERNAL_ENTRY_INCLUDED
+#define ASTCENC_INTERNAL_ENTRY_INCLUDED
+
+#include <atomic>
+#include <condition_variable>
+#include <functional>
+#include <mutex>
+
+#include "astcenc_internal.h"
+
+/* ============================================================================
+ Parallel execution control
+============================================================================ */
+
+/**
+ * @brief A simple counter-based manager for parallel task execution.
+ *
+ * The task processing execution consists of:
+ *
+ * * A single-threaded init stage.
+ * * A multi-threaded processing stage.
+ * * A condition variable so threads can wait for processing completion.
+ *
+ * The init stage will be executed by the first thread to arrive in the critical section, there is
+ * no main thread in the thread pool.
+ *
+ * The processing stage uses dynamic dispatch to assign task tickets to threads on an on-demand
+ * basis. Threads may each therefore executed different numbers of tasks, depending on their
+ * processing complexity. The task queue and the task tickets are just counters; the caller must map
+ * these integers to an actual processing partition in a specific problem domain.
+ *
+ * The exit wait condition is needed to ensure processing has finished before a worker thread can
+ * progress to the next stage of the pipeline. Specifically a worker may exit the processing stage
+ * because there are no new tasks to assign to it while other worker threads are still processing.
+ * Calling @c wait() will ensure that all other worker have finished before the thread can proceed.
+ *
+ * The basic usage model:
+ *
+ * // --------- From single-threaded code ---------
+ *
+ * // Reset the tracker state
+ * manager->reset()
+ *
+ * // --------- From multi-threaded code ---------
+ *
+ * // Run the stage init; only first thread actually runs the lambda
+ * manager->init(<lambda>)
+ *
+ * do
+ * {
+ * // Request a task assignment
+ * uint task_count;
+ * uint base_index = manager->get_tasks(<granule>, task_count);
+ *
+ * // Process any tasks we were given (task_count <= granule size)
+ * if (task_count)
+ * {
+ * // Run the user task processing code for N tasks here
+ * ...
+ *
+ * // Flag these tasks as complete
+ * manager->complete_tasks(task_count);
+ * }
+ * } while (task_count);
+ *
+ * // Wait for all threads to complete tasks before progressing
+ * manager->wait()
+ *
+ * // Run the stage term; only first thread actually runs the lambda
+ * manager->term(<lambda>)
+ */
+class ParallelManager
+{
+private:
+ /** @brief Lock used for critical section and condition synchronization. */
+ std::mutex m_lock;
+
+ /** @brief True if the stage init() step has been executed. */
+ bool m_init_done;
+
+ /** @brief True if the stage term() step has been executed. */
+ bool m_term_done;
+
+ /** @brief Condition variable for tracking stage processing completion. */
+ std::condition_variable m_complete;
+
+ /** @brief Number of tasks started, but not necessarily finished. */
+ std::atomic<unsigned int> m_start_count;
+
+ /** @brief Number of tasks finished. */
+ unsigned int m_done_count;
+
+ /** @brief Number of tasks that need to be processed. */
+ unsigned int m_task_count;
+
+public:
+ /** @brief Create a new ParallelManager. */
+ ParallelManager()
+ {
+ reset();
+ }
+
+ /**
+ * @brief Reset the tracker for a new processing batch.
+ *
+ * This must be called from single-threaded code before starting the multi-threaded processing
+ * operations.
+ */
+ void reset()
+ {
+ m_init_done = false;
+ m_term_done = false;
+ m_start_count = 0;
+ m_done_count = 0;
+ m_task_count = 0;
+ }
+
+ /**
+ * @brief Trigger the pipeline stage init step.
+ *
+ * This can be called from multi-threaded code. The first thread to hit this will process the
+ * initialization. Other threads will block and wait for it to complete.
+ *
+ * @param init_func Callable which executes the stage initialization. It must return the
+ * total number of tasks in the stage.
+ */
+ void init(std::function<unsigned int(void)> init_func)
+ {
+ std::lock_guard<std::mutex> lck(m_lock);
+ if (!m_init_done)
+ {
+ m_task_count = init_func();
+ m_init_done = true;
+ }
+ }
+
+ /**
+ * @brief Trigger the pipeline stage init step.
+ *
+ * This can be called from multi-threaded code. The first thread to hit this will process the
+ * initialization. Other threads will block and wait for it to complete.
+ *
+ * @param task_count Total number of tasks needing processing.
+ */
+ void init(unsigned int task_count)
+ {
+ std::lock_guard<std::mutex> lck(m_lock);
+ if (!m_init_done)
+ {
+ m_task_count = task_count;
+ m_init_done = true;
+ }
+ }
+
+ /**
+ * @brief Request a task assignment.
+ *
+ * Assign up to @c granule tasks to the caller for processing.
+ *
+ * @param granule Maximum number of tasks that can be assigned.
+ * @param[out] count Actual number of tasks assigned, or zero if no tasks were assigned.
+ *
+ * @return Task index of the first assigned task; assigned tasks increment from this.
+ */
+ unsigned int get_task_assignment(unsigned int granule, unsigned int& count)
+ {
+ unsigned int base = m_start_count.fetch_add(granule, std::memory_order_relaxed);
+ if (base >= m_task_count)
+ {
+ count = 0;
+ return 0;
+ }
+
+ count = astc::min(m_task_count - base, granule);
+ return base;
+ }
+
+ /**
+ * @brief Complete a task assignment.
+ *
+ * Mark @c count tasks as complete. This will notify all threads blocked on @c wait() if this
+ * completes the processing of the stage.
+ *
+ * @param count The number of completed tasks.
+ */
+ void complete_task_assignment(unsigned int count)
+ {
+ // Note: m_done_count cannot use an atomic without the mutex; this has a race between the
+ // update here and the wait() for other threads
+ std::unique_lock<std::mutex> lck(m_lock);
+ this->m_done_count += count;
+ if (m_done_count == m_task_count)
+ {
+ lck.unlock();
+ m_complete.notify_all();
+ }
+ }
+
+ /**
+ * @brief Wait for stage processing to complete.
+ */
+ void wait()
+ {
+ std::unique_lock<std::mutex> lck(m_lock);
+ m_complete.wait(lck, [this]{ return m_done_count == m_task_count; });
+ }
+
+ /**
+ * @brief Trigger the pipeline stage term step.
+ *
+ * This can be called from multi-threaded code. The first thread to hit this will process the
+ * work pool termination. Caller must have called @c wait() prior to calling this function to
+ * ensure that processing is complete.
+ *
+ * @param term_func Callable which executes the stage termination.
+ */
+ void term(std::function<void(void)> term_func)
+ {
+ std::lock_guard<std::mutex> lck(m_lock);
+ if (!m_term_done)
+ {
+ term_func();
+ m_term_done = true;
+ }
+ }
+};
+
+/**
+ * @brief The astcenc compression context.
+ */
+struct astcenc_context
+{
+ /** @brief The context internal state. */
+ astcenc_contexti context;
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+ /** @brief The parallel manager for averages computation. */
+ ParallelManager manage_avg;
+
+ /** @brief The parallel manager for compression. */
+ ParallelManager manage_compress;
+#endif
+
+ /** @brief The parallel manager for decompression. */
+ ParallelManager manage_decompress;
+};
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_mathlib.cpp b/thirdparty/astcenc/astcenc_mathlib.cpp
new file mode 100644
index 0000000000..f276ac7e3d
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_mathlib.cpp
@@ -0,0 +1,48 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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 "astcenc_mathlib.h"
+
+/**
+ * @brief 64-bit rotate left.
+ *
+ * @param val The value to rotate.
+ * @param count The rotation, in bits.
+ */
+static inline uint64_t rotl(uint64_t val, int count)
+{
+ return (val << count) | (val >> (64 - count));
+}
+
+/* See header for documentation. */
+void astc::rand_init(uint64_t state[2])
+{
+ state[0] = 0xfaf9e171cea1ec6bULL;
+ state[1] = 0xf1b318cc06af5d71ULL;
+}
+
+/* See header for documentation. */
+uint64_t astc::rand(uint64_t state[2])
+{
+ uint64_t s0 = state[0];
+ uint64_t s1 = state[1];
+ uint64_t res = s0 + s1;
+ s1 ^= s0;
+ state[0] = rotl(s0, 24) ^ s1 ^ (s1 << 16);
+ state[1] = rotl(s1, 37);
+ return res;
+}
diff --git a/thirdparty/astcenc/astcenc_mathlib.h b/thirdparty/astcenc/astcenc_mathlib.h
new file mode 100644
index 0000000000..0540c4fedd
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_mathlib.h
@@ -0,0 +1,476 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/*
+ * This module implements a variety of mathematical data types and library
+ * functions used by the codec.
+ */
+
+#ifndef ASTC_MATHLIB_H_INCLUDED
+#define ASTC_MATHLIB_H_INCLUDED
+
+#include <cassert>
+#include <cstdint>
+#include <cmath>
+
+#ifndef ASTCENC_POPCNT
+ #if defined(__POPCNT__)
+ #define ASTCENC_POPCNT 1
+ #else
+ #define ASTCENC_POPCNT 0
+ #endif
+#endif
+
+#ifndef ASTCENC_F16C
+ #if defined(__F16C__)
+ #define ASTCENC_F16C 1
+ #else
+ #define ASTCENC_F16C 0
+ #endif
+#endif
+
+#ifndef ASTCENC_SSE
+ #if defined(__SSE4_2__)
+ #define ASTCENC_SSE 42
+ #elif defined(__SSE4_1__)
+ #define ASTCENC_SSE 41
+ #elif defined(__SSE2__)
+ #define ASTCENC_SSE 20
+ #else
+ #define ASTCENC_SSE 0
+ #endif
+#endif
+
+#ifndef ASTCENC_AVX
+ #if defined(__AVX2__)
+ #define ASTCENC_AVX 2
+ #elif defined(__AVX__)
+ #define ASTCENC_AVX 1
+ #else
+ #define ASTCENC_AVX 0
+ #endif
+#endif
+
+#ifndef ASTCENC_NEON
+ #if defined(__aarch64__)
+ #define ASTCENC_NEON 1
+ #else
+ #define ASTCENC_NEON 0
+ #endif
+#endif
+
+#if ASTCENC_AVX
+ #define ASTCENC_VECALIGN 32
+#else
+ #define ASTCENC_VECALIGN 16
+#endif
+
+#if ASTCENC_SSE != 0 || ASTCENC_AVX != 0 || ASTCENC_POPCNT != 0
+ #include <immintrin.h>
+#endif
+
+/* ============================================================================
+ Fast math library; note that many of the higher-order functions in this set
+ use approximations which are less accurate, but faster, than <cmath> standard
+ library equivalents.
+
+ Note: Many of these are not necessarily faster than simple C versions when
+ used on a single scalar value, but are included for testing purposes as most
+ have an option based on SSE intrinsics and therefore provide an obvious route
+ to future vectorization.
+============================================================================ */
+
+// Union for manipulation of float bit patterns
+typedef union
+{
+ uint32_t u;
+ int32_t s;
+ float f;
+} if32;
+
+// These are namespaced to avoid colliding with C standard library functions.
+namespace astc
+{
+
+static const float PI = 3.14159265358979323846f;
+static const float PI_OVER_TWO = 1.57079632679489661923f;
+
+/**
+ * @brief SP float absolute value.
+ *
+ * @param v The value to make absolute.
+ *
+ * @return The absolute value.
+ */
+static inline float fabs(float v)
+{
+ return std::fabs(v);
+}
+
+/**
+ * @brief Test if a float value is a nan.
+ *
+ * @param v The value test.
+ *
+ * @return Zero is not a NaN, non-zero otherwise.
+ */
+static inline bool isnan(float v)
+{
+ return v != v;
+}
+
+/**
+ * @brief Return the minimum of two values.
+ *
+ * For floats, NaNs are turned into @c q.
+ *
+ * @param p The first value to compare.
+ * @param q The second value to compare.
+ *
+ * @return The smallest value.
+ */
+template<typename T>
+static inline T min(T p, T q)
+{
+ return p < q ? p : q;
+}
+
+/**
+ * @brief Return the minimum of three values.
+ *
+ * For floats, NaNs are turned into @c r.
+ *
+ * @param p The first value to compare.
+ * @param q The second value to compare.
+ * @param r The third value to compare.
+ *
+ * @return The smallest value.
+ */
+template<typename T>
+static inline T min(T p, T q, T r)
+{
+ return min(min(p, q), r);
+}
+
+/**
+ * @brief Return the minimum of four values.
+ *
+ * For floats, NaNs are turned into @c s.
+ *
+ * @param p The first value to compare.
+ * @param q The second value to compare.
+ * @param r The third value to compare.
+ * @param s The fourth value to compare.
+ *
+ * @return The smallest value.
+ */
+template<typename T>
+static inline T min(T p, T q, T r, T s)
+{
+ return min(min(p, q), min(r, s));
+}
+
+/**
+ * @brief Return the maximum of two values.
+ *
+ * For floats, NaNs are turned into @c q.
+ *
+ * @param p The first value to compare.
+ * @param q The second value to compare.
+ *
+ * @return The largest value.
+ */
+template<typename T>
+static inline T max(T p, T q)
+{
+ return p > q ? p : q;
+}
+
+/**
+ * @brief Return the maximum of three values.
+ *
+ * For floats, NaNs are turned into @c r.
+ *
+ * @param p The first value to compare.
+ * @param q The second value to compare.
+ * @param r The third value to compare.
+ *
+ * @return The largest value.
+ */
+template<typename T>
+static inline T max(T p, T q, T r)
+{
+ return max(max(p, q), r);
+}
+
+/**
+ * @brief Return the maximum of four values.
+ *
+ * For floats, NaNs are turned into @c s.
+ *
+ * @param p The first value to compare.
+ * @param q The second value to compare.
+ * @param r The third value to compare.
+ * @param s The fourth value to compare.
+ *
+ * @return The largest value.
+ */
+template<typename T>
+static inline T max(T p, T q, T r, T s)
+{
+ return max(max(p, q), max(r, s));
+}
+
+/**
+ * @brief Clamp a value value between @c mn and @c mx.
+ *
+ * For floats, NaNs are turned into @c mn.
+ *
+ * @param v The value to clamp.
+ * @param mn The min value (inclusive).
+ * @param mx The max value (inclusive).
+ *
+ * @return The clamped value.
+ */
+template<typename T>
+inline T clamp(T v, T mn, T mx)
+{
+ // Do not reorder; correct NaN handling relies on the fact that comparison
+ // with NaN returns false and will fall-though to the "min" value.
+ if (v > mx) return mx;
+ if (v > mn) return v;
+ return mn;
+}
+
+/**
+ * @brief Clamp a float value between 0.0f and 1.0f.
+ *
+ * NaNs are turned into 0.0f.
+ *
+ * @param v The value to clamp.
+ *
+ * @return The clamped value.
+ */
+static inline float clamp1f(float v)
+{
+ return astc::clamp(v, 0.0f, 1.0f);
+}
+
+/**
+ * @brief Clamp a float value between 0.0f and 255.0f.
+ *
+ * NaNs are turned into 0.0f.
+ *
+ * @param v The value to clamp.
+ *
+ * @return The clamped value.
+ */
+static inline float clamp255f(float v)
+{
+ return astc::clamp(v, 0.0f, 255.0f);
+}
+
+/**
+ * @brief SP float round-down.
+ *
+ * @param v The value to round.
+ *
+ * @return The rounded value.
+ */
+static inline float flt_rd(float v)
+{
+ return std::floor(v);
+}
+
+/**
+ * @brief SP float round-to-nearest and convert to integer.
+ *
+ * @param v The value to round.
+ *
+ * @return The rounded value.
+ */
+static inline int flt2int_rtn(float v)
+{
+
+ return static_cast<int>(v + 0.5f);
+}
+
+/**
+ * @brief SP float round down and convert to integer.
+ *
+ * @param v The value to round.
+ *
+ * @return The rounded value.
+ */
+static inline int flt2int_rd(float v)
+{
+ return static_cast<int>(v);
+}
+
+/**
+ * @brief SP float bit-interpreted as an integer.
+ *
+ * @param v The value to bitcast.
+ *
+ * @return The converted value.
+ */
+static inline int float_as_int(float v)
+{
+ union { int a; float b; } u;
+ u.b = v;
+ return u.a;
+}
+
+/**
+ * @brief Integer bit-interpreted as an SP float.
+ *
+ * @param v The value to bitcast.
+ *
+ * @return The converted value.
+ */
+static inline float int_as_float(int v)
+{
+ union { int a; float b; } u;
+ u.a = v;
+ return u.b;
+}
+
+/**
+ * @brief Fast approximation of 1.0 / sqrt(val).
+ *
+ * @param v The input value.
+ *
+ * @return The approximated result.
+ */
+static inline float rsqrt(float v)
+{
+ return 1.0f / std::sqrt(v);
+}
+
+/**
+ * @brief Fast approximation of sqrt(val).
+ *
+ * @param v The input value.
+ *
+ * @return The approximated result.
+ */
+static inline float sqrt(float v)
+{
+ return std::sqrt(v);
+}
+
+/**
+ * @brief Extract mantissa and exponent of a float value.
+ *
+ * @param v The input value.
+ * @param[out] expo The output exponent.
+ *
+ * @return The mantissa.
+ */
+static inline float frexp(float v, int* expo)
+{
+ if32 p;
+ p.f = v;
+ *expo = ((p.u >> 23) & 0xFF) - 126;
+ p.u = (p.u & 0x807fffff) | 0x3f000000;
+ return p.f;
+}
+
+/**
+ * @brief Initialize the seed structure for a random number generator.
+ *
+ * Important note: For the purposes of ASTC we want sets of random numbers to
+ * use the codec, but we want the same seed value across instances and threads
+ * to ensure that image output is stable across compressor runs and across
+ * platforms. Every PRNG created by this call will therefore return the same
+ * sequence of values ...
+ *
+ * @param state The state structure to initialize.
+ */
+void rand_init(uint64_t state[2]);
+
+/**
+ * @brief Return the next random number from the generator.
+ *
+ * This RNG is an implementation of the "xoroshoro-128+ 1.0" PRNG, based on the
+ * public-domain implementation given by David Blackman & Sebastiano Vigna at
+ * http://vigna.di.unimi.it/xorshift/xoroshiro128plus.c
+ *
+ * @param state The state structure to use/update.
+ */
+uint64_t rand(uint64_t state[2]);
+
+}
+
+/* ============================================================================
+ Softfloat library with fp32 and fp16 conversion functionality.
+============================================================================ */
+#if (ASTCENC_F16C == 0) && (ASTCENC_NEON == 0)
+ /* narrowing float->float conversions */
+ uint16_t float_to_sf16(float val);
+ float sf16_to_float(uint16_t val);
+#endif
+
+/*********************************
+ Vector library
+*********************************/
+#include "astcenc_vecmathlib.h"
+
+/*********************************
+ Declaration of line types
+*********************************/
+// parametric line, 2D: The line is given by line = a + b * t.
+
+struct line2
+{
+ vfloat4 a;
+ vfloat4 b;
+};
+
+// parametric line, 3D
+struct line3
+{
+ vfloat4 a;
+ vfloat4 b;
+};
+
+struct line4
+{
+ vfloat4 a;
+ vfloat4 b;
+};
+
+
+struct processed_line2
+{
+ vfloat4 amod;
+ vfloat4 bs;
+};
+
+struct processed_line3
+{
+ vfloat4 amod;
+ vfloat4 bs;
+};
+
+struct processed_line4
+{
+ vfloat4 amod;
+ vfloat4 bs;
+};
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_mathlib_softfloat.cpp b/thirdparty/astcenc/astcenc_mathlib_softfloat.cpp
new file mode 100644
index 0000000000..42db764549
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_mathlib_softfloat.cpp
@@ -0,0 +1,411 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Soft-float library for IEEE-754.
+ */
+#if (ASTCENC_F16C == 0) && (ASTCENC_NEON == 0)
+
+#include "astcenc_mathlib.h"
+
+/* sized soft-float types. These are mapped to the sized integer
+ types of C99, instead of C's floating-point types; this is because
+ the library needs to maintain exact, bit-level control on all
+ operations on these data types. */
+typedef uint16_t sf16;
+typedef uint32_t sf32;
+
+/******************************************
+ helper functions and their lookup tables
+ ******************************************/
+/* count leading zeros functions. Only used when the input is nonzero. */
+
+#if defined(__GNUC__) && (defined(__i386) || defined(__amd64))
+#elif defined(__arm__) && defined(__ARMCC_VERSION)
+#elif defined(__arm__) && defined(__GNUC__)
+#else
+ /* table used for the slow default versions. */
+ static const uint8_t clz_table[256] =
+ {
+ 8, 7, 6, 6, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+#endif
+
+/*
+ 32-bit count-leading-zeros function: use the Assembly instruction whenever possible. */
+static uint32_t clz32(uint32_t inp)
+{
+ #if defined(__GNUC__) && (defined(__i386) || defined(__amd64))
+ uint32_t bsr;
+ __asm__("bsrl %1, %0": "=r"(bsr):"r"(inp | 1));
+ return 31 - bsr;
+ #else
+ #if defined(__arm__) && defined(__ARMCC_VERSION)
+ return __clz(inp); /* armcc builtin */
+ #else
+ #if defined(__arm__) && defined(__GNUC__)
+ uint32_t lz;
+ __asm__("clz %0, %1": "=r"(lz):"r"(inp));
+ return lz;
+ #else
+ /* slow default version */
+ uint32_t summa = 24;
+ if (inp >= UINT32_C(0x10000))
+ {
+ inp >>= 16;
+ summa -= 16;
+ }
+ if (inp >= UINT32_C(0x100))
+ {
+ inp >>= 8;
+ summa -= 8;
+ }
+ return summa + clz_table[inp];
+ #endif
+ #endif
+ #endif
+}
+
+/* the five rounding modes that IEEE-754r defines */
+typedef enum
+{
+ SF_UP = 0, /* round towards positive infinity */
+ SF_DOWN = 1, /* round towards negative infinity */
+ SF_TOZERO = 2, /* round towards zero */
+ SF_NEARESTEVEN = 3, /* round toward nearest value; if mid-between, round to even value */
+ SF_NEARESTAWAY = 4 /* round toward nearest value; if mid-between, round away from zero */
+} roundmode;
+
+
+static uint32_t rtne_shift32(uint32_t inp, uint32_t shamt)
+{
+ uint32_t vl1 = UINT32_C(1) << shamt;
+ uint32_t inp2 = inp + (vl1 >> 1); /* added 0.5 ULP */
+ uint32_t msk = (inp | UINT32_C(1)) & vl1; /* nonzero if odd. '| 1' forces it to 1 if the shamt is 0. */
+ msk--; /* negative if even, nonnegative if odd. */
+ inp2 -= (msk >> 31); /* subtract epsilon before shift if even. */
+ inp2 >>= shamt;
+ return inp2;
+}
+
+static uint32_t rtna_shift32(uint32_t inp, uint32_t shamt)
+{
+ uint32_t vl1 = (UINT32_C(1) << shamt) >> 1;
+ inp += vl1;
+ inp >>= shamt;
+ return inp;
+}
+
+static uint32_t rtup_shift32(uint32_t inp, uint32_t shamt)
+{
+ uint32_t vl1 = UINT32_C(1) << shamt;
+ inp += vl1;
+ inp--;
+ inp >>= shamt;
+ return inp;
+}
+
+/* convert from FP16 to FP32. */
+static sf32 sf16_to_sf32(sf16 inp)
+{
+ uint32_t inpx = inp;
+
+ /*
+ This table contains, for every FP16 sign/exponent value combination,
+ the difference between the input FP16 value and the value obtained
+ by shifting the correct FP32 result right by 13 bits.
+ This table allows us to handle every case except denormals and NaN
+ with just 1 table lookup, 2 shifts and 1 add.
+ */
+
+ #define WITH_MSB(a) (UINT32_C(a) | (1u << 31))
+ static const uint32_t tbl[64] =
+ {
+ WITH_MSB(0x00000), 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000,
+ 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000,
+ 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000,
+ 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, 0x1C000, WITH_MSB(0x38000),
+ WITH_MSB(0x38000), 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000,
+ 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000,
+ 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000,
+ 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, 0x54000, WITH_MSB(0x70000)
+ };
+
+ uint32_t res = tbl[inpx >> 10];
+ res += inpx;
+
+ /* Normal cases: MSB of 'res' not set. */
+ if ((res & WITH_MSB(0)) == 0)
+ {
+ return res << 13;
+ }
+
+ /* Infinity and Zero: 10 LSB of 'res' not set. */
+ if ((res & 0x3FF) == 0)
+ {
+ return res << 13;
+ }
+
+ /* NaN: the exponent field of 'inp' is non-zero. */
+ if ((inpx & 0x7C00) != 0)
+ {
+ /* All NaNs are quietened. */
+ return (res << 13) | 0x400000;
+ }
+
+ /* Denormal cases */
+ uint32_t sign = (inpx & 0x8000) << 16;
+ uint32_t mskval = inpx & 0x7FFF;
+ uint32_t leadingzeroes = clz32(mskval);
+ mskval <<= leadingzeroes;
+ return (mskval >> 8) + ((0x85 - leadingzeroes) << 23) + sign;
+}
+
+/* Conversion routine that converts from FP32 to FP16. It supports denormals and all rounding modes. If a NaN is given as input, it is quietened. */
+static sf16 sf32_to_sf16(sf32 inp, roundmode rmode)
+{
+ /* for each possible sign/exponent combination, store a case index. This gives a 512-byte table */
+ static const uint8_t tab[512] {
+ 0, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30,
+ 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 30, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 50,
+
+ 5, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25, 25,
+ 25, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35,
+ 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 35, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45,
+ 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 45, 55,
+ };
+
+ /* many of the cases below use a case-dependent magic constant. So we look up a magic constant before actually performing the switch. This table allows us to group cases, thereby minimizing code
+ size. */
+ static const uint32_t tabx[60] {
+ UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0x8000), UINT32_C(0x80000000), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000),
+ UINT32_C(1), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0x8000), UINT32_C(0x8001), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000),
+ UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000), UINT32_C(0x8000),
+ UINT32_C(0xC8001FFF), UINT32_C(0xC8000000), UINT32_C(0xC8000000), UINT32_C(0xC8000FFF), UINT32_C(0xC8001000),
+ UINT32_C(0x58000000), UINT32_C(0x38001FFF), UINT32_C(0x58000000), UINT32_C(0x58000FFF), UINT32_C(0x58001000),
+ UINT32_C(0x7C00), UINT32_C(0x7BFF), UINT32_C(0x7BFF), UINT32_C(0x7C00), UINT32_C(0x7C00),
+ UINT32_C(0xFBFF), UINT32_C(0xFC00), UINT32_C(0xFBFF), UINT32_C(0xFC00), UINT32_C(0xFC00),
+ UINT32_C(0x90000000), UINT32_C(0x90000000), UINT32_C(0x90000000), UINT32_C(0x90000000), UINT32_C(0x90000000),
+ UINT32_C(0x20000000), UINT32_C(0x20000000), UINT32_C(0x20000000), UINT32_C(0x20000000), UINT32_C(0x20000000)
+ };
+
+ uint32_t p;
+ uint32_t idx = rmode + tab[inp >> 23];
+ uint32_t vlx = tabx[idx];
+ switch (idx)
+ {
+ /*
+ Positive number which may be Infinity or NaN.
+ We need to check whether it is NaN; if it is, quieten it by setting the top bit of the mantissa.
+ (If we don't do this quieting, then a NaN that is distinguished only by having
+ its low-order bits set, would be turned into an INF. */
+ case 50:
+ case 51:
+ case 52:
+ case 53:
+ case 54:
+ case 55:
+ case 56:
+ case 57:
+ case 58:
+ case 59:
+ /*
+ the input value is 0x7F800000 or 0xFF800000 if it is INF.
+ By subtracting 1, we get 7F7FFFFF or FF7FFFFF, that is, bit 23 becomes zero.
+ For NaNs, however, this operation will keep bit 23 with the value 1.
+ We can then extract bit 23, and logical-OR bit 9 of the result with this
+ bit in order to quieten the NaN (a Quiet NaN is a NaN where the top bit
+ of the mantissa is set.)
+ */
+ p = (inp - 1) & UINT32_C(0x800000); /* zero if INF, nonzero if NaN. */
+ return static_cast<sf16>(((inp + vlx) >> 13) | (p >> 14));
+ /*
+ positive, exponent = 0, round-mode == UP; need to check whether number actually is 0.
+ If it is, then return 0, else return 1 (the smallest representable nonzero number)
+ */
+ case 0:
+ /*
+ -inp will set the MSB if the input number is nonzero.
+ Thus (-inp) >> 31 will turn into 0 if the input number is 0 and 1 otherwise.
+ */
+ return static_cast<sf16>(static_cast<uint32_t>((-static_cast<int32_t>(inp))) >> 31);
+
+ /*
+ negative, exponent = , round-mode == DOWN, need to check whether number is
+ actually 0. If it is, return 0x8000 ( float -0.0 )
+ Else return the smallest negative number ( 0x8001 ) */
+ case 6:
+ /*
+ in this case 'vlx' is 0x80000000. By subtracting the input value from it,
+ we obtain a value that is 0 if the input value is in fact zero and has
+ the MSB set if it isn't. We then right-shift the value by 31 places to
+ get a value that is 0 if the input is -0.0 and 1 otherwise.
+ */
+ return static_cast<sf16>(((vlx - inp) >> 31) + UINT32_C(0x8000));
+
+ /*
+ for all other cases involving underflow/overflow, we don't need to
+ do actual tests; we just return 'vlx'.
+ */
+ case 1:
+ case 2:
+ case 3:
+ case 4:
+ case 5:
+ case 7:
+ case 8:
+ case 9:
+ case 10:
+ case 11:
+ case 12:
+ case 13:
+ case 14:
+ case 15:
+ case 16:
+ case 17:
+ case 18:
+ case 19:
+ case 40:
+ case 41:
+ case 42:
+ case 43:
+ case 44:
+ case 45:
+ case 46:
+ case 47:
+ case 48:
+ case 49:
+ return static_cast<sf16>(vlx);
+
+ /*
+ for normal numbers, 'vlx' is the difference between the FP32 value of a number and the
+ FP16 representation of the same number left-shifted by 13 places. In addition, a rounding constant is
+ baked into 'vlx': for rounding-away-from zero, the constant is 2^13 - 1, causing roundoff away
+ from zero. for round-to-nearest away, the constant is 2^12, causing roundoff away from zero.
+ for round-to-nearest-even, the constant is 2^12 - 1. This causes correct round-to-nearest-even
+ except for odd input numbers. For odd input numbers, we need to add 1 to the constant. */
+
+ /* normal number, all rounding modes except round-to-nearest-even: */
+ case 30:
+ case 31:
+ case 32:
+ case 34:
+ case 35:
+ case 36:
+ case 37:
+ case 39:
+ return static_cast<sf16>((inp + vlx) >> 13);
+
+ /* normal number, round-to-nearest-even. */
+ case 33:
+ case 38:
+ p = inp + vlx;
+ p += (inp >> 13) & 1;
+ return static_cast<sf16>(p >> 13);
+
+ /*
+ the various denormal cases. These are not expected to be common, so their performance is a bit
+ less important. For each of these cases, we need to extract an exponent and a mantissa
+ (including the implicit '1'!), and then right-shift the mantissa by a shift-amount that
+ depends on the exponent. The shift must apply the correct rounding mode. 'vlx' is used to supply the
+ sign of the resulting denormal number.
+ */
+ case 21:
+ case 22:
+ case 25:
+ case 27:
+ /* denormal, round towards zero. */
+ p = 126 - ((inp >> 23) & 0xFF);
+ return static_cast<sf16>((((inp & UINT32_C(0x7FFFFF)) + UINT32_C(0x800000)) >> p) | vlx);
+ case 20:
+ case 26:
+ /* denormal, round away from zero. */
+ p = 126 - ((inp >> 23) & 0xFF);
+ return static_cast<sf16>(rtup_shift32((inp & UINT32_C(0x7FFFFF)) + UINT32_C(0x800000), p) | vlx);
+ case 24:
+ case 29:
+ /* denormal, round to nearest-away */
+ p = 126 - ((inp >> 23) & 0xFF);
+ return static_cast<sf16>(rtna_shift32((inp & UINT32_C(0x7FFFFF)) + UINT32_C(0x800000), p) | vlx);
+ case 23:
+ case 28:
+ /* denormal, round to nearest-even. */
+ p = 126 - ((inp >> 23) & 0xFF);
+ return static_cast<sf16>(rtne_shift32((inp & UINT32_C(0x7FFFFF)) + UINT32_C(0x800000), p) | vlx);
+ }
+
+ return 0;
+}
+
+/* convert from soft-float to native-float */
+float sf16_to_float(uint16_t p)
+{
+ if32 i;
+ i.u = sf16_to_sf32(p);
+ return i.f;
+}
+
+/* convert from native-float to soft-float */
+uint16_t float_to_sf16(float p)
+{
+ if32 i;
+ i.f = p;
+ return sf32_to_sf16(i.u, SF_NEARESTEVEN);
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_partition_tables.cpp b/thirdparty/astcenc/astcenc_partition_tables.cpp
new file mode 100644
index 0000000000..cad42384d7
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_partition_tables.cpp
@@ -0,0 +1,481 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2023 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for generating partition tables on demand.
+ */
+
+#include "astcenc_internal.h"
+
+/** @brief The number of 64-bit words needed to represent a canonical partition bit pattern. */
+#define BIT_PATTERN_WORDS (((ASTCENC_BLOCK_MAX_TEXELS * 2) + 63) / 64)
+
+/**
+ * @brief Generate a canonical representation of a partition pattern.
+ *
+ * The returned value stores two bits per texel, for up to 6x6x6 texels, where the two bits store
+ * the remapped texel index. Remapping ensures that we only match on the partition pattern,
+ * independent of the partition order generated by the hash.
+ *
+ * @param texel_count The number of texels in the block.
+ * @param partition_of_texel The partition assignments, in hash order.
+ * @param[out] bit_pattern The output bit pattern representation.
+ */
+static void generate_canonical_partitioning(
+ unsigned int texel_count,
+ const uint8_t* partition_of_texel,
+ uint64_t bit_pattern[BIT_PATTERN_WORDS]
+) {
+ // Clear the pattern
+ for (unsigned int i = 0; i < BIT_PATTERN_WORDS; i++)
+ {
+ bit_pattern[i] = 0;
+ }
+
+ // Store a mapping to reorder the raw partitions so that the partitions are ordered such
+ // that the lowest texel index in partition N is smaller than the lowest texel index in
+ // partition N + 1.
+ int mapped_index[BLOCK_MAX_PARTITIONS];
+ int map_weight_count = 0;
+
+ for (unsigned int i = 0; i < BLOCK_MAX_PARTITIONS; i++)
+ {
+ mapped_index[i] = -1;
+ }
+
+ for (unsigned int i = 0; i < texel_count; i++)
+ {
+ int index = partition_of_texel[i];
+ if (mapped_index[index] < 0)
+ {
+ mapped_index[index] = map_weight_count++;
+ }
+
+ uint64_t xlat_index = mapped_index[index];
+ bit_pattern[i >> 5] |= xlat_index << (2 * (i & 0x1F));
+ }
+}
+
+/**
+ * @brief Compare two canonical patterns to see if they are the same.
+ *
+ * @param part1 The first canonical bit pattern to check.
+ * @param part2 The second canonical bit pattern to check.
+ *
+ * @return @c true if the patterns are the same, @c false otherwise.
+ */
+static bool compare_canonical_partitionings(
+ const uint64_t part1[BIT_PATTERN_WORDS],
+ const uint64_t part2[BIT_PATTERN_WORDS]
+) {
+ return (part1[0] == part2[0])
+#if BIT_PATTERN_WORDS > 1
+ && (part1[1] == part2[1])
+#endif
+#if BIT_PATTERN_WORDS > 2
+ && (part1[2] == part2[2])
+#endif
+#if BIT_PATTERN_WORDS > 3
+ && (part1[3] == part2[3])
+#endif
+#if BIT_PATTERN_WORDS > 4
+ && (part1[4] == part2[4])
+#endif
+#if BIT_PATTERN_WORDS > 5
+ && (part1[5] == part2[5])
+#endif
+#if BIT_PATTERN_WORDS > 6
+ && (part1[6] == part2[6])
+#endif
+ ;
+}
+
+/**
+ * @brief Hash function used for procedural partition assignment.
+ *
+ * @param inp The hash seed.
+ *
+ * @return The hashed value.
+ */
+static uint32_t hash52(
+ uint32_t inp
+) {
+ inp ^= inp >> 15;
+
+ // (2^4 + 1) * (2^7 + 1) * (2^17 - 1)
+ inp *= 0xEEDE0891;
+ inp ^= inp >> 5;
+ inp += inp << 16;
+ inp ^= inp >> 7;
+ inp ^= inp >> 3;
+ inp ^= inp << 6;
+ inp ^= inp >> 17;
+ return inp;
+}
+
+/**
+ * @brief Select texel assignment for a single coordinate.
+ *
+ * @param seed The seed - the partition index from the block.
+ * @param x The texel X coordinate in the block.
+ * @param y The texel Y coordinate in the block.
+ * @param z The texel Z coordinate in the block.
+ * @param partition_count The total partition count of this encoding.
+ * @param small_block @c true if the block has fewer than 32 texels.
+ *
+ * @return The assigned partition index for this texel.
+ */
+static uint8_t select_partition(
+ int seed,
+ int x,
+ int y,
+ int z,
+ int partition_count,
+ bool small_block
+) {
+ // For small blocks bias the coordinates to get better distribution
+ if (small_block)
+ {
+ x <<= 1;
+ y <<= 1;
+ z <<= 1;
+ }
+
+ seed += (partition_count - 1) * 1024;
+
+ uint32_t rnum = hash52(seed);
+
+ uint8_t seed1 = rnum & 0xF;
+ uint8_t seed2 = (rnum >> 4) & 0xF;
+ uint8_t seed3 = (rnum >> 8) & 0xF;
+ uint8_t seed4 = (rnum >> 12) & 0xF;
+ uint8_t seed5 = (rnum >> 16) & 0xF;
+ uint8_t seed6 = (rnum >> 20) & 0xF;
+ uint8_t seed7 = (rnum >> 24) & 0xF;
+ uint8_t seed8 = (rnum >> 28) & 0xF;
+ uint8_t seed9 = (rnum >> 18) & 0xF;
+ uint8_t seed10 = (rnum >> 22) & 0xF;
+ uint8_t seed11 = (rnum >> 26) & 0xF;
+ uint8_t seed12 = ((rnum >> 30) | (rnum << 2)) & 0xF;
+
+ // Squaring all the seeds in order to bias their distribution towards lower values.
+ seed1 *= seed1;
+ seed2 *= seed2;
+ seed3 *= seed3;
+ seed4 *= seed4;
+ seed5 *= seed5;
+ seed6 *= seed6;
+ seed7 *= seed7;
+ seed8 *= seed8;
+ seed9 *= seed9;
+ seed10 *= seed10;
+ seed11 *= seed11;
+ seed12 *= seed12;
+
+ int sh1, sh2;
+ if (seed & 1)
+ {
+ sh1 = (seed & 2 ? 4 : 5);
+ sh2 = (partition_count == 3 ? 6 : 5);
+ }
+ else
+ {
+ sh1 = (partition_count == 3 ? 6 : 5);
+ sh2 = (seed & 2 ? 4 : 5);
+ }
+
+ int sh3 = (seed & 0x10) ? sh1 : sh2;
+
+ seed1 >>= sh1;
+ seed2 >>= sh2;
+ seed3 >>= sh1;
+ seed4 >>= sh2;
+ seed5 >>= sh1;
+ seed6 >>= sh2;
+ seed7 >>= sh1;
+ seed8 >>= sh2;
+
+ seed9 >>= sh3;
+ seed10 >>= sh3;
+ seed11 >>= sh3;
+ seed12 >>= sh3;
+
+ int a = seed1 * x + seed2 * y + seed11 * z + (rnum >> 14);
+ int b = seed3 * x + seed4 * y + seed12 * z + (rnum >> 10);
+ int c = seed5 * x + seed6 * y + seed9 * z + (rnum >> 6);
+ int d = seed7 * x + seed8 * y + seed10 * z + (rnum >> 2);
+
+ // Apply the saw
+ a &= 0x3F;
+ b &= 0x3F;
+ c &= 0x3F;
+ d &= 0x3F;
+
+ // Remove some of the components if we are to output < 4 partitions.
+ if (partition_count <= 3)
+ {
+ d = 0;
+ }
+
+ if (partition_count <= 2)
+ {
+ c = 0;
+ }
+
+ if (partition_count <= 1)
+ {
+ b = 0;
+ }
+
+ uint8_t partition;
+ if (a >= b && a >= c && a >= d)
+ {
+ partition = 0;
+ }
+ else if (b >= c && b >= d)
+ {
+ partition = 1;
+ }
+ else if (c >= d)
+ {
+ partition = 2;
+ }
+ else
+ {
+ partition = 3;
+ }
+
+ return partition;
+}
+
+/**
+ * @brief Generate a single partition info structure.
+ *
+ * @param[out] bsd The block size information.
+ * @param partition_count The partition count of this partitioning.
+ * @param partition_index The partition index / seed of this partitioning.
+ * @param partition_remap_index The remapped partition index of this partitioning.
+ * @param[out] pi The partition info structure to populate.
+ *
+ * @return True if this is a useful partition index, False if we can skip it.
+ */
+static bool generate_one_partition_info_entry(
+ block_size_descriptor& bsd,
+ unsigned int partition_count,
+ unsigned int partition_index,
+ unsigned int partition_remap_index,
+ partition_info& pi
+) {
+ int texels_per_block = bsd.texel_count;
+ bool small_block = texels_per_block < 32;
+
+ uint8_t *partition_of_texel = pi.partition_of_texel;
+
+ // Assign texels to partitions
+ int texel_idx = 0;
+ int counts[BLOCK_MAX_PARTITIONS] { 0 };
+ for (unsigned int z = 0; z < bsd.zdim; z++)
+ {
+ for (unsigned int y = 0; y < bsd.ydim; y++)
+ {
+ for (unsigned int x = 0; x < bsd.xdim; x++)
+ {
+ uint8_t part = select_partition(partition_index, x, y, z, partition_count, small_block);
+ pi.texels_of_partition[part][counts[part]++] = static_cast<uint8_t>(texel_idx++);
+ *partition_of_texel++ = part;
+ }
+ }
+ }
+
+ // Fill loop tail so we can overfetch later
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ int ptex_count = counts[i];
+ int ptex_count_simd = round_up_to_simd_multiple_vla(ptex_count);
+ for (int j = ptex_count; j < ptex_count_simd; j++)
+ {
+ pi.texels_of_partition[i][j] = pi.texels_of_partition[i][ptex_count - 1];
+ }
+ }
+
+ // Populate the actual procedural partition count
+ if (counts[0] == 0)
+ {
+ pi.partition_count = 0;
+ }
+ else if (counts[1] == 0)
+ {
+ pi.partition_count = 1;
+ }
+ else if (counts[2] == 0)
+ {
+ pi.partition_count = 2;
+ }
+ else if (counts[3] == 0)
+ {
+ pi.partition_count = 3;
+ }
+ else
+ {
+ pi.partition_count = 4;
+ }
+
+ // Populate the partition index
+ pi.partition_index = static_cast<uint16_t>(partition_index);
+
+ // Populate the coverage bitmaps for 2/3/4 partitions
+ uint64_t* bitmaps { nullptr };
+ if (partition_count == 2)
+ {
+ bitmaps = bsd.coverage_bitmaps_2[partition_remap_index];
+ }
+ else if (partition_count == 3)
+ {
+ bitmaps = bsd.coverage_bitmaps_3[partition_remap_index];
+ }
+ else if (partition_count == 4)
+ {
+ bitmaps = bsd.coverage_bitmaps_4[partition_remap_index];
+ }
+
+ for (unsigned int i = 0; i < BLOCK_MAX_PARTITIONS; i++)
+ {
+ pi.partition_texel_count[i] = static_cast<uint8_t>(counts[i]);
+ }
+
+ // Valid partitionings have texels in all of the requested partitions
+ bool valid = pi.partition_count == partition_count;
+
+ if (bitmaps)
+ {
+ // Populate the partition coverage bitmap
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ bitmaps[i] = 0ULL;
+ }
+
+ unsigned int texels_to_process = astc::min(bsd.texel_count, BLOCK_MAX_KMEANS_TEXELS);
+ for (unsigned int i = 0; i < texels_to_process; i++)
+ {
+ unsigned int idx = bsd.kmeans_texels[i];
+ bitmaps[pi.partition_of_texel[idx]] |= 1ULL << i;
+ }
+ }
+
+ return valid;
+}
+
+static void build_partition_table_for_one_partition_count(
+ block_size_descriptor& bsd,
+ bool can_omit_partitionings,
+ unsigned int partition_count_cutoff,
+ unsigned int partition_count,
+ partition_info* ptab,
+ uint64_t* canonical_patterns
+) {
+ unsigned int next_index = 0;
+ bsd.partitioning_count_selected[partition_count - 1] = 0;
+ bsd.partitioning_count_all[partition_count - 1] = 0;
+
+ // Skip tables larger than config max partition count if we can omit modes
+ if (can_omit_partitionings && (partition_count > partition_count_cutoff))
+ {
+ return;
+ }
+
+ // Iterate through twice
+ // - Pass 0: Keep selected partitionings
+ // - Pass 1: Keep non-selected partitionings (skip if in omit mode)
+ unsigned int max_iter = can_omit_partitionings ? 1 : 2;
+
+ // Tracker for things we built in the first iteration
+ uint8_t build[BLOCK_MAX_PARTITIONINGS] { 0 };
+ for (unsigned int x = 0; x < max_iter; x++)
+ {
+ for (unsigned int i = 0; i < BLOCK_MAX_PARTITIONINGS; i++)
+ {
+ // Don't include things we built in the first pass
+ if ((x == 1) && build[i])
+ {
+ continue;
+ }
+
+ bool keep_useful = generate_one_partition_info_entry(bsd, partition_count, i, next_index, ptab[next_index]);
+ if ((x == 0) && !keep_useful)
+ {
+ continue;
+ }
+
+ generate_canonical_partitioning(bsd.texel_count, ptab[next_index].partition_of_texel, canonical_patterns + next_index * BIT_PATTERN_WORDS);
+ bool keep_canonical = true;
+ for (unsigned int j = 0; j < next_index; j++)
+ {
+ bool match = compare_canonical_partitionings(canonical_patterns + next_index * BIT_PATTERN_WORDS, canonical_patterns + j * BIT_PATTERN_WORDS);
+ if (match)
+ {
+ keep_canonical = false;
+ break;
+ }
+ }
+
+ if (keep_useful && keep_canonical)
+ {
+ if (x == 0)
+ {
+ bsd.partitioning_packed_index[partition_count - 2][i] = static_cast<uint16_t>(next_index);
+ bsd.partitioning_count_selected[partition_count - 1]++;
+ bsd.partitioning_count_all[partition_count - 1]++;
+ build[i] = 1;
+ next_index++;
+ }
+ }
+ else
+ {
+ if (x == 1)
+ {
+ bsd.partitioning_packed_index[partition_count - 2][i] = static_cast<uint16_t>(next_index);
+ bsd.partitioning_count_all[partition_count - 1]++;
+ next_index++;
+ }
+ }
+ }
+ }
+}
+
+/* See header for documentation. */
+void init_partition_tables(
+ block_size_descriptor& bsd,
+ bool can_omit_partitionings,
+ unsigned int partition_count_cutoff
+) {
+ partition_info* par_tab2 = bsd.partitionings;
+ partition_info* par_tab3 = par_tab2 + BLOCK_MAX_PARTITIONINGS;
+ partition_info* par_tab4 = par_tab3 + BLOCK_MAX_PARTITIONINGS;
+ partition_info* par_tab1 = par_tab4 + BLOCK_MAX_PARTITIONINGS;
+
+ generate_one_partition_info_entry(bsd, 1, 0, 0, *par_tab1);
+ bsd.partitioning_count_selected[0] = 1;
+ bsd.partitioning_count_all[0] = 1;
+
+ uint64_t* canonical_patterns = new uint64_t[BLOCK_MAX_PARTITIONINGS * BIT_PATTERN_WORDS];
+
+ build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 2, par_tab2, canonical_patterns);
+ build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 3, par_tab3, canonical_patterns);
+ build_partition_table_for_one_partition_count(bsd, can_omit_partitionings, partition_count_cutoff, 4, par_tab4, canonical_patterns);
+
+ delete[] canonical_patterns;
+}
diff --git a/thirdparty/astcenc/astcenc_percentile_tables.cpp b/thirdparty/astcenc/astcenc_percentile_tables.cpp
new file mode 100644
index 0000000000..448ddcc968
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_percentile_tables.cpp
@@ -0,0 +1,1251 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Percentile data tables for different block encodings.
+ *
+ * To reduce binary size the tables are stored using a packed differential encoding.
+ */
+
+#include "astcenc_internal.h"
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+/**
+ * @brief Structure containing packed percentile metadata.
+ *
+ * Note that percentile tables do not exist for 3D textures, so no zdim is stored.
+ */
+struct packed_percentile_table
+{
+ /** The block X dimension. */
+ uint8_t xdim;
+
+ /** The block Y dimension. */
+ uint8_t ydim;
+
+ /** The number of packed items in the 1 and 2 plane data. */
+ uint16_t item_count[2];
+
+ /** The accumulator divisor for 1 and 2 plane data. */
+ uint16_t difscales[2];
+
+ /** The initial accumulator values for 1 and 2 plane data. */
+ uint16_t initial_percs[2];
+
+ /** The packed data for the 1 and 2 plane data. */
+ const uint16_t *items[2];
+};
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (4 * 4)
+static const uint16_t percentile_arr_4x4_0[61] {
+ 0x0242, 0x7243, 0x6A51, 0x6A52, 0x5A41, 0x4A53, 0x8851, 0x3842,
+ 0x3852, 0x3853, 0x3043, 0xFA33, 0x1BDF, 0x2022, 0x1032, 0x29CE,
+ 0x21DE, 0x2823, 0x0813, 0x0A13, 0x0A31, 0x0A23, 0x09CF, 0x0833,
+ 0x0A32, 0x01DF, 0x0BDD, 0x0BCF, 0x0221, 0x095F, 0x0A01, 0x0BDE,
+ 0x0BCD, 0x0A22, 0x09AF, 0x0B5F, 0x0B4D, 0x0BCE, 0x0BBF, 0x0A11,
+ 0x01BF, 0x0202, 0x0B5D, 0x1203, 0x034E, 0x0B8E, 0x035E, 0x0212,
+ 0x032E, 0x0B4F, 0x03AF, 0x03AD, 0x03BD, 0x0BBE, 0x03AE, 0x039F,
+ 0x039E, 0x033E, 0x033F, 0x038F, 0x032F
+};
+
+static const uint16_t percentile_arr_4x4_1[84] {
+ 0x0452, 0xFFAE, 0x2433, 0x1DDF, 0x17CD, 0x1E21, 0x1C43, 0x1442,
+ 0x3FBE, 0x1FDD, 0x0E31, 0x0F4F, 0x1423, 0x0FBD, 0x1451, 0x0E03,
+ 0x05CF, 0x0C32, 0x0DDE, 0x27AD, 0x274E, 0x0E02, 0x0F5E, 0x07AF,
+ 0x0F5F, 0x0DCE, 0x0C41, 0x0422, 0x0613, 0x0E12, 0x0611, 0x0F3F,
+ 0x0601, 0x0DBF, 0x05DD, 0x075D, 0x0C02, 0x054E, 0x0431, 0x0413,
+ 0x079F, 0x05BE, 0x0F4D, 0x0403, 0x05AF, 0x055F, 0x05AE, 0x054F,
+ 0x0421, 0x05BD, 0x0DCD, 0x0411, 0x0412, 0x055E, 0x055D, 0x073D,
+ 0x058E, 0x072F, 0x072D, 0x079D, 0x0D2E, 0x0453, 0x078D, 0x053E,
+ 0x053F, 0x059E, 0x052F, 0x058F, 0x072E, 0x078F, 0x059F, 0x078E,
+ 0x071F, 0x073E, 0x051F, 0x070D, 0x079E, 0x070E, 0x071D, 0x0622,
+ 0x070F, 0x071E, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_4x4 {
+ 4, 4,
+ { 61, 84 },
+ { 184, 141 },
+ { 0, 53 },
+ { percentile_arr_4x4_0, percentile_arr_4x4_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (5 * 4)
+static const uint16_t percentile_arr_5x4_0[91] {
+ 0x02C1, 0xFAD1, 0xE8D3, 0xDAC2, 0xA8D2, 0x70D1, 0x50C2, 0x80C3,
+ 0xD2C3, 0x4AA2, 0x2AD2, 0x2242, 0x2251, 0x42A3, 0x1A43, 0x4A52,
+ 0x32B3, 0x2A41, 0x1042, 0x1851, 0x5892, 0x10A2, 0x2253, 0x10B2,
+ 0x10B3, 0x13DF, 0x3083, 0x08B1, 0x1043, 0x12B1, 0x0AB2, 0x1A93,
+ 0x1852, 0x1A33, 0x09CE, 0x08A3, 0x1022, 0x1283, 0x0853, 0x1AA1,
+ 0x1093, 0x11DE, 0x135F, 0x1832, 0x195F, 0x0A81, 0x11CF, 0x0A31,
+ 0x09DF, 0x0B4D, 0x09AF, 0x03CF, 0x0813, 0x03DD, 0x0A92, 0x0A82,
+ 0x03CD, 0x0023, 0x0BDE, 0x0BBF, 0x1232, 0x0221, 0x0291, 0x0A23,
+ 0x0833, 0x035D, 0x0BCE, 0x01BF, 0x0222, 0x134E, 0x0213, 0x0A01,
+ 0x0B4F, 0x0B5E, 0x038E, 0x032E, 0x03AF, 0x0A11, 0x03AD, 0x0203,
+ 0x0202, 0x0BBD, 0x033E, 0x03AE, 0x03BE, 0x0212, 0x033F, 0x039E,
+ 0x039F, 0x032F, 0x038F
+};
+
+static const uint16_t percentile_arr_5x4_1[104] {
+ 0x0433, 0xB621, 0x5452, 0x4443, 0x7FAE, 0xFCA3, 0x7CC2, 0x24B2,
+ 0x45DF, 0x44B3, 0x7631, 0x27CD, 0x1CD1, 0x1E03, 0x4FBE, 0x774F,
+ 0x1C42, 0x7691, 0x24A2, 0x2681, 0x3C23, 0x3C93, 0x0FBD, 0x1C32,
+ 0x1E82, 0x1E12, 0x0F4E, 0x1602, 0x0FAD, 0x0C51, 0x1FDD, 0x0E13,
+ 0x0DCF, 0x175E, 0x0C22, 0x175F, 0x15DE, 0x0CB1, 0x17AF, 0x1CC1,
+ 0x1F3F, 0x1483, 0x0441, 0x0C91, 0x04D2, 0x0DCE, 0x154E, 0x079F,
+ 0x0CA1, 0x0F5D, 0x0431, 0x15DD, 0x05BF, 0x0C92, 0x0611, 0x0C82,
+ 0x0402, 0x074D, 0x0DBD, 0x055E, 0x05BE, 0x0DCD, 0x0421, 0x05AF,
+ 0x0403, 0x0D4F, 0x055F, 0x05AE, 0x0413, 0x0E01, 0x055D, 0x073D,
+ 0x0C12, 0x0692, 0x0411, 0x072D, 0x078D, 0x079D, 0x058E, 0x0D2E,
+ 0x0453, 0x072F, 0x059E, 0x052F, 0x071F, 0x053F, 0x053E, 0x078F,
+ 0x058F, 0x051F, 0x0F2E, 0x059F, 0x078E, 0x073E, 0x071D, 0x070D,
+ 0x070E, 0x079E, 0x0622, 0x0683, 0x070F, 0x071E, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_5x4 {
+ 5, 4,
+ { 91, 104 },
+ { 322, 464 },
+ { 0, 202 },
+ { percentile_arr_5x4_0, percentile_arr_5x4_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (5 * 5)
+static const uint16_t percentile_arr_5x5_0[129] {
+ 0x00F3, 0xF8F2, 0x70E3, 0x62E1, 0x60E1, 0x4AC1, 0x3261, 0x38D3,
+ 0x3271, 0x5AF1, 0x5873, 0x2AD1, 0x28E2, 0x28F1, 0x2262, 0x9AC2,
+ 0x18D2, 0x1072, 0x1071, 0x22A2, 0x2062, 0x1A51, 0x10C2, 0x0892,
+ 0x08D1, 0x1AA3, 0x23EE, 0x08C3, 0x0BEF, 0x2242, 0x0863, 0x0AB3,
+ 0x0BFF, 0x0A93, 0x08A2, 0x0A41, 0x1083, 0x0842, 0x10B3, 0x21EE,
+ 0x10B2, 0x00B1, 0x1263, 0x12C3, 0x0A83, 0x0851, 0x11FE, 0x0253,
+ 0x09FD, 0x0A72, 0x09FF, 0x1AB2, 0x0BDF, 0x0A33, 0x0243, 0x0B7F,
+ 0x0AB1, 0x12D2, 0x0252, 0x096F, 0x00A3, 0x0893, 0x0822, 0x0843,
+ 0x097E, 0x097F, 0x01EF, 0x09CE, 0x03FE, 0x0A81, 0x036F, 0x0052,
+ 0x13FD, 0x0AA1, 0x1853, 0x036D, 0x0A92, 0x0832, 0x01DE, 0x0A82,
+ 0x0BED, 0x0231, 0x0BBF, 0x03DD, 0x0B6E, 0x01AF, 0x0813, 0x0023,
+ 0x0A91, 0x015F, 0x037E, 0x01CF, 0x0232, 0x0BCD, 0x0221, 0x0BDE,
+ 0x0213, 0x035F, 0x0B7D, 0x0223, 0x01BF, 0x0BCF, 0x01DF, 0x0033,
+ 0x0222, 0x03CE, 0x0A01, 0x03AF, 0x034D, 0x0B8E, 0x032E, 0x0203,
+ 0x0211, 0x0202, 0x0B5D, 0x03AD, 0x034E, 0x03AE, 0x034F, 0x033F,
+ 0x039F, 0x03BD, 0x03BE, 0x035E, 0x0212, 0x033E, 0x039E, 0x032F,
+ 0x038F
+};
+
+static const uint16_t percentile_arr_5x5_1[126] {
+ 0x0443, 0x6452, 0xFE21, 0x27AE, 0x2433, 0x1FCD, 0x25DF, 0x6CC2,
+ 0x2C62, 0x1F4F, 0x4C42, 0x1FBE, 0x0DEF, 0x34A3, 0x0E03, 0x54B2,
+ 0x1F7D, 0x17DD, 0x0DFF, 0x0CD1, 0x0E31, 0x0C71, 0x1CF1, 0x15FE,
+ 0x1691, 0x1681, 0x24B3, 0x174E, 0x0F6E, 0x0493, 0x175E, 0x1C51,
+ 0x17BD, 0x076D, 0x2CA2, 0x05EE, 0x1472, 0x2423, 0x0DCF, 0x0432,
+ 0x15DE, 0x0612, 0x0CD2, 0x0682, 0x0F5F, 0x07AD, 0x0602, 0x0CE1,
+ 0x0C91, 0x0FAF, 0x073F, 0x0E13, 0x0D7F, 0x0DCE, 0x0422, 0x0D7D,
+ 0x0441, 0x05FD, 0x0CB1, 0x0C83, 0x04C1, 0x0461, 0x0F9F, 0x0DDD,
+ 0x056E, 0x0C92, 0x0482, 0x0431, 0x05ED, 0x0D6F, 0x075D, 0x0402,
+ 0x057E, 0x0DBF, 0x04A1, 0x054E, 0x0F4D, 0x0403, 0x05CD, 0x0453,
+ 0x05AE, 0x0421, 0x0F1F, 0x05BE, 0x0601, 0x0611, 0x05BD, 0x05AF,
+ 0x078D, 0x072D, 0x073D, 0x055E, 0x0F9D, 0x0411, 0x0413, 0x0412,
+ 0x055F, 0x077E, 0x055D, 0x052E, 0x054F, 0x053E, 0x058E, 0x078F,
+ 0x059E, 0x071D, 0x0E92, 0x053F, 0x059F, 0x051F, 0x072F, 0x052F,
+ 0x070D, 0x079E, 0x058F, 0x072E, 0x070E, 0x078E, 0x070F, 0x073E,
+ 0x0622, 0x0683, 0x071E, 0x076F, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_5x5 {
+ 5, 5,
+ { 129, 126 },
+ { 258, 291 },
+ { 0, 116 },
+ { percentile_arr_5x5_0, percentile_arr_5x5_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (6 * 5)
+static const uint16_t percentile_arr_6x5_0[165] {
+ 0x0163, 0xF8F3, 0x9962, 0x8972, 0x7961, 0x7173, 0x6953, 0x5943,
+ 0x4B41, 0x3AE1, 0x38E3, 0x6971, 0x32C1, 0x28D3, 0x2A61, 0xC8F2,
+ 0x2271, 0x4873, 0x5B21, 0x3AD1, 0x1B13, 0x1952, 0x1B51, 0x12F1,
+ 0x1A62, 0x1322, 0x1951, 0x10E2, 0x1B31, 0x20F1, 0x2102, 0x2072,
+ 0x10D2, 0x1142, 0x2912, 0x3871, 0x2BEE, 0x0862, 0x1123, 0x0AC2,
+ 0x12A2, 0x0A51, 0x1922, 0x0941, 0x1BEF, 0x0B42, 0x08D1, 0x13FF,
+ 0x1933, 0x08C3, 0x08C2, 0x1131, 0x08E1, 0x2903, 0x0863, 0x0B32,
+ 0x1132, 0x1AC3, 0x0A42, 0x1A41, 0x0042, 0x21EE, 0x09FF, 0x03DF,
+ 0x0AA3, 0x11FE, 0x02B3, 0x0B11, 0x10B3, 0x0B03, 0x11FD, 0x0913,
+ 0x0A53, 0x037F, 0x1263, 0x0051, 0x0A33, 0x0B01, 0x016F, 0x0A72,
+ 0x1312, 0x08A2, 0x10B1, 0x0BFE, 0x11EF, 0x0B02, 0x0A52, 0x0043,
+ 0x0822, 0x01CE, 0x0A43, 0x097F, 0x036F, 0x08B2, 0x03FD, 0x0A83,
+ 0x0B33, 0x0AB1, 0x017E, 0x0B23, 0x0852, 0x02D2, 0x0BBF, 0x0BDD,
+ 0x03ED, 0x0AB2, 0x02A1, 0x0853, 0x036D, 0x0892, 0x0032, 0x0A31,
+ 0x0083, 0x09DE, 0x0A93, 0x08A3, 0x1213, 0x0BDE, 0x03CD, 0x036E,
+ 0x037E, 0x0A21, 0x0023, 0x0BCF, 0x01CF, 0x0013, 0x01AF, 0x0A92,
+ 0x0232, 0x035F, 0x0093, 0x0B7D, 0x015F, 0x0282, 0x01BF, 0x09DF,
+ 0x03CE, 0x0223, 0x0833, 0x0222, 0x03AF, 0x0A01, 0x0291, 0x0B4D,
+ 0x032E, 0x038E, 0x0203, 0x0281, 0x035D, 0x03AD, 0x0B9F, 0x0202,
+ 0x034F, 0x03BE, 0x0211, 0x03AE, 0x03BD, 0x0212, 0x034E, 0x033F,
+ 0x033E, 0x035E, 0x039E, 0x032F, 0x038F
+};
+
+static const uint16_t percentile_arr_6x5_1[145] {
+ 0x0443, 0xEFAE, 0x2CC2, 0x2E21, 0x2C52, 0x7C33, 0x47CD, 0x25DF,
+ 0x3CA3, 0xFFBE, 0x2551, 0x24B3, 0x474F, 0x1513, 0x2691, 0x1603,
+ 0x1462, 0x1D32, 0x14B2, 0x5442, 0x2CD2, 0x35EF, 0x0CD1, 0x3D22,
+ 0x17BD, 0x0FDD, 0x0DFF, 0x2631, 0x177D, 0x0CF1, 0x1E81, 0x0E82,
+ 0x1DFE, 0x0F5E, 0x0701, 0x2CA2, 0x1D03, 0x0F4E, 0x1471, 0x0C51,
+ 0x1F6E, 0x2FAF, 0x0561, 0x0C72, 0x176D, 0x0FAD, 0x0DEE, 0x05CF,
+ 0x0E13, 0x0F5F, 0x0E12, 0x0C23, 0x1E02, 0x1D12, 0x0CB1, 0x0C32,
+ 0x0C93, 0x15DE, 0x0F9F, 0x0F3F, 0x0D41, 0x0C41, 0x0CC1, 0x0D31,
+ 0x0C22, 0x05FD, 0x057F, 0x0D01, 0x0461, 0x04E1, 0x0D7D, 0x05CE,
+ 0x0502, 0x0C31, 0x05ED, 0x05DD, 0x0511, 0x0F11, 0x0491, 0x0D6F,
+ 0x0521, 0x056E, 0x0C83, 0x0D23, 0x04A1, 0x0C02, 0x075D, 0x05BF,
+ 0x0C21, 0x079D, 0x0482, 0x05BD, 0x0DBE, 0x05CD, 0x054E, 0x057E,
+ 0x0DAE, 0x074D, 0x078D, 0x0542, 0x0492, 0x05AF, 0x0611, 0x0F3D,
+ 0x0601, 0x071F, 0x055E, 0x059E, 0x0571, 0x054F, 0x0412, 0x0453,
+ 0x058E, 0x0413, 0x0D3E, 0x077E, 0x072D, 0x052E, 0x059F, 0x055D,
+ 0x072F, 0x0403, 0x0411, 0x058F, 0x055F, 0x0692, 0x078E, 0x053F,
+ 0x0D2F, 0x078F, 0x070D, 0x071D, 0x051F, 0x072E, 0x079E, 0x070E,
+ 0x070F, 0x073E, 0x0622, 0x0683, 0x0702, 0x071E, 0x076F, 0x07BF,
+ 0x07CE
+};
+
+static const packed_percentile_table block_pcd_6x5 {
+ 6, 5,
+ { 165, 145 },
+ { 388, 405 },
+ { 0, 156 },
+ { percentile_arr_6x5_0, percentile_arr_6x5_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (6 * 6)
+static const uint16_t percentile_arr_6x6_0[206] {
+ 0x006F, 0xF908, 0xF104, 0xE918, 0xE963, 0xD114, 0xB0F3, 0xA07E,
+ 0x7972, 0x705F, 0x687F, 0x6162, 0x5953, 0x586E, 0x610C, 0x524D,
+ 0x5973, 0x9943, 0x98E3, 0x904F, 0x8341, 0x7AC1, 0x3A61, 0x70D3,
+ 0xA073, 0x6AE1, 0x30F2, 0x3313, 0x2B21, 0x9A2E, 0x4322, 0x225D,
+ 0x2331, 0x2271, 0x22D1, 0x1A2D, 0x221F, 0x22F1, 0x1971, 0x6952,
+ 0x1951, 0x187D, 0x18F1, 0x1902, 0x185E, 0x1B51, 0x105D, 0x1A3D,
+ 0x30E2, 0x10D2, 0x1961, 0x12A2, 0x6072, 0x3942, 0x386D, 0x33EE,
+ 0x104E, 0x4923, 0x101E, 0x2122, 0x1251, 0x1141, 0x182F, 0x3133,
+ 0x080E, 0x1262, 0x123E, 0x1B32, 0x102E, 0x1931, 0x10D1, 0x1912,
+ 0x0871, 0x12C2, 0x08C2, 0x1103, 0x0B03, 0x1062, 0x083D, 0x08E1,
+ 0x1132, 0x184D, 0x0863, 0x08C3, 0x303F, 0x083E, 0x10B3, 0x12A3,
+ 0x0BEF, 0x0B11, 0x1A42, 0x2233, 0x13FF, 0x080F, 0x0A41, 0x0AC3,
+ 0x0842, 0x1A63, 0x0BDF, 0x09FF, 0x12B3, 0x124E, 0x0B12, 0x0B42,
+ 0x0A2F, 0x1253, 0x0913, 0x1051, 0x0B01, 0x120F, 0x0B02, 0x08A2,
+ 0x0BBF, 0x00B1, 0x22B1, 0x01EE, 0x1B33, 0x0B23, 0x0283, 0x13FD,
+ 0x0AB2, 0x11FD, 0x09FE, 0x0A43, 0x08B2, 0x0A1D, 0x0A52, 0x023F,
+ 0x101F, 0x01CE, 0x0A31, 0x0BDD, 0x0293, 0x1822, 0x12A1, 0x03FE,
+ 0x121E, 0x0843, 0x0272, 0x0B6F, 0x0052, 0x0A0D, 0x0BED, 0x12D2,
+ 0x1B7F, 0x1053, 0x0032, 0x01DE, 0x08A3, 0x020E, 0x0883, 0x09EF,
+ 0x0892, 0x0A21, 0x03CD, 0x0B5F, 0x0213, 0x0A32, 0x016F, 0x1292,
+ 0x03DE, 0x017E, 0x0BAF, 0x0223, 0x1093, 0x0BCF, 0x037E, 0x01DF,
+ 0x09CF, 0x015F, 0x09AF, 0x0023, 0x01BF, 0x0222, 0x0282, 0x03CE,
+ 0x1013, 0x036E, 0x097F, 0x0033, 0x0A01, 0x0B6D, 0x03BE, 0x037D,
+ 0x0281, 0x0BAE, 0x0203, 0x032E, 0x034D, 0x034F, 0x0291, 0x0211,
+ 0x038E, 0x03BD, 0x039E, 0x0BAD, 0x033E, 0x034E, 0x039F, 0x0202,
+ 0x035D, 0x0212, 0x033F, 0x035E, 0x038F, 0x032F
+};
+
+static const uint16_t percentile_arr_6x6_1[164] {
+ 0x07AE, 0x8443, 0x7E21, 0x77CD, 0x6C62, 0x9433, 0x6452, 0x34C2,
+ 0x5DDF, 0xC7BE, 0x25EF, 0x24A3, 0x3CF1, 0xFDFF, 0x177D, 0x1F4F,
+ 0xC551, 0x5CB3, 0x1532, 0x1513, 0x143E, 0x245D, 0x14B2, 0x2472,
+ 0x14D2, 0x1FBD, 0x1631, 0x2DFE, 0x1691, 0x17DD, 0x2E03, 0x376E,
+ 0x2442, 0x0F6D, 0x3C71, 0x2CD1, 0x2522, 0x6C51, 0x260D, 0x17AF,
+ 0x0DEE, 0x1C1F, 0x2F01, 0x142E, 0x0CA2, 0x0FAD, 0x3D03, 0x275E,
+ 0x1681, 0x274E, 0x1682, 0x1C23, 0x273F, 0x0F5F, 0x05DE, 0x15FD,
+ 0x0DCF, 0x1E02, 0x04B1, 0x144D, 0x0E12, 0x0D12, 0x1CC1, 0x0E13,
+ 0x1C6D, 0x0C32, 0x043D, 0x0C61, 0x0F9F, 0x04E1, 0x0DCE, 0x0D41,
+ 0x1C93, 0x0C22, 0x061D, 0x0D7F, 0x0C41, 0x0561, 0x0531, 0x0D21,
+ 0x0711, 0x0C91, 0x0501, 0x0C1E, 0x040F, 0x15DD, 0x0431, 0x0C2F,
+ 0x057D, 0x0C2D, 0x0DBE, 0x040E, 0x0D02, 0x0D11, 0x054E, 0x040D,
+ 0x0D23, 0x0DBF, 0x04A1, 0x05ED, 0x0C1D, 0x05BD, 0x072D, 0x056E,
+ 0x0483, 0x0F3D, 0x0482, 0x078D, 0x0F5D, 0x0453, 0x0D9E, 0x0C4E,
+ 0x05CD, 0x079D, 0x0402, 0x05AE, 0x0F1F, 0x0542, 0x074D, 0x056F,
+ 0x0421, 0x0D4F, 0x0601, 0x0571, 0x0492, 0x059F, 0x053F, 0x05AF,
+ 0x0611, 0x055E, 0x0D8E, 0x053E, 0x055D, 0x047D, 0x0411, 0x052E,
+ 0x058F, 0x051F, 0x055F, 0x0D7E, 0x072F, 0x052F, 0x0412, 0x078F,
+ 0x0403, 0x077E, 0x070D, 0x070E, 0x078E, 0x0F1D, 0x072E, 0x0413,
+ 0x070F, 0x0692, 0x079E, 0x060E, 0x0622, 0x0683, 0x0702, 0x071E,
+ 0x073E, 0x076F, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_6x6 {
+ 6, 6,
+ { 206, 164 },
+ { 769, 644 },
+ { 0, 256 },
+ { percentile_arr_6x6_0, percentile_arr_6x6_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 5)
+static const uint16_t percentile_arr_8x5_0[226] {
+ 0x0066, 0xF865, 0xE963, 0xA856, 0xA1F2, 0x9875, 0x91C3, 0x91E2,
+ 0x80F3, 0x8076, 0x61E3, 0x6153, 0x5172, 0x59D2, 0x51D3, 0x5047,
+ 0xA943, 0x49B3, 0x4846, 0x4962, 0xC037, 0x4173, 0x39F1, 0x7027,
+ 0xA2C1, 0x3AE1, 0x9341, 0x30D3, 0x5225, 0x2A61, 0x33C1, 0x28E3,
+ 0x53A1, 0x49C2, 0x2A06, 0x4055, 0x2006, 0x21D1, 0x2271, 0x4321,
+ 0x3873, 0x18F2, 0x2015, 0x1A15, 0x1857, 0x52D1, 0x3045, 0x4835,
+ 0x1952, 0x29E1, 0x3207, 0x1036, 0x1816, 0x2A16, 0x2971, 0x13B1,
+ 0x2A17, 0x2351, 0x1025, 0x1826, 0x30E2, 0x1262, 0x20F1, 0x1007,
+ 0x1072, 0x1151, 0x10D2, 0x1235, 0x1205, 0x1062, 0x4AF1, 0x1251,
+ 0x0B31, 0x1381, 0x13EE, 0x1B92, 0x13EF, 0x0942, 0x1AA2, 0x13FF,
+ 0x1161, 0x0B93, 0x19A2, 0x11B1, 0x08D1, 0x12C2, 0x0B13, 0x1B22,
+ 0x2123, 0x09A3, 0x2071, 0x1B7F, 0x1817, 0x0A42, 0x10C2, 0x1233,
+ 0x08C3, 0x0A41, 0x0B42, 0x09C1, 0x0933, 0x1AB3, 0x1382, 0x1BDF,
+ 0x2122, 0x0A53, 0x0AC3, 0x20E1, 0x0941, 0x0931, 0x0042, 0x0BA2,
+ 0x0AA3, 0x0992, 0x0863, 0x08B3, 0x11B2, 0x0902, 0x1283, 0x09FF,
+ 0x0B83, 0x0982, 0x0932, 0x0BFE, 0x0B32, 0x0BBF, 0x11FE, 0x036F,
+ 0x0851, 0x08B1, 0x18A2, 0x11EE, 0x0A52, 0x0BB2, 0x01FD, 0x0A43,
+ 0x1A63, 0x1193, 0x0B91, 0x0043, 0x1231, 0x0A26, 0x0AB1, 0x03FD,
+ 0x096F, 0x00B2, 0x0983, 0x0A72, 0x01CE, 0x0BDD, 0x0022, 0x0B11,
+ 0x1213, 0x0B6D, 0x017E, 0x1333, 0x0112, 0x0852, 0x02D2, 0x097F,
+ 0x01EF, 0x0AB2, 0x0293, 0x0853, 0x0BED, 0x0B12, 0x1303, 0x02A1,
+ 0x0892, 0x0032, 0x0883, 0x0B6E, 0x0292, 0x0A32, 0x037E, 0x0B23,
+ 0x0103, 0x0A21, 0x0B01, 0x0302, 0x0BCD, 0x00A3, 0x0BCF, 0x0BDE,
+ 0x0113, 0x01DE, 0x0B5F, 0x0013, 0x0BAF, 0x0223, 0x0222, 0x0A82,
+ 0x0833, 0x0023, 0x09CF, 0x037D, 0x01AF, 0x095F, 0x03CE, 0x09DF,
+ 0x01BF, 0x0893, 0x0203, 0x0201, 0x0B4D, 0x03BE, 0x032E, 0x03AE,
+ 0x0291, 0x0A02, 0x0211, 0x039F, 0x0281, 0x038E, 0x03AD, 0x033F,
+ 0x035D, 0x033E, 0x034E, 0x034F, 0x0212, 0x03BD, 0x032F, 0x035E,
+ 0x038F, 0x039E
+};
+
+static const uint16_t percentile_arr_8x5_1[167] {
+ 0x0621, 0xFCC2, 0x3443, 0xA433, 0x5532, 0x2551, 0x6CA3, 0x27AE,
+ 0x6452, 0x8E03, 0x3CB3, 0x4DA2, 0x6DDF, 0x37CD, 0x6F01, 0x1691,
+ 0x2E82, 0x27BE, 0x1513, 0x34D2, 0x1D22, 0x3E31, 0x2593, 0x2CB2,
+ 0x1C16, 0x374F, 0x0DD1, 0x2583, 0x6613, 0x0CD1, 0x0C35, 0x1462,
+ 0x3E81, 0x2612, 0x2C42, 0x3407, 0x14A2, 0x0E02, 0x1CF1, 0x0C06,
+ 0x17BD, 0x0F7D, 0x1D23, 0x35B1, 0x179F, 0x0D92, 0x0F5E, 0x1451,
+ 0x04B1, 0x1F6E, 0x0DEF, 0x0D31, 0x374E, 0x15C1, 0x0541, 0x2405,
+ 0x17AD, 0x0471, 0x1472, 0x0DFE, 0x0711, 0x0FDD, 0x0DFF, 0x0432,
+ 0x1D82, 0x0423, 0x0F6D, 0x07AF, 0x0F5F, 0x04C1, 0x1542, 0x0561,
+ 0x0DCF, 0x1D03, 0x1493, 0x0422, 0x0445, 0x0D12, 0x0C25, 0x0415,
+ 0x0DA1, 0x1591, 0x0DEE, 0x05DE, 0x0C31, 0x0491, 0x0441, 0x0D21,
+ 0x078D, 0x057D, 0x0C61, 0x0F3F, 0x0581, 0x0D6E, 0x0501, 0x0CA1,
+ 0x04E1, 0x0DFD, 0x057F, 0x0502, 0x0511, 0x0C82, 0x0483, 0x0C03,
+ 0x079D, 0x0402, 0x0DDD, 0x0611, 0x05AE, 0x0DCE, 0x056F, 0x0421,
+ 0x057E, 0x071F, 0x0DBF, 0x05BE, 0x0412, 0x059F, 0x054E, 0x077E,
+ 0x0C26, 0x05ED, 0x073D, 0x0601, 0x0492, 0x0453, 0x075D, 0x058E,
+ 0x0F2D, 0x05CD, 0x0571, 0x053E, 0x0692, 0x05BD, 0x054F, 0x055E,
+ 0x0411, 0x0F1D, 0x074D, 0x059E, 0x05AF, 0x070D, 0x053F, 0x058F,
+ 0x0413, 0x070F, 0x055D, 0x070E, 0x078F, 0x052E, 0x072F, 0x055F,
+ 0x078E, 0x0F2E, 0x052F, 0x051F, 0x0417, 0x071E, 0x0781, 0x0622,
+ 0x0683, 0x0702, 0x073E, 0x076F, 0x079E, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_8x5 {
+ 8, 5,
+ { 226, 167 },
+ { 763, 517 },
+ { 0, 178 },
+ { percentile_arr_8x5_0, percentile_arr_8x5_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 6)
+static const uint16_t percentile_arr_8x6_0[273] {
+ 0x0154, 0xF944, 0xE066, 0xA128, 0x9963, 0x8118, 0x806F, 0x79F2,
+ 0x79E2, 0x7108, 0xD934, 0x6056, 0x69C3, 0x60F3, 0x5972, 0x59E3,
+ 0x5075, 0x91B3, 0xC9D2, 0x807E, 0x385F, 0x4153, 0x3943, 0x4162,
+ 0x3837, 0x3847, 0x7173, 0x31D3, 0x6948, 0x3046, 0x307F, 0x5827,
+ 0x3114, 0x32C1, 0x3076, 0x2A4D, 0x58E3, 0x306E, 0x2924, 0x2A61,
+ 0x29F1, 0x50D3, 0x704F, 0x210C, 0x2BA1, 0x2225, 0x2873, 0x4865,
+ 0x2206, 0x8341, 0x2006, 0x3B21, 0x18F2, 0x21C2, 0x1A1F, 0x23C1,
+ 0x3AE1, 0x1855, 0x19D1, 0x1A15, 0x3815, 0x1207, 0x1835, 0x2A2E,
+ 0x1A16, 0x1836, 0x2271, 0x2845, 0x1A2D, 0x11E1, 0x1816, 0x1171,
+ 0x2217, 0x1952, 0x12D1, 0x3904, 0x125D, 0x4BB1, 0x207D, 0x10E2,
+ 0x1026, 0x2025, 0x12F1, 0x28F1, 0x105D, 0x1235, 0x12A2, 0x1007,
+ 0x123D, 0x1A05, 0x1072, 0x1331, 0x101E, 0x0951, 0x10D2, 0x1057,
+ 0x1B92, 0x185E, 0x1251, 0x19A2, 0x186D, 0x0B81, 0x2BEE, 0x080E,
+ 0x1A33, 0x1942, 0x0B13, 0x0B51, 0x11A3, 0x0923, 0x2322, 0x09B1,
+ 0x184E, 0x1161, 0x18D1, 0x0933, 0x0B93, 0x4A62, 0x1017, 0x082F,
+ 0x0A42, 0x0B82, 0x0AA3, 0x0A41, 0x08C2, 0x08B3, 0x0A3E, 0x22B3,
+ 0x0871, 0x1BBF, 0x09C1, 0x0AC2, 0x09B2, 0x0BEF, 0x082E, 0x1062,
+ 0x0922, 0x08C3, 0x1063, 0x0A53, 0x0BDF, 0x080F, 0x0B42, 0x0A83,
+ 0x084D, 0x103F, 0x0931, 0x08E1, 0x0A0F, 0x1BA2, 0x09FF, 0x1332,
+ 0x03FF, 0x0941, 0x12C3, 0x0A63, 0x003D, 0x0842, 0x083E, 0x0B83,
+ 0x0BB2, 0x0A31, 0x0932, 0x1102, 0x0992, 0x0982, 0x1051, 0x08B1,
+ 0x0A2F, 0x121E, 0x02B1, 0x0A4E, 0x11EE, 0x00A2, 0x1022, 0x0043,
+ 0x0A52, 0x0A1D, 0x0226, 0x1193, 0x03DD, 0x08B2, 0x0BFD, 0x0A43,
+ 0x0A13, 0x0AB2, 0x01FD, 0x09FE, 0x020D, 0x081F, 0x0B33, 0x0053,
+ 0x0B91, 0x0293, 0x0B11, 0x0B7F, 0x0AA1, 0x0B03, 0x0A0E, 0x03FE,
+ 0x01CE, 0x0B6F, 0x0183, 0x0912, 0x023F, 0x0852, 0x0A21, 0x0323,
+ 0x03ED, 0x0A32, 0x13AF, 0x0272, 0x08A3, 0x0B12, 0x0083, 0x0832,
+ 0x13CD, 0x0223, 0x0A92, 0x0092, 0x0AD2, 0x0301, 0x0302, 0x0BDE,
+ 0x0A22, 0x01EF, 0x0B5F, 0x0103, 0x0BCF, 0x096F, 0x017E, 0x0113,
+ 0x01DE, 0x0823, 0x0282, 0x0B6E, 0x015F, 0x0813, 0x01AF, 0x01CF,
+ 0x0B7E, 0x0033, 0x01DF, 0x0BCE, 0x01BF, 0x036D, 0x0A03, 0x017F,
+ 0x03BE, 0x0201, 0x0893, 0x038E, 0x034D, 0x03AE, 0x0202, 0x039F,
+ 0x0291, 0x0A11, 0x032E, 0x033F, 0x034F, 0x0281, 0x037D, 0x03BD,
+ 0x0212, 0x033E, 0x035E, 0x034E, 0x035D, 0x03AD, 0x032F, 0x038F,
+ 0x039E
+};
+
+static const uint16_t percentile_arr_8x6_1[186] {
+ 0x0621, 0xFC33, 0x37AE, 0x1CC2, 0x2C43, 0xAD32, 0x34A3, 0x4551,
+ 0x6452, 0x5C62, 0x1FCD, 0x14F1, 0x4CB3, 0x24D2, 0x15DF, 0x0FBE,
+ 0x2603, 0x3DA2, 0x2E31, 0x25D1, 0x25EF, 0x0D22, 0x2E91, 0x1E82,
+ 0x0FBD, 0x1513, 0x0CB2, 0x0CD1, 0x0F4F, 0x1F7D, 0x1701, 0x0C16,
+ 0x2593, 0x2C42, 0x0C72, 0x14A2, 0x0F6E, 0x0C35, 0x0C71, 0x0D83,
+ 0x0C07, 0x1DFF, 0x043E, 0x1613, 0x07DD, 0x0FAD, 0x1451, 0x076D,
+ 0x0E81, 0x05FE, 0x0406, 0x0E0D, 0x045D, 0x2612, 0x0E02, 0x07AF,
+ 0x0DB1, 0x0F5E, 0x15C1, 0x0C23, 0x1523, 0x0C1F, 0x0D92, 0x04B1,
+ 0x0D31, 0x0432, 0x0D61, 0x0F4E, 0x0D41, 0x0DEE, 0x0D42, 0x04C1,
+ 0x0CE1, 0x079F, 0x0C2E, 0x0405, 0x0C22, 0x0461, 0x0E1D, 0x0582,
+ 0x073F, 0x0571, 0x0C4D, 0x0DFD, 0x05CE, 0x0C6D, 0x05DE, 0x0415,
+ 0x0C45, 0x075F, 0x0C41, 0x0D03, 0x05A1, 0x0711, 0x05CF, 0x0425,
+ 0x0C93, 0x0D21, 0x0591, 0x043D, 0x0D12, 0x0501, 0x040F, 0x0511,
+ 0x0431, 0x0C03, 0x04A1, 0x078D, 0x0581, 0x041E, 0x040D, 0x0C02,
+ 0x040E, 0x05DD, 0x057F, 0x079D, 0x042D, 0x0D9F, 0x0502, 0x056E,
+ 0x0412, 0x071F, 0x044E, 0x05BF, 0x0C1D, 0x0482, 0x05AE, 0x042F,
+ 0x057D, 0x0491, 0x054E, 0x047D, 0x0DBE, 0x0611, 0x0492, 0x0601,
+ 0x05BD, 0x05CD, 0x0426, 0x05ED, 0x072D, 0x073D, 0x0483, 0x0F5D,
+ 0x0421, 0x056F, 0x053F, 0x058E, 0x054F, 0x078F, 0x053E, 0x059E,
+ 0x057E, 0x051F, 0x055D, 0x0413, 0x070D, 0x05AF, 0x0411, 0x0453,
+ 0x0D5E, 0x077E, 0x052F, 0x070F, 0x074D, 0x0692, 0x070E, 0x072F,
+ 0x072E, 0x058F, 0x071D, 0x052E, 0x0417, 0x073E, 0x0781, 0x078E,
+ 0x055F, 0x060E, 0x0622, 0x0683, 0x0702, 0x071E, 0x076F, 0x079E,
+ 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_8x6 {
+ 8, 6,
+ { 273, 186 },
+ { 880, 300 },
+ { 0, 64 },
+ { percentile_arr_8x6_0, percentile_arr_8x6_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 8)
+static const uint16_t percentile_arr_8x8_0[347] {
+ 0x0334, 0xFD44, 0xDD14, 0x9154, 0x9B08, 0x906A, 0x8928, 0x8108,
+ 0xE866, 0xC918, 0x606F, 0xC0FE, 0x5963, 0x58EE, 0x6534, 0x505A,
+ 0x51E2, 0xA8CF, 0x5354, 0x5314, 0x5134, 0x5524, 0x48F3, 0x504B,
+ 0x487E, 0x5344, 0x49C3, 0x4972, 0x49F2, 0x4856, 0xD0EF, 0x81D2,
+ 0x78DE, 0x4261, 0x3AC1, 0x71E3, 0x6879, 0x390C, 0x3143, 0x31B3,
+ 0x385F, 0x3153, 0x306E, 0x3037, 0x30DF, 0x3162, 0x304F, 0x3075,
+ 0xB03B, 0x2847, 0x28E3, 0x2914, 0x507F, 0x28BF, 0x5173, 0x5073,
+ 0x20D3, 0x2A06, 0x2827, 0x2508, 0x2229, 0x29D3, 0x204A, 0x207A,
+ 0x2046, 0x4148, 0x20FD, 0x4225, 0x23A1, 0x3944, 0x2065, 0x1924,
+ 0x2324, 0x1806, 0x19F1, 0x2215, 0x1876, 0x22AD, 0x502B, 0x1B04,
+ 0x18F2, 0x3A4D, 0x3216, 0x3504, 0x18DD, 0x1B21, 0x10CE, 0x1869,
+ 0x1B41, 0x1855, 0x1207, 0x1AE1, 0x2845, 0x19D1, 0x2A0A, 0x1A2D,
+ 0x2A1A, 0x11C2, 0x1A0B, 0x1217, 0x2816, 0x121B, 0x1271, 0x2AD1,
+ 0x1035, 0x1015, 0x287D, 0x12F1, 0x43C1, 0x1171, 0x1A05, 0x08E2,
+ 0x11E1, 0x3251, 0x2049, 0x20F1, 0x12CD, 0x0A39, 0x1219, 0x1059,
+ 0x1104, 0x1036, 0x1872, 0x3007, 0x08ED, 0x205E, 0x1026, 0x0952,
+ 0x1392, 0x1019, 0x0951, 0x100A, 0x13EE, 0x08D2, 0x1242, 0x0ABD,
+ 0x22A2, 0x0BDF, 0x2B81, 0x0A35, 0x13B1, 0x0839, 0x13BF, 0x0A33,
+ 0x1B31, 0x205D, 0x1241, 0x183A, 0x2025, 0x0B93, 0x0A3D, 0x1017,
+ 0x1313, 0x1253, 0x082A, 0x204E, 0x09A2, 0x080B, 0x0A1F, 0x125D,
+ 0x0A2E, 0x081A, 0x08D1, 0x082F, 0x086D, 0x1B82, 0x0A09, 0x0B22,
+ 0x1062, 0x11A3, 0x2161, 0x0923, 0x129F, 0x1A62, 0x0871, 0x0942,
+ 0x081B, 0x1133, 0x18AE, 0x0A9E, 0x0863, 0x09FF, 0x18C2, 0x0B51,
+ 0x08BD, 0x0AA3, 0x09B1, 0x1AC2, 0x08B3, 0x0829, 0x0BEF, 0x0B83,
+ 0x0AAE, 0x0A8D, 0x1857, 0x185B, 0x08AF, 0x103F, 0x08C3, 0x09B2,
+ 0x0A4E, 0x11C1, 0x0A31, 0x0B42, 0x0A83, 0x0BFF, 0x13DD, 0x00CD,
+ 0x0AB3, 0x0842, 0x08BE, 0x0922, 0x1A8E, 0x08E1, 0x002E, 0x0BA2,
+ 0x0A8F, 0x2263, 0x0252, 0x0B32, 0x0AC3, 0x0941, 0x0A43, 0x083D,
+ 0x083E, 0x0A3E, 0x084D, 0x1131, 0x136F, 0x0AB1, 0x0193, 0x0BFD,
+ 0x0391, 0x0851, 0x13AF, 0x0843, 0x0213, 0x1226, 0x0932, 0x03B2,
+ 0x0902, 0x0BCD, 0x0221, 0x089E, 0x00B1, 0x0BDE, 0x03FE, 0x02A1,
+ 0x0982, 0x009F, 0x080E, 0x0B5F, 0x02BE, 0x0A32, 0x0A2A, 0x01EE,
+ 0x0053, 0x0AB2, 0x0192, 0x09FD, 0x0052, 0x0B03, 0x0293, 0x00A2,
+ 0x0B7F, 0x0BED, 0x0311, 0x08B2, 0x0A72, 0x088E, 0x0333, 0x0B12,
+ 0x0A23, 0x0822, 0x0083, 0x11CE, 0x021D, 0x08A3, 0x088F, 0x029D,
+ 0x0A22, 0x0A3F, 0x01FE, 0x020F, 0x0983, 0x02D2, 0x0292, 0x0B23,
+ 0x001E, 0x0BCF, 0x03CE, 0x09AF, 0x0B02, 0x0301, 0x022F, 0x137E,
+ 0x021E, 0x09EF, 0x016F, 0x0112, 0x097E, 0x080F, 0x020D, 0x0092,
+ 0x01DE, 0x09DF, 0x0032, 0x0033, 0x0A82, 0x03BE, 0x0B6E, 0x001F,
+ 0x020E, 0x0023, 0x09CF, 0x0113, 0x0103, 0x0013, 0x0BAE, 0x0203,
+ 0x0BAD, 0x01BF, 0x034F, 0x095F, 0x036D, 0x0202, 0x017F, 0x0093,
+ 0x0201, 0x034D, 0x0212, 0x035D, 0x03BD, 0x0B3F, 0x035E, 0x0211,
+ 0x0281, 0x0291, 0x032E, 0x037D, 0x034E, 0x038E, 0x039F, 0x032F,
+ 0x033E, 0x038F, 0x039E
+};
+
+static const uint16_t percentile_arr_8x8_1[208] {
+ 0x0621, 0x3443, 0x47CD, 0x97AE, 0xFC62, 0x14F1, 0x24C2, 0x25DF,
+ 0x3C33, 0x1C52, 0x9C72, 0x0FBE, 0x0C5D, 0x343E, 0x24A3, 0x1551,
+ 0x5D32, 0x1CD2, 0x15EF, 0x4E31, 0x04DD, 0x1FDD, 0x174F, 0x0DD1,
+ 0x3E0D, 0x15FF, 0x0DA2, 0x1E03, 0x17BD, 0x177D, 0x14B3, 0x0471,
+ 0x0CAE, 0x1C1F, 0x04D1, 0x0F6E, 0x0DFE, 0x1C42, 0x0C16, 0x0D22,
+ 0x0C9F, 0x2C2E, 0x0FAD, 0x0571, 0x147D, 0x0C07, 0x04B2, 0x0F6D,
+ 0x0F5E, 0x07AF, 0x146D, 0x0C51, 0x0593, 0x2583, 0x0C4E, 0x040B,
+ 0x0C35, 0x0513, 0x0E91, 0x0406, 0x073F, 0x144D, 0x0561, 0x048F,
+ 0x0F01, 0x0F4E, 0x0CA2, 0x075F, 0x1682, 0x04E1, 0x0C1A, 0x04BD,
+ 0x0542, 0x0D41, 0x0DEE, 0x04CD, 0x0DCF, 0x04B1, 0x0C15, 0x0C3D,
+ 0x0423, 0x0592, 0x0DDE, 0x0422, 0x0432, 0x05FD, 0x0DC1, 0x05B1,
+ 0x0DCE, 0x0612, 0x0C2F, 0x0445, 0x0602, 0x0531, 0x0439, 0x0E81,
+ 0x0582, 0x0C61, 0x061D, 0x049E, 0x0405, 0x0409, 0x0DBE, 0x079F,
+ 0x0D21, 0x04C1, 0x0C0A, 0x0E13, 0x04AD, 0x040E, 0x0581, 0x0419,
+ 0x05DD, 0x0D03, 0x049D, 0x0449, 0x0429, 0x048E, 0x0DA1, 0x0425,
+ 0x0512, 0x0501, 0x0431, 0x0523, 0x0441, 0x042D, 0x040F, 0x0D7D,
+ 0x0511, 0x0502, 0x05BF, 0x04A1, 0x0C03, 0x0402, 0x079D, 0x05AE,
+ 0x075D, 0x057F, 0x041D, 0x048D, 0x042A, 0x0453, 0x05AF, 0x078D,
+ 0x0C0D, 0x073D, 0x0491, 0x0591, 0x05BD, 0x072D, 0x057E, 0x051F,
+ 0x0482, 0x0492, 0x041E, 0x0412, 0x0D9F, 0x0421, 0x0493, 0x0711,
+ 0x056E, 0x059E, 0x054E, 0x0611, 0x05ED, 0x074D, 0x070F, 0x056F,
+ 0x052F, 0x053F, 0x071F, 0x054F, 0x05CD, 0x0483, 0x055E, 0x072F,
+ 0x0E01, 0x0426, 0x058F, 0x0413, 0x078F, 0x071D, 0x055F, 0x058E,
+ 0x0411, 0x053E, 0x071E, 0x055D, 0x077E, 0x052E, 0x0692, 0x0417,
+ 0x070D, 0x078E, 0x070E, 0x072E, 0x041B, 0x060E, 0x0622, 0x0683,
+ 0x068D, 0x0702, 0x073E, 0x076F, 0x0781, 0x079E, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_8x8 {
+ 8, 8,
+ { 347, 208 },
+ { 1144, 267 },
+ { 0, 38 },
+ { percentile_arr_8x8_0, percentile_arr_8x8_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 5)
+static const uint16_t percentile_arr_10x5_0[274] {
+ 0x0165, 0xF975, 0xD866, 0xC056, 0xA946, 0x90C6, 0x90F5, 0x8963,
+ 0x80D6, 0x80E6, 0x60F3, 0x61C3, 0x59F2, 0xA927, 0x5075, 0x4847,
+ 0x5153, 0x4955, 0x49E2, 0x48B6, 0x41D2, 0x4943, 0x8305, 0x8172,
+ 0x4046, 0x4037, 0x40A7, 0x70B7, 0x7AC1, 0x31E3, 0x7027, 0x30E5,
+ 0x69D3, 0x99B3, 0x3315, 0x6115, 0x3136, 0x3076, 0x3173, 0x30D5,
+ 0x3106, 0x8962, 0x2916, 0x30C7, 0x5126, 0x30D3, 0x2956, 0x5117,
+ 0x2B41, 0x2AE1, 0x2A61, 0x29F1, 0x2306, 0x2145, 0x4A85, 0x2057,
+ 0x40E3, 0x4137, 0x3B21, 0x23C1, 0x2065, 0x1925, 0x51C2, 0x5225,
+ 0x4935, 0x1AD1, 0x23A1, 0x19D1, 0x1A71, 0x4055, 0x1873, 0x1A86,
+ 0x1295, 0x18F2, 0x28A6, 0x1952, 0x4AA5, 0x20B5, 0x10C5, 0x2AA2,
+ 0x11E1, 0x1107, 0x10D2, 0x2171, 0x1351, 0x3036, 0x1331, 0x1BEE,
+ 0x2035, 0x1045, 0x1313, 0x0A15, 0x1087, 0x1296, 0x13EF, 0x18E2,
+ 0x1151, 0x1086, 0x10F1, 0x08A5, 0x12C2, 0x1BFF, 0x1095, 0x1A62,
+ 0x1322, 0x0942, 0x1026, 0x1872, 0x1062, 0x0897, 0x1123, 0x08D1,
+ 0x1A06, 0x0806, 0x137F, 0x13B1, 0x13DF, 0x1A51, 0x09B1, 0x0A83,
+ 0x1015, 0x22F1, 0x0961, 0x0B81, 0x12B3, 0x0A35, 0x0AA3, 0x20B3,
+ 0x08C3, 0x2342, 0x0933, 0x0A33, 0x09A2, 0x10C2, 0x0896, 0x2205,
+ 0x0825, 0x20E1, 0x0922, 0x1242, 0x0B16, 0x0B32, 0x09A3, 0x0AC3,
+ 0x0BBF, 0x0B93, 0x0071, 0x0931, 0x0A41, 0x2392, 0x13FE, 0x09C1,
+ 0x0B07, 0x0016, 0x1182, 0x09B2, 0x0A26, 0x0132, 0x0941, 0x0A93,
+ 0x0992, 0x1063, 0x1217, 0x01FF, 0x11EE, 0x1216, 0x0B23, 0x0B82,
+ 0x0042, 0x1102, 0x0213, 0x0B6F, 0x09FE, 0x1207, 0x0807, 0x18B1,
+ 0x0253, 0x0AB1, 0x08A2, 0x13FD, 0x01FD, 0x1983, 0x0AB2, 0x0A31,
+ 0x016F, 0x0B11, 0x00B2, 0x0851, 0x0AD2, 0x0993, 0x0BDD, 0x12A1,
+ 0x017F, 0x0A97, 0x1022, 0x0383, 0x0843, 0x0A52, 0x03A2, 0x097E,
+ 0x0817, 0x03B2, 0x0A43, 0x09EF, 0x0A63, 0x0B33, 0x0B03, 0x0292,
+ 0x0272, 0x09CE, 0x0287, 0x136D, 0x0053, 0x0B12, 0x0083, 0x0892,
+ 0x0112, 0x1282, 0x03ED, 0x0852, 0x0301, 0x1391, 0x0232, 0x0B7E,
+ 0x0221, 0x08A3, 0x0BCD, 0x0BCF, 0x036E, 0x09DE, 0x0103, 0x03DE,
+ 0x0832, 0x0BAF, 0x0302, 0x13CE, 0x035F, 0x0093, 0x0A23, 0x01DF,
+ 0x0013, 0x0A22, 0x0023, 0x0113, 0x09AF, 0x01BF, 0x0033, 0x095F,
+ 0x0203, 0x0281, 0x09CF, 0x037D, 0x0201, 0x0B4D, 0x03AE, 0x03BE,
+ 0x0291, 0x035E, 0x038E, 0x0B9F, 0x03AD, 0x0202, 0x034F, 0x0211,
+ 0x035D, 0x0212, 0x032E, 0x039E, 0x033F, 0x034E, 0x03BD, 0x032F,
+ 0x033E, 0x038F
+};
+
+static const uint16_t percentile_arr_10x5_1[180] {
+ 0x0532, 0xFCA3, 0x3621, 0x6E82, 0x2CC2, 0x3D51, 0x3F01, 0x2691,
+ 0x17AE, 0x35A2, 0x74B3, 0x1603, 0x4433, 0x3C43, 0x6C35, 0x25D1,
+ 0x1D13, 0x15DF, 0x37CD, 0x0D93, 0x1D22, 0x0E81, 0x1452, 0x0CD2,
+ 0x37BE, 0x0CB2, 0x3407, 0x1523, 0x0C16, 0x0CB5, 0x0C96, 0x1486,
+ 0x2631, 0x1506, 0x0F4F, 0x1583, 0x0CD1, 0x2CA2, 0x2612, 0x1613,
+ 0x1602, 0x1F11, 0x179F, 0x17BD, 0x15B1, 0x0406, 0x1D41, 0x0CF1,
+ 0x0D31, 0x0442, 0x1C62, 0x0F6E, 0x077D, 0x0C51, 0x0445, 0x0D15,
+ 0x2592, 0x0CB1, 0x05EF, 0x0542, 0x17AF, 0x1425, 0x075E, 0x0FAD,
+ 0x0CC1, 0x0503, 0x0512, 0x15C1, 0x0C95, 0x0415, 0x0505, 0x0F4E,
+ 0x04A5, 0x0493, 0x0C32, 0x0F5F, 0x04E1, 0x0521, 0x0C85, 0x07DD,
+ 0x0582, 0x15FF, 0x05CF, 0x0405, 0x0D91, 0x05A1, 0x05FE, 0x0C23,
+ 0x0561, 0x0472, 0x0471, 0x0C22, 0x0DEE, 0x076D, 0x0502, 0x0426,
+ 0x0C61, 0x0D7D, 0x0525, 0x05DE, 0x0DCE, 0x079D, 0x0692, 0x0441,
+ 0x0C91, 0x05DD, 0x0511, 0x057F, 0x0611, 0x0DFD, 0x078D, 0x056E,
+ 0x0492, 0x04A1, 0x073F, 0x0C31, 0x05BE, 0x0483, 0x0571, 0x056F,
+ 0x0D9F, 0x0581, 0x0501, 0x057E, 0x05BF, 0x078F, 0x0516, 0x05ED,
+ 0x0402, 0x0F7E, 0x0482, 0x054E, 0x075D, 0x071F, 0x05CD, 0x0535,
+ 0x05AE, 0x0C11, 0x058F, 0x05AF, 0x0421, 0x0413, 0x0601, 0x054F,
+ 0x073D, 0x059E, 0x0487, 0x070F, 0x078E, 0x0781, 0x053E, 0x0403,
+ 0x072D, 0x055D, 0x05BD, 0x079E, 0x0D8E, 0x0412, 0x052E, 0x074D,
+ 0x053F, 0x051F, 0x070E, 0x055F, 0x072F, 0x052F, 0x070D, 0x055E,
+ 0x0417, 0x0453, 0x072E, 0x0622, 0x0683, 0x0702, 0x071D, 0x071E,
+ 0x073E, 0x076F, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_10x5 {
+ 10, 5,
+ { 274, 180 },
+ { 954, 324 },
+ { 0, 79 },
+ { percentile_arr_10x5_0, percentile_arr_10x5_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 6)
+static const uint16_t percentile_arr_10x6_0[325] {
+ 0x01A4, 0xF954, 0xA066, 0x9975, 0x80F5, 0x7056, 0x6918, 0x6963,
+ 0x58C6, 0x5946, 0x5928, 0x5174, 0x586F, 0xA0E6, 0x5108, 0x48D6,
+ 0x49E2, 0x40F3, 0x9172, 0x41F2, 0xB875, 0x3927, 0x39C3, 0xA953,
+ 0x3934, 0x3305, 0x30B6, 0x6943, 0x31D2, 0x3876, 0x3037, 0x2955,
+ 0x30A7, 0x32C1, 0x29B3, 0x3027, 0x287E, 0x30B7, 0x29E3, 0x5846,
+ 0x2B15, 0x2847, 0x3162, 0x5173, 0x4936, 0x285F, 0x48D3, 0x2164,
+ 0x4906, 0x20E5, 0x2915, 0x2116, 0x407F, 0x20D5, 0x2A61, 0x4117,
+ 0x20E3, 0x2126, 0x4148, 0x206E, 0x39D3, 0x2145, 0x41B4, 0x1B06,
+ 0x2114, 0x2165, 0x5321, 0x5A85, 0x1A4D, 0x1A1F, 0x19F1, 0x3341,
+ 0x184F, 0x1956, 0x3125, 0x30C7, 0x28F2, 0x1937, 0x1AE1, 0x1073,
+ 0x1BA1, 0x1935, 0x110C, 0x1BC1, 0x3A25, 0x19C2, 0x1295, 0x122E,
+ 0x1944, 0x11D1, 0x1124, 0x1857, 0x22D1, 0x2286, 0x1A2D, 0x12A2,
+ 0x2107, 0x1055, 0x2065, 0x0A71, 0x2152, 0x10C5, 0x10D2, 0x1331,
+ 0x08B5, 0x1171, 0x2836, 0x10A6, 0x0904, 0x123D, 0x20F1, 0x12A5,
+ 0x10E2, 0x107D, 0x1AF1, 0x1313, 0x0951, 0x11E1, 0x1B22, 0x1B51,
+ 0x0835, 0x101E, 0x0A5D, 0x0A15, 0x3045, 0x0A96, 0x08A5, 0x1142,
+ 0x12A3, 0x1872, 0x085D, 0x09B1, 0x100E, 0x0887, 0x0886, 0x086D,
+ 0x0933, 0x12B3, 0x0897, 0x08B3, 0x0A33, 0x0923, 0x1095, 0x0BEE,
+ 0x2BB1, 0x085E, 0x1283, 0x0A51, 0x1026, 0x0A06, 0x12C2, 0x08D1,
+ 0x11A2, 0x13BF, 0x08C3, 0x10C2, 0x0A3E, 0x0BDF, 0x0B81, 0x13EF,
+ 0x0A35, 0x0B16, 0x082F, 0x2161, 0x1B32, 0x0806, 0x084E, 0x11A3,
+ 0x1015, 0x1122, 0x2931, 0x0342, 0x0825, 0x0A0F, 0x0896, 0x0A05,
+ 0x0241, 0x09C1, 0x083F, 0x0A42, 0x0071, 0x0B07, 0x082E, 0x0393,
+ 0x12B1, 0x0A62, 0x0226, 0x0A2F, 0x0B92, 0x0063, 0x0932, 0x0862,
+ 0x09FF, 0x0A31, 0x00E1, 0x12B2, 0x09B2, 0x0AC3, 0x0941, 0x0293,
+ 0x1323, 0x104D, 0x003E, 0x083D, 0x0992, 0x1382, 0x03FF, 0x0A13,
+ 0x1016, 0x0A53, 0x0182, 0x1007, 0x0AA1, 0x080F, 0x0A16, 0x0A1E,
+ 0x0042, 0x0902, 0x13DD, 0x0BB2, 0x0A63, 0x00A2, 0x08B1, 0x03FE,
+ 0x1207, 0x08B2, 0x0B83, 0x09EE, 0x0311, 0x0A87, 0x0BAF, 0x03A2,
+ 0x09FD, 0x0051, 0x0B33, 0x020D, 0x09CE, 0x0217, 0x021D, 0x0817,
+ 0x020E, 0x0A4E, 0x001F, 0x0BFD, 0x0297, 0x0983, 0x0A92, 0x0252,
+ 0x0243, 0x0B03, 0x0193, 0x036F, 0x0B12, 0x0043, 0x0822, 0x0A21,
+ 0x01FE, 0x0853, 0x037F, 0x023F, 0x0BED, 0x02D2, 0x0B91, 0x0232,
+ 0x0282, 0x0912, 0x08A3, 0x0852, 0x0223, 0x0BCD, 0x0083, 0x0301,
+ 0x0832, 0x01EF, 0x0892, 0x0302, 0x0A72, 0x03DE, 0x0893, 0x0BCF,
+ 0x09DE, 0x03CE, 0x035F, 0x0833, 0x0023, 0x0103, 0x017E, 0x0813,
+ 0x01CF, 0x01BF, 0x016F, 0x0A22, 0x037E, 0x0113, 0x01AF, 0x0B6E,
+ 0x03BE, 0x0201, 0x0A03, 0x01DF, 0x036D, 0x03AE, 0x015F, 0x0281,
+ 0x033E, 0x0A02, 0x038E, 0x017F, 0x0291, 0x034D, 0x03BD, 0x0B7D,
+ 0x03AD, 0x0211, 0x0212, 0x034F, 0x032E, 0x039F, 0x034E, 0x035D,
+ 0x035E, 0x033F, 0x039E, 0x032F, 0x038F
+};
+
+static const uint16_t percentile_arr_10x6_1[199] {
+ 0x0621, 0xBD32, 0x5CA3, 0x1FAE, 0x64C2, 0x1D51, 0x6C33, 0xFC43,
+ 0x5CB3, 0x25A2, 0x2E82, 0x35D1, 0x4F01, 0x3FBE, 0x3691, 0x2DDF,
+ 0x2E03, 0x3FCD, 0x14D2, 0x1CF1, 0x0C52, 0x3C35, 0x2D22, 0x1513,
+ 0x1462, 0x54B2, 0x0E31, 0x4E81, 0x1593, 0x1D23, 0x1CD1, 0x14B5,
+ 0x2FBD, 0x0C07, 0x1D06, 0x0DEF, 0x14A2, 0x1612, 0x1F4F, 0x0C16,
+ 0x1F7D, 0x0C96, 0x0486, 0x1F9F, 0x0D42, 0x4583, 0x0E02, 0x0472,
+ 0x0DB1, 0x1613, 0x0FAD, 0x0D41, 0x0F11, 0x0E0D, 0x1C42, 0x143E,
+ 0x076E, 0x04B1, 0x0FAF, 0x0D61, 0x0531, 0x0C71, 0x0DFF, 0x0DFE,
+ 0x0406, 0x0C45, 0x0451, 0x0D15, 0x05C1, 0x2CC1, 0x141F, 0x0CE1,
+ 0x0FDD, 0x0C22, 0x0582, 0x0D92, 0x0571, 0x0F6D, 0x0C93, 0x045D,
+ 0x0F5E, 0x044D, 0x0423, 0x0D05, 0x0425, 0x0C95, 0x04A5, 0x0DCE,
+ 0x075F, 0x0E1D, 0x0503, 0x042E, 0x0D91, 0x0512, 0x0DDE, 0x05A1,
+ 0x074E, 0x0C32, 0x0431, 0x0415, 0x0D21, 0x05EE, 0x040E, 0x0DDD,
+ 0x0485, 0x1525, 0x0491, 0x0C26, 0x046D, 0x0C05, 0x05CF, 0x05FD,
+ 0x0E92, 0x073F, 0x0C0D, 0x043D, 0x0502, 0x0C1E, 0x041D, 0x0461,
+ 0x04A1, 0x0511, 0x0581, 0x05BD, 0x0C41, 0x059F, 0x05BF, 0x040F,
+ 0x0C7D, 0x0402, 0x054E, 0x057D, 0x0403, 0x078D, 0x05AE, 0x042D,
+ 0x0483, 0x079D, 0x0D7F, 0x0482, 0x0611, 0x056E, 0x0516, 0x05BE,
+ 0x0535, 0x044E, 0x05AF, 0x0DED, 0x042F, 0x0492, 0x058E, 0x078F,
+ 0x0412, 0x057E, 0x053E, 0x0F1F, 0x073D, 0x0601, 0x0501, 0x075D,
+ 0x059E, 0x05CD, 0x053F, 0x054F, 0x055E, 0x055D, 0x0421, 0x074D,
+ 0x051F, 0x072F, 0x0781, 0x0411, 0x0D6F, 0x077E, 0x0487, 0x070E,
+ 0x070F, 0x072D, 0x058F, 0x078E, 0x079E, 0x052E, 0x0413, 0x072E,
+ 0x071D, 0x052F, 0x055F, 0x073E, 0x0417, 0x0453, 0x060E, 0x0622,
+ 0x0683, 0x0702, 0x070D, 0x071E, 0x076F, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_10x6 {
+ 10, 6,
+ { 325, 199 },
+ { 922, 381 },
+ { 0, 78 },
+ { percentile_arr_10x6_0, percentile_arr_10x6_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 8)
+static const uint16_t percentile_arr_10x8_0[400] {
+ 0x0154, 0xAB34, 0xAD44, 0x8308, 0x7866, 0x7B64, 0x79A4, 0x7975,
+ 0x686A, 0x6908, 0xC514, 0x6174, 0x6128, 0x6118, 0x5B54, 0x5163,
+ 0xF856, 0x50F5, 0x986F, 0xDD34, 0x48FE, 0x4972, 0x48E6, 0x4146,
+ 0x48EE, 0x40F3, 0x4AC1, 0x38C6, 0x41E2, 0xBB05, 0x707E, 0x38D6,
+ 0x3927, 0x6B14, 0x384B, 0x3948, 0x3153, 0x385A, 0x3134, 0x6B15,
+ 0x39F2, 0x30CF, 0x3143, 0x91D2, 0x31C3, 0x60EF, 0x5973, 0x3076,
+ 0x28D3, 0x3261, 0x2875, 0x28DE, 0x290C, 0x51E3, 0x28A7, 0x20E3,
+ 0x2962, 0x2B06, 0x2917, 0x483B, 0x20B6, 0x2D24, 0x206E, 0x285F,
+ 0x20B7, 0x2936, 0x4047, 0x2037, 0x20DF, 0x28BF, 0x21B4, 0x21B3,
+ 0x1D08, 0x2027, 0x404F, 0x3846, 0x2116, 0x187F, 0x1879, 0x2285,
+ 0x1A29, 0x3915, 0x4873, 0x1955, 0x3114, 0x1B44, 0x2165, 0x107A,
+ 0x1956, 0x6137, 0x1106, 0x3145, 0x1B21, 0x19D3, 0x12AD, 0x1B41,
+ 0x1AD1, 0x1126, 0x18F2, 0x282B, 0x40E5, 0x20D5, 0x2A0A, 0x284A,
+ 0x1286, 0x1295, 0x121A, 0x2A0B, 0x321B, 0x122D, 0x10FD, 0x13A1,
+ 0x32A2, 0x12E1, 0x1164, 0x13C1, 0x124D, 0x1239, 0x4504, 0x10C7,
+ 0x22F1, 0x11F1, 0x0AC2, 0x2125, 0x1225, 0x0B04, 0x1107, 0x1069,
+ 0x1A19, 0x13BF, 0x2A96, 0x08D2, 0x1271, 0x0952, 0x2BDF, 0x0B31,
+ 0x1251, 0x2124, 0x0B13, 0x12BD, 0x1233, 0x13EE, 0x2144, 0x0B16,
+ 0x0A15, 0x18E2, 0x08DD, 0x1097, 0x0857, 0x0B24, 0x0AA5, 0x12A3,
+ 0x11C2, 0x11D1, 0x10CE, 0x0865, 0x123D, 0x08B3, 0x0B51, 0x1971,
+ 0x0A41, 0x0A06, 0x1039, 0x080A, 0x0B22, 0x0923, 0x0836, 0x08C3,
+ 0x0A1F, 0x1072, 0x080B, 0x0935, 0x0855, 0x18A6, 0x0A42, 0x1133,
+ 0x0A83, 0x0A09, 0x0ACD, 0x0A2E, 0x0887, 0x083A, 0x10C5, 0x085E,
+ 0x13B1, 0x087D, 0x0819, 0x0A9F, 0x0049, 0x08F1, 0x0BEF, 0x1161,
+ 0x0B42, 0x09E1, 0x0A05, 0x0904, 0x12AE, 0x029E, 0x0A31, 0x09FF,
+ 0x0951, 0x0859, 0x001A, 0x082F, 0x0B81, 0x08B5, 0x0A35, 0x082A,
+ 0x08ED, 0x1142, 0x1262, 0x0B32, 0x08A5, 0x12D2, 0x03DD, 0x0B07,
+ 0x18AE, 0x083F, 0x00AF, 0x0AB3, 0x086D, 0x0287, 0x0A93, 0x025D,
+ 0x0816, 0x13FF, 0x0A8D, 0x005D, 0x08D1, 0x0392, 0x0845, 0x0AC3,
+ 0x08C2, 0x01A3, 0x0AB1, 0x09A2, 0x005B, 0x0B93, 0x02B2, 0x1086,
+ 0x001B, 0x0863, 0x0216, 0x0AA1, 0x0896, 0x0A8F, 0x084E, 0x0A8E,
+ 0x0A53, 0x0026, 0x0A26, 0x0382, 0x0807, 0x0862, 0x0029, 0x0871,
+ 0x00BD, 0x0835, 0x024E, 0x0806, 0x0941, 0x0895, 0x03AF, 0x0A13,
+ 0x0932, 0x03ED, 0x0BFD, 0x0207, 0x0B83, 0x0993, 0x09B1, 0x03CD,
+ 0x0A3E, 0x03FE, 0x0A21, 0x0015, 0x0B11, 0x0A43, 0x00E1, 0x136F,
+ 0x00BE, 0x00A2, 0x0842, 0x0043, 0x0825, 0x082E, 0x0A2A, 0x03DE,
+ 0x0BA2, 0x0122, 0x0BCF, 0x004D, 0x0323, 0x09C1, 0x0292, 0x083E,
+ 0x0252, 0x0017, 0x0A72, 0x00CD, 0x0182, 0x0A63, 0x0131, 0x09B2,
+ 0x0303, 0x0902, 0x0053, 0x035F, 0x0A32, 0x003D, 0x0992, 0x0A2F,
+ 0x03B2, 0x0ABE, 0x009F, 0x0183, 0x0312, 0x08B1, 0x0B02, 0x0A17,
+ 0x0B7F, 0x0333, 0x0297, 0x0A23, 0x020F, 0x0282, 0x0851, 0x0822,
+ 0x03CE, 0x01EE, 0x000E, 0x08B2, 0x0083, 0x0A1D, 0x00A3, 0x0222,
+ 0x088F, 0x0112, 0x029D, 0x0092, 0x0A3F, 0x0391, 0x089E, 0x0301,
+ 0x01FD, 0x09BF, 0x01CE, 0x0852, 0x01FE, 0x0013, 0x0903, 0x088E,
+ 0x037E, 0x021E, 0x01EF, 0x095F, 0x016F, 0x09DE, 0x03BE, 0x020E,
+ 0x0113, 0x01DF, 0x080F, 0x020D, 0x0833, 0x03AE, 0x0032, 0x03BD,
+ 0x0823, 0x001E, 0x01AF, 0x0203, 0x034F, 0x0093, 0x0A81, 0x036E,
+ 0x0291, 0x038E, 0x0A01, 0x001F, 0x017F, 0x01CF, 0x017E, 0x0202,
+ 0x0BAD, 0x0211, 0x035D, 0x035E, 0x039F, 0x0212, 0x032E, 0x033F,
+ 0x034D, 0x034E, 0x036D, 0x032F, 0x033E, 0x037D, 0x038F, 0x039E
+};
+
+static const uint16_t percentile_arr_10x8_1[221] {
+ 0x0621, 0xDFAE, 0x2443, 0x54C2, 0x37CD, 0x1CF1, 0xFCA3, 0x14D2,
+ 0x2D32, 0x5551, 0x7DDF, 0x5C33, 0x15D1, 0x3462, 0x24B3, 0x7452,
+ 0x5FBE, 0x6472, 0x65A2, 0x1D06, 0x445D, 0x15EF, 0x0E31, 0x1D71,
+ 0x343E, 0x0D42, 0x0CDD, 0x1F01, 0x4691, 0x1435, 0x0E82, 0x0DFF,
+ 0x17DD, 0x0D22, 0x24B2, 0x1603, 0x04B5, 0x24AE, 0x060D, 0x2D13,
+ 0x0C7D, 0x0496, 0x17BD, 0x1F4F, 0x1F7D, 0x1486, 0x0593, 0x1C16,
+ 0x0C07, 0x15FE, 0x041F, 0x14D1, 0x0C9F, 0x0E81, 0x0D15, 0x27AF,
+ 0x0C2E, 0x0D23, 0x176E, 0x0FAD, 0x1C06, 0x1561, 0x0DB1, 0x040B,
+ 0x1C4E, 0x0D83, 0x1711, 0x0C42, 0x0C71, 0x1C1A, 0x0D25, 0x04A2,
+ 0x0C45, 0x076D, 0x0F9F, 0x075F, 0x0E12, 0x046D, 0x048F, 0x1D92,
+ 0x0602, 0x0C39, 0x174E, 0x0C51, 0x0CA1, 0x075E, 0x05C1, 0x14BD,
+ 0x0D31, 0x0423, 0x0F3F, 0x0495, 0x0C93, 0x049E, 0x0D05, 0x04E1,
+ 0x0DEE, 0x0415, 0x04B1, 0x0503, 0x0CCD, 0x042F, 0x0DCF, 0x044D,
+ 0x0541, 0x1582, 0x05DE, 0x0D01, 0x0487, 0x040A, 0x0516, 0x0CA5,
+ 0x05FD, 0x05BF, 0x057D, 0x0DA1, 0x0426, 0x040F, 0x071F, 0x0613,
+ 0x0432, 0x0D12, 0x043D, 0x0425, 0x0461, 0x061D, 0x0D21, 0x0591,
+ 0x079D, 0x048D, 0x0429, 0x0C49, 0x04C1, 0x042A, 0x040E, 0x0485,
+ 0x0511, 0x0405, 0x0502, 0x0441, 0x0C19, 0x0692, 0x0535, 0x058F,
+ 0x041D, 0x059F, 0x072D, 0x04AD, 0x049D, 0x05CE, 0x048E, 0x0C31,
+ 0x057F, 0x078D, 0x0409, 0x041E, 0x05AE, 0x0611, 0x058E, 0x05DD,
+ 0x05CD, 0x056E, 0x0483, 0x073D, 0x054E, 0x0D9E, 0x0402, 0x0491,
+ 0x040D, 0x056F, 0x042D, 0x0581, 0x0421, 0x057E, 0x0781, 0x053E,
+ 0x0482, 0x078F, 0x0413, 0x052E, 0x0601, 0x0422, 0x0492, 0x055E,
+ 0x05BE, 0x0F9E, 0x072F, 0x074D, 0x0412, 0x070F, 0x075D, 0x05BD,
+ 0x051F, 0x071D, 0x073E, 0x077E, 0x0403, 0x0411, 0x078E, 0x055D,
+ 0x05AF, 0x05ED, 0x052F, 0x053F, 0x070D, 0x070E, 0x072E, 0x054F,
+ 0x0417, 0x041B, 0x0453, 0x055F, 0x060E, 0x0622, 0x0683, 0x068D,
+ 0x0702, 0x071E, 0x076F, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_10x8 =
+{
+ 10, 8,
+ { 400, 221 },
+ { 1119, 376 },
+ { 0, 52 },
+ { percentile_arr_10x8_0, percentile_arr_10x8_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 10)
+static const uint16_t percentile_arr_10x10_0[453] {
+ 0x0334, 0x9514, 0x8954, 0x806A, 0x6F14, 0x6724, 0x6108, 0x6364,
+ 0x5175, 0x5D44, 0x5866, 0x5118, 0x5308, 0xA179, 0x5128, 0xF534,
+ 0x49A4, 0x5354, 0x9174, 0x486F, 0x48EA, 0x40F3, 0x4963, 0x414A,
+ 0xF8F9, 0x3984, 0x4172, 0x387E, 0x405A, 0x38DA, 0x38F5, 0x9B05,
+ 0x30EE, 0x32C1, 0x3261, 0x3D08, 0x31E2, 0x3056, 0x292B, 0x3146,
+ 0x3127, 0x3315, 0x58CA, 0x58E6, 0x290C, 0x3314, 0x8134, 0x28E3,
+ 0x28FE, 0x2948, 0x28C6, 0x78DE, 0x28BB, 0x68D6, 0x286E, 0x2173,
+ 0x2962, 0x21D2, 0x205F, 0x49F2, 0x2917, 0x2306, 0x207F, 0x404F,
+ 0x2153, 0x2943, 0x20CF, 0x21C3, 0x2073, 0x20D3, 0x2136, 0x183B,
+ 0x430A, 0x40A7, 0x18B6, 0x2079, 0x2309, 0x2075, 0x184B, 0x20EF,
+ 0x187A, 0x7837, 0x1B19, 0x20AB, 0x18BA, 0x20B7, 0x1994, 0x19E3,
+ 0x21B4, 0x49B3, 0x38BF, 0x193B, 0x1876, 0x182B, 0x30F2, 0x193A,
+ 0x1827, 0x1965, 0x1914, 0x184A, 0x4047, 0x1916, 0x1285, 0x1937,
+ 0x122D, 0x1915, 0x1321, 0x1955, 0x1046, 0x191B, 0x2106, 0x2919,
+ 0x1344, 0x1524, 0x12E1, 0x3926, 0x10E5, 0x2295, 0x1159, 0x1145,
+ 0x10DF, 0x124D, 0x1271, 0x092A, 0x2169, 0x1704, 0x22A2, 0x1164,
+ 0x13EE, 0x12F1, 0x0AD1, 0x128A, 0x110A, 0x11D3, 0x1286, 0x115A,
+ 0x2BA1, 0x0BBF, 0x3956, 0x2A89, 0x12AD, 0x10E9, 0x0B41, 0x1A29,
+ 0x2225, 0x08FD, 0x1107, 0x08D5, 0x191A, 0x1125, 0x1A96, 0x0B04,
+ 0x18D9, 0x2B16, 0x11F1, 0x0A33, 0x0924, 0x131A, 0x1149, 0x1324,
+ 0x0BEF, 0x0A99, 0x08CB, 0x123D, 0x1331, 0x0BDF, 0x0872, 0x22A3,
+ 0x0AC2, 0x1144, 0x0D04, 0x08D2, 0x08CE, 0x0AA9, 0x0A9A, 0x0B13,
+ 0x1251, 0x0865, 0x1069, 0x0897, 0x1215, 0x18B3, 0x1A62, 0x08C7,
+ 0x185E, 0x10E2, 0x0AA5, 0x21FF, 0x090B, 0x0952, 0x09E1, 0x0A42,
+ 0x08F1, 0x0A06, 0x0B22, 0x087D, 0x1139, 0x021F, 0x122E, 0x082F,
+ 0x09C2, 0x0887, 0x0A0A, 0x03C1, 0x0929, 0x0A5D, 0x0A83, 0x0BFF,
+ 0x0935, 0x085B, 0x0104, 0x08DD, 0x0923, 0x083F, 0x0241, 0x09D1,
+ 0x0A39, 0x0863, 0x0A8B, 0x08A6, 0x008B, 0x1133, 0x13B1, 0x089B,
+ 0x0AB3, 0x0036, 0x0BDD, 0x08ED, 0x0857, 0x0971, 0x0219, 0x1235,
+ 0x0AB1, 0x0ACD, 0x036F, 0x0A31, 0x08AA, 0x003A, 0x08C3, 0x0A05,
+ 0x02BD, 0x0B92, 0x0B07, 0x12B2, 0x08C5, 0x0B51, 0x0381, 0x0A8D,
+ 0x01A3, 0x0896, 0x0855, 0x0BFD, 0x005D, 0x0BFE, 0x023E, 0x08AF,
+ 0x00B9, 0x0A93, 0x00B5, 0x0862, 0x0A0B, 0x0A09, 0x0A72, 0x0332,
+ 0x0AA1, 0x08C9, 0x024E, 0x1382, 0x0951, 0x00A5, 0x0A2A, 0x0059,
+ 0x0A9E, 0x0B42, 0x004E, 0x0942, 0x03ED, 0x09B2, 0x02D2, 0x0849,
+ 0x0035, 0x0216, 0x0961, 0x0BAF, 0x00AE, 0x0826, 0x0287, 0x0A1A,
+ 0x0393, 0x0221, 0x09A2, 0x086D, 0x0226, 0x0871, 0x0039, 0x082A,
+ 0x08C2, 0x08E1, 0x0845, 0x0207, 0x0B23, 0x0015, 0x00D1, 0x0B83,
+ 0x037F, 0x0252, 0x08A9, 0x0099, 0x0A13, 0x0053, 0x0807, 0x03CD,
+ 0x0BDE, 0x0016, 0x089A, 0x0232, 0x035F, 0x0A8E, 0x0AC3, 0x022F,
+ 0x0263, 0x0829, 0x004D, 0x0132, 0x0806, 0x0311, 0x01B1, 0x0941,
+ 0x0086, 0x000B, 0x1122, 0x0025, 0x0842, 0x00BD, 0x0BCF, 0x03A2,
+ 0x0043, 0x0B03, 0x0895, 0x0A8F, 0x008A, 0x09EF, 0x0253, 0x0A1B,
+ 0x0182, 0x0243, 0x0A92, 0x00CD, 0x083E, 0x030B, 0x0223, 0x081A,
+ 0x0A9F, 0x0193, 0x00BE, 0x0017, 0x0931, 0x0391, 0x037E, 0x09C1,
+ 0x0312, 0x0333, 0x03B2, 0x083D, 0x08B1, 0x00B2, 0x002E, 0x021D,
+ 0x0A9D, 0x0192, 0x02AE, 0x0102, 0x0022, 0x081B, 0x0222, 0x009E,
+ 0x021E, 0x000A, 0x089F, 0x0217, 0x0BCE, 0x0052, 0x020F, 0x0A97,
+ 0x0282, 0x008E, 0x0A3F, 0x01FD, 0x00A3, 0x0019, 0x08A2, 0x0301,
+ 0x036E, 0x01FE, 0x03BE, 0x0ABE, 0x01CE, 0x0302, 0x029B, 0x0051,
+ 0x0883, 0x008F, 0x0BAE, 0x01DF, 0x0183, 0x0912, 0x000E, 0x020D,
+ 0x01EE, 0x0B4F, 0x0033, 0x0103, 0x020E, 0x0832, 0x01AF, 0x0913,
+ 0x01DE, 0x0203, 0x001E, 0x0092, 0x0093, 0x000F, 0x015F, 0x0291,
+ 0x0281, 0x0813, 0x001F, 0x01CF, 0x033F, 0x0023, 0x01BF, 0x0202,
+ 0x016F, 0x017E, 0x03AD, 0x0201, 0x034E, 0x0BBD, 0x036D, 0x017F,
+ 0x0211, 0x038E, 0x0212, 0x032E, 0x034D, 0x035E, 0x037D, 0x039E,
+ 0x032F, 0x033E, 0x035D, 0x038F, 0x039F
+};
+
+static const uint16_t percentile_arr_10x10_1[234] {
+ 0x07CD, 0x6E21, 0x24F1, 0x8443, 0xD7AE, 0x24C2, 0x1C62, 0xCCA3,
+ 0x1C33, 0xFDEF, 0x2532, 0x55DF, 0x1472, 0x6C3E, 0x14D2, 0x34DD,
+ 0x1452, 0x745D, 0x4D51, 0x8DD1, 0x247D, 0x75FF, 0x0CB3, 0x17BE,
+ 0x6CAE, 0x17DD, 0x1571, 0x3D06, 0x4E31, 0x0DA2, 0x67BD, 0x160D,
+ 0x2C4E, 0x0D22, 0x176E, 0x3CB2, 0x142E, 0x4DFE, 0x0F4F, 0x1435,
+ 0x0F01, 0x0D42, 0x0F7D, 0x0CB5, 0x1E03, 0x149F, 0x1C96, 0x141F,
+ 0x14B9, 0x0FAF, 0x0439, 0x0E91, 0x2682, 0x1D13, 0x1FAD, 0x0407,
+ 0x3471, 0x0C86, 0x0F6D, 0x0D15, 0x0D61, 0x040B, 0x0C6D, 0x0C16,
+ 0x0C9A, 0x0D0A, 0x0593, 0x0CD1, 0x248F, 0x0C2F, 0x3C42, 0x1523,
+ 0x0445, 0x0E81, 0x0CA2, 0x1525, 0x0406, 0x1C8A, 0x0C1A, 0x04BD,
+ 0x0F5E, 0x0F3F, 0x1F4E, 0x0E1D, 0x0423, 0x0DCF, 0x044D, 0x0D92,
+ 0x0583, 0x0DB1, 0x1449, 0x15EE, 0x0F5F, 0x079F, 0x0D19, 0x0409,
+ 0x04CD, 0x05FD, 0x143D, 0x0612, 0x0D03, 0x0D82, 0x04B1, 0x0C95,
+ 0x0C2A, 0x049E, 0x05AF, 0x0D31, 0x05BE, 0x04E1, 0x0D05, 0x0516,
+ 0x0711, 0x05C1, 0x0509, 0x0D41, 0x0493, 0x048E, 0x0602, 0x05BF,
+ 0x0CA5, 0x0529, 0x0535, 0x0D12, 0x0539, 0x0451, 0x0C29, 0x071F,
+ 0x040A, 0x0F3D, 0x0432, 0x059F, 0x0425, 0x0C99, 0x05DE, 0x05CE,
+ 0x0C0F, 0x0489, 0x051A, 0x0501, 0x0415, 0x057F, 0x0431, 0x0E13,
+ 0x040D, 0x041D, 0x075D, 0x0C53, 0x0502, 0x04C1, 0x049D, 0x0426,
+ 0x040E, 0x05A1, 0x055F, 0x0781, 0x0591, 0x04A9, 0x048B, 0x0D8E,
+ 0x052E, 0x0412, 0x0521, 0x0405, 0x04AD, 0x074D, 0x0611, 0x077E,
+ 0x078F, 0x078D, 0x048D, 0x041E, 0x0487, 0x0461, 0x0C85, 0x05ED,
+ 0x0402, 0x0483, 0x0419, 0x0511, 0x0491, 0x0482, 0x059E, 0x068D,
+ 0x055D, 0x072E, 0x05DD, 0x054E, 0x0441, 0x0422, 0x052F, 0x057D,
+ 0x072D, 0x079D, 0x0CA1, 0x072F, 0x079E, 0x0581, 0x042D, 0x055E,
+ 0x0601, 0x0413, 0x0692, 0x0403, 0x051F, 0x053F, 0x054F, 0x05CD,
+ 0x070F, 0x071D, 0x05AE, 0x05BD, 0x0492, 0x056E, 0x0411, 0x0417,
+ 0x041B, 0x0421, 0x053E, 0x056F, 0x057E, 0x058F, 0x060E, 0x0622,
+ 0x0683, 0x0702, 0x070D, 0x070E, 0x071E, 0x073E, 0x076F, 0x078E,
+ 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_10x10 {
+ 10, 10,
+ { 453, 234 },
+ { 1095, 472 },
+ { 0, 70 },
+ { percentile_arr_10x10_0, percentile_arr_10x10_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (12 * 10)
+static const uint16_t percentile_arr_12x10_0[491] {
+ 0x0334, 0x9954, 0x8514, 0x7128, 0x6364, 0xC174, 0x5D34, 0x5866,
+ 0x5975, 0x5354, 0xAF14, 0x506A, 0x5108, 0x5724, 0x5308, 0x4544,
+ 0x4918, 0x4064, 0x49E2, 0x4179, 0x8163, 0x4054, 0xF81C, 0x394A,
+ 0x38F3, 0x4172, 0x38F5, 0xA06F, 0x68EA, 0x69F2, 0x3134, 0x31A4,
+ 0x305A, 0x68DA, 0x3056, 0x3146, 0x31F5, 0x3148, 0x5A61, 0x32C1,
+ 0x31D2, 0x307E, 0x29E3, 0x30E6, 0x59C3, 0x2984, 0x29B6, 0x28F9,
+ 0x5204, 0x28EE, 0x50CA, 0x2997, 0x48C6, 0x4838, 0x2953, 0x200C,
+ 0x2943, 0x2173, 0x2D08, 0x4162, 0x29B4, 0x2314, 0x21B3, 0x212B,
+ 0x210C, 0x48E3, 0x60DE, 0x205F, 0x20FE, 0x2028, 0x21A6, 0x404F,
+ 0x20D6, 0x2214, 0x2127, 0x1873, 0x40CF, 0x206E, 0x1B09, 0x21C6,
+ 0x2075, 0x19D5, 0x2305, 0x18D3, 0x2076, 0x1804, 0x230A, 0x304B,
+ 0x20BB, 0x18B6, 0x1936, 0x1B19, 0x3037, 0x187F, 0x18A7, 0x1B85,
+ 0x30BA, 0x183B, 0x1027, 0x18EF, 0x1B21, 0x1879, 0x10AB, 0x1917,
+ 0x1114, 0x18BF, 0x1074, 0x1994, 0x2847, 0x111B, 0x28F2, 0x11E5,
+ 0x19A7, 0x113A, 0x1046, 0x28B7, 0x207A, 0x182B, 0x1155, 0x104A,
+ 0x1344, 0x293B, 0x11D3, 0x2014, 0x1044, 0x1018, 0x13A1, 0x1315,
+ 0x2524, 0x20DF, 0x10E5, 0x1126, 0x12A2, 0x1824, 0x2271, 0x11F1,
+ 0x2964, 0x12D1, 0x115A, 0x092A, 0x2341, 0x1A2D, 0x12E1, 0x090A,
+ 0x13BF, 0x0A4D, 0x2119, 0x0BC1, 0x1233, 0x1A8A, 0x2008, 0x1159,
+ 0x1A89, 0x08D5, 0x1156, 0x0834, 0x13EE, 0x1169, 0x1187, 0x1AA3,
+ 0x1229, 0x1331, 0x0A85, 0x0937, 0x1704, 0x08FD, 0x2124, 0x0B13,
+ 0x1251, 0x0AAD, 0x082C, 0x091A, 0x18D9, 0x0A99, 0x1848, 0x18E9,
+ 0x0B95, 0x1144, 0x0AF1, 0x1A25, 0x131A, 0x09C5, 0x0986, 0x1BDF,
+ 0x0B24, 0x0965, 0x1262, 0x0949, 0x0872, 0x09C2, 0x12C2, 0x0916,
+ 0x085E, 0x0B06, 0x08CB, 0x08C7, 0x1242, 0x1BEF, 0x0A9A, 0x1152,
+ 0x08B3, 0x0AA9, 0x090B, 0x08D2, 0x1B22, 0x0B04, 0x0865, 0x0A15,
+ 0x1286, 0x0A83, 0x0A95, 0x09D1, 0x0A06, 0x0196, 0x1139, 0x0A3D,
+ 0x0933, 0x13B1, 0x0123, 0x0D04, 0x08E2, 0x122E, 0x08A6, 0x00CE,
+ 0x0A31, 0x1241, 0x0B51, 0x1057, 0x1171, 0x007D, 0x1145, 0x0A0A,
+ 0x0129, 0x09FF, 0x089B, 0x085B, 0x0063, 0x0AB1, 0x0A1F, 0x0A5D,
+ 0x0AA5, 0x0036, 0x0904, 0x0B86, 0x0A8B, 0x0897, 0x11E1, 0x0332,
+ 0x083F, 0x0A19, 0x02B3, 0x0859, 0x08C3, 0x0855, 0x11B5, 0x01A5,
+ 0x0AB2, 0x0392, 0x10DD, 0x09A3, 0x00ED, 0x0907, 0x1161, 0x002F,
+ 0x0887, 0x0216, 0x0ABD, 0x0B81, 0x0A93, 0x0A21, 0x003A, 0x0ACD,
+ 0x0AA1, 0x0A35, 0x0272, 0x0BDD, 0x03FE, 0x0BAF, 0x0869, 0x0213,
+ 0x088B, 0x020B, 0x00B5, 0x1035, 0x08F1, 0x0151, 0x0A4E, 0x0239,
+ 0x0BA2, 0x00AA, 0x0896, 0x0382, 0x0A08, 0x0A05, 0x0A09, 0x0142,
+ 0x086D, 0x004E, 0x0B23, 0x0106, 0x0807, 0x036F, 0x0995, 0x03FD,
+ 0x08AF, 0x08C5, 0x0062, 0x0053, 0x0B42, 0x0826, 0x021A, 0x01A2,
+ 0x09B1, 0x00C9, 0x09B2, 0x0045, 0x0207, 0x08B9, 0x00A5, 0x0AD2,
+ 0x0095, 0x003E, 0x0A32, 0x0383, 0x0849, 0x0135, 0x029E, 0x0A26,
+ 0x023E, 0x0BFF, 0x0A52, 0x0311, 0x001B, 0x0915, 0x0A8D, 0x0223,
+ 0x022A, 0x0BED, 0x0086, 0x0A96, 0x0222, 0x035F, 0x0A43, 0x085D,
+ 0x0303, 0x0393, 0x0A63, 0x082A, 0x037F, 0x0932, 0x0043, 0x0292,
+ 0x03CD, 0x0BDE, 0x009F, 0x0125, 0x08A9, 0x0253, 0x0015, 0x0192,
+ 0x0A17, 0x08C2, 0x0316, 0x00D1, 0x0282, 0x0871, 0x0312, 0x0122,
+ 0x0A9F, 0x02AE, 0x0006, 0x0A8E, 0x08E1, 0x0016, 0x0B0B, 0x00AE,
+ 0x0025, 0x0193, 0x0AC3, 0x0017, 0x0307, 0x00BD, 0x08BE, 0x0039,
+ 0x0BB2, 0x021B, 0x01FD, 0x084D, 0x03CE, 0x00A3, 0x0302, 0x0BCF,
+ 0x0033, 0x0391, 0x028F, 0x0852, 0x0287, 0x008A, 0x0333, 0x080B,
+ 0x0131, 0x01C1, 0x037E, 0x0A0F, 0x00B1, 0x002E, 0x0099, 0x0902,
+ 0x009A, 0x003D, 0x0982, 0x0301, 0x00CD, 0x0941, 0x0042, 0x0183,
+ 0x029D, 0x08A2, 0x021D, 0x001A, 0x0A97, 0x01EF, 0x01CE, 0x0051,
+ 0x0BAE, 0x022F, 0x03BE, 0x021E, 0x000A, 0x09DF, 0x0029, 0x020D,
+ 0x02BE, 0x029B, 0x09EE, 0x00B2, 0x0912, 0x036E, 0x009E, 0x0022,
+ 0x0019, 0x0892, 0x0032, 0x01FE, 0x0083, 0x023F, 0x0B96, 0x000E,
+ 0x008F, 0x0113, 0x0103, 0x001E, 0x0A0E, 0x0013, 0x008E, 0x0281,
+ 0x09AF, 0x017E, 0x0203, 0x016F, 0x0291, 0x0023, 0x0093, 0x03BD,
+ 0x001F, 0x01CF, 0x01DE, 0x0201, 0x01BF, 0x0B4F, 0x000F, 0x0202,
+ 0x037D, 0x038E, 0x0211, 0x0212, 0x034E, 0x039F, 0x03AD, 0x015F,
+ 0x017F, 0x032E, 0x033F, 0x034D, 0x035E, 0x036D, 0x032F, 0x033E,
+ 0x035D, 0x038F, 0x039E
+};
+
+static const uint16_t percentile_arr_12x10_1[240] {
+ 0x0621, 0xA443, 0xFCC2, 0x3CA3, 0x1D32, 0x14F1, 0x7462, 0x1433,
+ 0x27CD, 0x2571, 0x57AE, 0x5DD1, 0x64B3, 0x44D2, 0x2C72, 0x25A2,
+ 0x1E31, 0x55DF, 0x4C52, 0x1DEF, 0x0D51, 0x3C5D, 0x3C3E, 0x74DD,
+ 0x347D, 0x27BE, 0x5CB5, 0x17DD, 0x2C14, 0x0CAE, 0x24B2, 0x15FF,
+ 0x2701, 0x0D42, 0x1FBD, 0x0C35, 0x1603, 0x060D, 0x1D93, 0x0C96,
+ 0x1C07, 0x1522, 0x0D06, 0x0F4F, 0x0C9F, 0x1F6E, 0x0D86, 0x0C2E,
+ 0x1DFE, 0x0682, 0x1E91, 0x0F7D, 0x0C86, 0x040B, 0x1513, 0x044E,
+ 0x14D1, 0x0C39, 0x14B9, 0x1C71, 0x05B1, 0x0C1F, 0x0681, 0x1445,
+ 0x0C16, 0x0D95, 0x1583, 0x0D61, 0x0FAD, 0x1442, 0x048F, 0x0D0A,
+ 0x049A, 0x0F6D, 0x146D, 0x0C2F, 0x0D25, 0x0406, 0x0C1A, 0x0D23,
+ 0x0612, 0x0FAF, 0x0F11, 0x0592, 0x0515, 0x14E1, 0x0602, 0x048A,
+ 0x0E1D, 0x0CBD, 0x0F9F, 0x0423, 0x075E, 0x174E, 0x0426, 0x0404,
+ 0x0C22, 0x0CA2, 0x0DEE, 0x0CA5, 0x0F3F, 0x05C1, 0x0CCD, 0x0503,
+ 0x044D, 0x0D16, 0x0449, 0x0D82, 0x0613, 0x0585, 0x0519, 0x0C95,
+ 0x075F, 0x0D35, 0x04B1, 0x0509, 0x0531, 0x0DA1, 0x049E, 0x040A,
+ 0x05CF, 0x0D41, 0x0415, 0x0692, 0x05FD, 0x0C25, 0x04A1, 0x0529,
+ 0x0591, 0x0C93, 0x057F, 0x04C1, 0x0512, 0x051A, 0x078D, 0x0451,
+ 0x0C0F, 0x0487, 0x0611, 0x0432, 0x042A, 0x05AF, 0x0461, 0x072D,
+ 0x0409, 0x0405, 0x0D39, 0x05DE, 0x048E, 0x0499, 0x0483, 0x04A9,
+ 0x0491, 0x042D, 0x049D, 0x0429, 0x040E, 0x05AE, 0x0521, 0x043D,
+ 0x0581, 0x05DD, 0x0492, 0x0CAD, 0x041E, 0x058F, 0x071F, 0x072F,
+ 0x0419, 0x073D, 0x057D, 0x0511, 0x05CE, 0x041D, 0x0485, 0x056E,
+ 0x0412, 0x0431, 0x05BF, 0x0441, 0x054E, 0x0489, 0x0421, 0x0502,
+ 0x0408, 0x040D, 0x051F, 0x059F, 0x073E, 0x078F, 0x0482, 0x079D,
+ 0x0C02, 0x05BE, 0x048B, 0x0411, 0x0505, 0x057E, 0x052E, 0x074D,
+ 0x077E, 0x054F, 0x0601, 0x055F, 0x068D, 0x070D, 0x070F, 0x071E,
+ 0x072E, 0x05CD, 0x0403, 0x0501, 0x055D, 0x059E, 0x0781, 0x0413,
+ 0x0417, 0x041B, 0x0453, 0x048D, 0x052F, 0x053E, 0x053F, 0x055E,
+ 0x056F, 0x058E, 0x05BD, 0x05ED, 0x060E, 0x0622, 0x0683, 0x0702,
+ 0x070E, 0x071D, 0x075D, 0x076F, 0x078E, 0x079E, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_12x10 =
+{
+ 12, 10,
+ { 491, 240 },
+ { 1099, 341 },
+ { 0, 23 },
+ { percentile_arr_12x10_0, percentile_arr_12x10_1 }
+};
+#endif
+
+#if ASTCENC_BLOCK_MAX_TEXELS >= (12 * 12)
+static const uint16_t percentile_arr_12x12_0[529] {
+ 0x0334, 0xF534, 0x8514, 0x8954, 0x7F14, 0xFB54, 0x7B08, 0x7128,
+ 0x7974, 0x6179, 0x6B64, 0x6908, 0x606A, 0x6724, 0xB544, 0xB066,
+ 0xA14A, 0x5118, 0x9975, 0x51F9, 0x981C, 0x49CA, 0x4854, 0x886F,
+ 0x88D4, 0x48EE, 0x41E2, 0x4163, 0x40F3, 0x4261, 0x4064, 0x407E,
+ 0x385A, 0x42C1, 0x4172, 0x38EA, 0x3946, 0x78CF, 0xA056, 0x38DE,
+ 0x3D08, 0x38F9, 0x3B14, 0x38FE, 0xA134, 0x38B8, 0x31A4, 0x71D2,
+ 0x60DA, 0x39C3, 0x99BA, 0x60CA, 0x39F2, 0x30F5, 0x304F, 0x31B6,
+ 0x31F5, 0x3204, 0x3148, 0x305F, 0x2953, 0x3194, 0x3184, 0x310C,
+ 0x889C, 0x300C, 0x2943, 0x30EF, 0x28C6, 0x2997, 0x2838, 0x58E6,
+ 0x20E4, 0x28E3, 0x2873, 0x29E3, 0x2A84, 0x28D3, 0x492B, 0x2962,
+ 0x286E, 0x20BF, 0x21AA, 0x29A6, 0x6A14, 0x2828, 0x89C6, 0x21B3,
+ 0x2305, 0x29B4, 0x2173, 0x2127, 0x20D6, 0x407F, 0x2294, 0x21D9,
+ 0x21D5, 0x2004, 0x404B, 0x18DF, 0x2079, 0x219B, 0x18A8, 0x2385,
+ 0x1936, 0x21AB, 0x188C, 0x1B09, 0x18BA, 0x203B, 0x187A, 0x1875,
+ 0x2344, 0x18BB, 0x18B6, 0x193A, 0x1837, 0x1914, 0x1846, 0x1876,
+ 0x1884, 0x1D24, 0x182B, 0x284A, 0x18A7, 0x18AB, 0x1917, 0x322D,
+ 0x1047, 0x1874, 0x1818, 0x18F2, 0x1164, 0x1B89, 0x2959, 0x1B21,
+ 0x39E5, 0x1827, 0x10F4, 0x18B7, 0x11D3, 0x1A4D, 0x1315, 0x12AD,
+ 0x1AD1, 0x3A71, 0x1319, 0x11A7, 0x2044, 0x2F04, 0x2341, 0x10E5,
+ 0x1155, 0x195A, 0x1024, 0x111B, 0x1251, 0x1233, 0x12E1, 0x13A1,
+ 0x13BF, 0x212A, 0x22A2, 0x113B, 0x23DF, 0x10D5, 0x2399, 0x0814,
+ 0x1126, 0x13EE, 0x1285, 0x10C4, 0x18FD, 0x20D9, 0x0987, 0x1242,
+ 0x29C5, 0x2313, 0x0898, 0x13C1, 0x08C8, 0x11F1, 0x1034, 0x1B24,
+ 0x0B0A, 0x11E9, 0x0808, 0x125D, 0x18E9, 0x0848, 0x1395, 0x0965,
+ 0x123D, 0x2186, 0x1295, 0x18CE, 0x098B, 0x0BEF, 0x1504, 0x082C,
+ 0x0A41, 0x1144, 0x0A89, 0x0956, 0x1331, 0x085E, 0x0B04, 0x128A,
+ 0x12A3, 0x1937, 0x19C2, 0x0952, 0x0872, 0x08B4, 0x1262, 0x1124,
+ 0x1969, 0x1063, 0x0AF1, 0x1225, 0x0894, 0x11C9, 0x18D2, 0x0ACD,
+ 0x0A29, 0x0B06, 0x09B5, 0x18C7, 0x0916, 0x1088, 0x09FF, 0x2206,
+ 0x0A15, 0x08B3, 0x0B51, 0x0A1F, 0x18CB, 0x0AC2, 0x0A2E, 0x1865,
+ 0x08AC, 0x0A31, 0x08A4, 0x138A, 0x0A99, 0x09D1, 0x0A86, 0x189B,
+ 0x0283, 0x0BDD, 0x0ABD, 0x1933, 0x083F, 0x1386, 0x0923, 0x0322,
+ 0x0869, 0x10DD, 0x13B1, 0x082F, 0x087D, 0x11B9, 0x085B, 0x08ED,
+ 0x00C3, 0x08E2, 0x084E, 0x0887, 0x0855, 0x0A0A, 0x0857, 0x0B92,
+ 0x1036, 0x12A5, 0x0293, 0x0945, 0x08A6, 0x0196, 0x19A3, 0x036F,
+ 0x0904, 0x1205, 0x09E1, 0x0381, 0x0971, 0x1219, 0x0BAF, 0x0949,
+ 0x00AF, 0x0AA9, 0x018A, 0x0907, 0x0BFD, 0x003A, 0x0BCD, 0x0AB2,
+ 0x088B, 0x0252, 0x0A4E, 0x03FF, 0x0845, 0x0897, 0x0059, 0x090B,
+ 0x0B42, 0x0807, 0x0A16, 0x0853, 0x0A8D, 0x01B2, 0x0AB1, 0x091A,
+ 0x0195, 0x0A35, 0x00B5, 0x10AA, 0x0115, 0x0A21, 0x0096, 0x0A08,
+ 0x03FE, 0x0B7F, 0x08B9, 0x12B3, 0x023E, 0x0A23, 0x029E, 0x08F1,
+ 0x01A9, 0x0BDE, 0x0843, 0x02D2, 0x0A1A, 0x08C5, 0x0151, 0x0A43,
+ 0x0332, 0x0383, 0x0826, 0x0BED, 0x10C2, 0x00AE, 0x0B82, 0x0213,
+ 0x0232, 0x085D, 0x02A1, 0x101B, 0x035F, 0x0303, 0x0A39, 0x0207,
+ 0x0A53, 0x0142, 0x01A5, 0x082A, 0x0099, 0x0A17, 0x03CF, 0x0906,
+ 0x0125, 0x0A96, 0x0A9A, 0x0209, 0x0393, 0x0961, 0x0131, 0x0A88,
+ 0x0139, 0x099A, 0x0292, 0x0272, 0x0862, 0x08BE, 0x0141, 0x02C3,
+ 0x0886, 0x0039, 0x08A9, 0x01A2, 0x01B1, 0x0851, 0x020B, 0x086D,
+ 0x0312, 0x08CD, 0x020F, 0x0311, 0x0BCE, 0x0135, 0x0006, 0x0849,
+ 0x0132, 0x0A8F, 0x022F, 0x022A, 0x0AAE, 0x0A8E, 0x0263, 0x03A2,
+ 0x083E, 0x009A, 0x021B, 0x0835, 0x0323, 0x0871, 0x0993, 0x0226,
+ 0x0302, 0x0922, 0x0119, 0x0222, 0x021D, 0x0B07, 0x08C9, 0x037E,
+ 0x08BD, 0x0042, 0x00D1, 0x0B33, 0x01C1, 0x0B9A, 0x0282, 0x088A,
+ 0x0182, 0x083D, 0x004D, 0x010A, 0x0A1E, 0x0019, 0x00B2, 0x0999,
+ 0x00A5, 0x0095, 0x0817, 0x0022, 0x031A, 0x0902, 0x00A3, 0x01BF,
+ 0x029F, 0x0816, 0x03B2, 0x0015, 0x0391, 0x0BBE, 0x01FE, 0x1129,
+ 0x002E, 0x01DF, 0x0301, 0x0033, 0x0B6E, 0x00E1, 0x0297, 0x00B1,
+ 0x009F, 0x0B16, 0x000A, 0x001A, 0x0052, 0x080B, 0x030B, 0x029D,
+ 0x0BAE, 0x01FD, 0x020E, 0x00A2, 0x0A3F, 0x0192, 0x0ABE, 0x020D,
+ 0x008F, 0x028B, 0x0083, 0x0025, 0x09EE, 0x01EF, 0x0029, 0x0291,
+ 0x0B4F, 0x0396, 0x0287, 0x008E, 0x0092, 0x0B4E, 0x017E, 0x001E,
+ 0x009E, 0x0103, 0x080F, 0x000E, 0x0113, 0x0203, 0x01CF, 0x0183,
+ 0x01CE, 0x001F, 0x0112, 0x01DE, 0x038E, 0x0832, 0x033E, 0x0212,
+ 0x029B, 0x0023, 0x016F, 0x0201, 0x09AF, 0x0202, 0x0281, 0x035E,
+ 0x034D, 0x037D, 0x03AD, 0x0013, 0x0093, 0x015F, 0x0211, 0x033F,
+ 0x036D, 0x039F, 0x03BD, 0x017F, 0x032E, 0x032F, 0x035D, 0x038F,
+ 0x039E
+};
+
+static const uint16_t percentile_arr_12x12_1[246] {
+ 0x0443, 0xFFCD, 0x2C62, 0x2E21, 0x3CF1, 0x34C2, 0x4CDD, 0x2452,
+ 0xD5DF, 0x1DD1, 0x0FAE, 0x64A3, 0x0C7D, 0x3433, 0x1CD2, 0x2DEF,
+ 0x0C3E, 0x1D71, 0xA472, 0x0D32, 0x54B3, 0x4D51, 0x445D, 0x0E31,
+ 0x1FDD, 0x0DFF, 0x0CAE, 0x45A2, 0x2FBE, 0xA4B9, 0x1C4E, 0x2C9F,
+ 0x160D, 0x0D42, 0x342E, 0x074F, 0x1414, 0x0F6E, 0x0CB2, 0x34B5,
+ 0x0DFE, 0x0D86, 0x1496, 0x1D22, 0x0691, 0x140B, 0x041F, 0x0C35,
+ 0x1D93, 0x1506, 0x1439, 0x0C9A, 0x0F01, 0x2442, 0x0C8F, 0x04D1,
+ 0x1486, 0x0C6D, 0x0513, 0x0C71, 0x0E82, 0x177D, 0x0E03, 0x07BD,
+ 0x0C2F, 0x0D83, 0x07AF, 0x0D61, 0x1407, 0x0DB1, 0x050A, 0x0C94,
+ 0x07AD, 0x0D8A, 0x0C04, 0x0416, 0x0C49, 0x0445, 0x15C1, 0x0C1A,
+ 0x0525, 0x0595, 0x0C8A, 0x075E, 0x0CBD, 0x0681, 0x0F4E, 0x075F,
+ 0x061D, 0x1541, 0x0CB1, 0x0F3F, 0x0406, 0x076D, 0x0DCF, 0x05EE,
+ 0x0D23, 0x0599, 0x0CCD, 0x0711, 0x0C23, 0x079F, 0x0D15, 0x0585,
+ 0x04A2, 0x042A, 0x0D31, 0x05BF, 0x0D92, 0x0C26, 0x043D, 0x0C93,
+ 0x0502, 0x0C15, 0x048B, 0x0D03, 0x0613, 0x0516, 0x0495, 0x0C29,
+ 0x04A5, 0x040F, 0x0425, 0x0539, 0x0D19, 0x04E1, 0x05BE, 0x0422,
+ 0x0432, 0x0C0A, 0x0431, 0x041E, 0x0492, 0x04A9, 0x0582, 0x0529,
+ 0x0487, 0x0C4D, 0x0512, 0x049E, 0x0505, 0x0451, 0x0D7F, 0x0489,
+ 0x0602, 0x05DE, 0x0591, 0x0535, 0x074D, 0x055E, 0x04C1, 0x0612,
+ 0x05DD, 0x05FD, 0x0C61, 0x0521, 0x0484, 0x05CE, 0x0581, 0x0491,
+ 0x051A, 0x04A1, 0x048E, 0x040D, 0x0499, 0x071F, 0x072E, 0x075D,
+ 0x0441, 0x0589, 0x057E, 0x0CAD, 0x0501, 0x054F, 0x0692, 0x0511,
+ 0x049D, 0x0509, 0x056E, 0x040E, 0x0409, 0x0601, 0x048D, 0x0413,
+ 0x053E, 0x0419, 0x072D, 0x0408, 0x0485, 0x042D, 0x041D, 0x05A1,
+ 0x0781, 0x0402, 0x05ED, 0x0C82, 0x0403, 0x057D, 0x05CD, 0x0611,
+ 0x0488, 0x0411, 0x054E, 0x051F, 0x053F, 0x056F, 0x059F, 0x070F,
+ 0x071D, 0x073D, 0x073E, 0x077E, 0x078F, 0x0405, 0x079D, 0x079E,
+ 0x058E, 0x0412, 0x055D, 0x05AE, 0x041B, 0x0421, 0x0453, 0x0417,
+ 0x0483, 0x052E, 0x052F, 0x055F, 0x058F, 0x059E, 0x05AF, 0x05BD,
+ 0x060E, 0x0622, 0x0683, 0x068D, 0x0702, 0x070D, 0x070E, 0x071E,
+ 0x072F, 0x076F, 0x078D, 0x078E, 0x07BF, 0x07CE
+};
+
+static const packed_percentile_table block_pcd_12x12 {
+ 12, 12,
+ { 529, 246 },
+ { 1435, 335 },
+ { 0, 22 },
+ { percentile_arr_12x12_0, percentile_arr_12x12_1 }
+};
+#endif
+
+/**
+ * @brief Fetch the packed percentile table for the given 2D block size.
+ *
+ * @param xdim The block x size.
+ * @param ydim The block y size.
+ *
+ * @return The packed table.
+ */
+static const packed_percentile_table *get_packed_table(
+ int xdim,
+ int ydim
+) {
+ int idx = (ydim << 8) | xdim;
+ switch (idx)
+ {
+#if ASTCENC_BLOCK_MAX_TEXELS >= (4 * 4)
+ case 0x0404: return &block_pcd_4x4;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (5 * 4)
+ case 0x0405: return &block_pcd_5x4;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (5 * 5)
+ case 0x0505: return &block_pcd_5x5;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (6 * 5)
+ case 0x0506: return &block_pcd_6x5;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (6 * 6)
+ case 0x0606: return &block_pcd_6x6;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 5)
+ case 0x0508: return &block_pcd_8x5;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 6)
+ case 0x0608: return &block_pcd_8x6;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (8 * 8)
+ case 0x0808: return &block_pcd_8x8;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 5)
+ case 0x050A: return &block_pcd_10x5;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 6)
+ case 0x060A: return &block_pcd_10x6;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 8)
+ case 0x080A: return &block_pcd_10x8;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (10 * 10)
+ case 0x0A0A: return &block_pcd_10x10;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (12 * 10)
+ case 0x0A0C: return &block_pcd_12x10;
+#endif
+#if ASTCENC_BLOCK_MAX_TEXELS >= (12 * 12)
+ case 0x0C0C: return &block_pcd_12x12;
+#endif
+ }
+
+ // Should never hit this with a valid 2D block size
+ return nullptr;
+}
+
+/* See header for documentation. */
+const float *get_2d_percentile_table(
+ unsigned int xdim,
+ unsigned int ydim
+) {
+ float* unpacked_table = new float[WEIGHTS_MAX_BLOCK_MODES];
+ const packed_percentile_table *apt = get_packed_table(xdim, ydim);
+
+ // Set the default percentile
+ for (unsigned int i = 0; i < WEIGHTS_MAX_BLOCK_MODES; i++)
+ {
+ unpacked_table[i] = 1.0f;
+ }
+
+ // Populate the unpacked percentile values
+ for (int i = 0; i < 2; i++)
+ {
+ unsigned int itemcount = apt->item_count[i];
+ unsigned int difscale = apt->difscales[i];
+ unsigned int accum = apt->initial_percs[i];
+ const uint16_t *item_ptr = apt->items[i];
+
+ for (unsigned int j = 0; j < itemcount; j++)
+ {
+ uint16_t item = item_ptr[j];
+ unsigned int idx = item & 0x7FF;
+ unsigned int weight = (item >> 11) & 0x1F;
+ accum += weight;
+ unpacked_table[idx] = static_cast<float>(accum) / static_cast<float>(difscale);
+ }
+ }
+
+ return unpacked_table;
+}
+#endif
+
+/* See header for documentation. */
+bool is_legal_2d_block_size(
+ unsigned int xdim,
+ unsigned int ydim
+) {
+ unsigned int idx = (xdim << 8) | ydim;
+ switch (idx)
+ {
+ case 0x0404:
+ case 0x0504:
+ case 0x0505:
+ case 0x0605:
+ case 0x0606:
+ case 0x0805:
+ case 0x0806:
+ case 0x0808:
+ case 0x0A05:
+ case 0x0A06:
+ case 0x0A08:
+ case 0x0A0A:
+ case 0x0C0A:
+ case 0x0C0C:
+ return true;
+ }
+
+ return false;
+}
+
+/* See header for documentation. */
+bool is_legal_3d_block_size(
+ unsigned int xdim,
+ unsigned int ydim,
+ unsigned int zdim
+) {
+ unsigned int idx = (xdim << 16) | (ydim << 8) | zdim;
+ switch (idx)
+ {
+ case 0x030303:
+ case 0x040303:
+ case 0x040403:
+ case 0x040404:
+ case 0x050404:
+ case 0x050504:
+ case 0x050505:
+ case 0x060505:
+ case 0x060605:
+ case 0x060606:
+ return true;
+ }
+
+ return false;
+}
diff --git a/thirdparty/astcenc/astcenc_pick_best_endpoint_format.cpp b/thirdparty/astcenc/astcenc_pick_best_endpoint_format.cpp
new file mode 100644
index 0000000000..f25140d4c7
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_pick_best_endpoint_format.cpp
@@ -0,0 +1,1350 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Functions for finding best endpoint format.
+ *
+ * We assume there are two independent sources of error in any given partition:
+ *
+ * - Encoding choice errors
+ * - Quantization errors
+ *
+ * Encoding choice errors are caused by encoder decisions. For example:
+ *
+ * - Using luminance instead of separate RGB components.
+ * - Using a constant 1.0 alpha instead of storing an alpha component.
+ * - Using RGB+scale instead of storing two full RGB endpoints.
+ *
+ * Quantization errors occur due to the limited precision we use for storage. These errors generally
+ * scale with quantization level, but are not actually independent of color encoding. In particular:
+ *
+ * - If we can use offset encoding then quantization error is halved.
+ * - If we can use blue-contraction then quantization error for RG is halved.
+ * - If we use HDR endpoints the quantization error is higher.
+ *
+ * Apart from these effects, we assume the error is proportional to the quantization step size.
+ */
+
+
+#include "astcenc_internal.h"
+#include "astcenc_vecmathlib.h"
+
+#include <assert.h>
+
+/**
+ * @brief Compute the errors of the endpoint line options for one partition.
+ *
+ * Uncorrelated data assumes storing completely independent RGBA channels for each endpoint. Same
+ * chroma data assumes storing RGBA endpoints which pass though the origin (LDR only). RGBL data
+ * assumes storing RGB + lumashift (HDR only). Luminance error assumes storing RGB channels as a
+ * single value.
+ *
+ *
+ * @param pi The partition info data.
+ * @param partition_index The partition index to compule the error for.
+ * @param blk The image block.
+ * @param uncor_pline The endpoint line assuming uncorrelated endpoints.
+ * @param[out] uncor_err The computed error for the uncorrelated endpoint line.
+ * @param samec_pline The endpoint line assuming the same chroma for both endpoints.
+ * @param[out] samec_err The computed error for the uncorrelated endpoint line.
+ * @param rgbl_pline The endpoint line assuming RGB + lumashift data.
+ * @param[out] rgbl_err The computed error for the RGB + lumashift endpoint line.
+ * @param l_pline The endpoint line assuming luminance data.
+ * @param[out] l_err The computed error for the luminance endpoint line.
+ * @param[out] a_drop_err The computed error for dropping the alpha component.
+ */
+static void compute_error_squared_rgb_single_partition(
+ const partition_info& pi,
+ int partition_index,
+ const image_block& blk,
+ const processed_line3& uncor_pline,
+ float& uncor_err,
+ const processed_line3& samec_pline,
+ float& samec_err,
+ const processed_line3& rgbl_pline,
+ float& rgbl_err,
+ const processed_line3& l_pline,
+ float& l_err,
+ float& a_drop_err
+) {
+ vfloat4 ews = blk.channel_weight;
+
+ unsigned int texel_count = pi.partition_texel_count[partition_index];
+ const uint8_t* texel_indexes = pi.texels_of_partition[partition_index];
+ promise(texel_count > 0);
+
+ vfloatacc a_drop_errv = vfloatacc::zero();
+ vfloat default_a(blk.get_default_alpha());
+
+ vfloatacc uncor_errv = vfloatacc::zero();
+ vfloat uncor_bs0(uncor_pline.bs.lane<0>());
+ vfloat uncor_bs1(uncor_pline.bs.lane<1>());
+ vfloat uncor_bs2(uncor_pline.bs.lane<2>());
+
+ vfloat uncor_amod0(uncor_pline.amod.lane<0>());
+ vfloat uncor_amod1(uncor_pline.amod.lane<1>());
+ vfloat uncor_amod2(uncor_pline.amod.lane<2>());
+
+ vfloatacc samec_errv = vfloatacc::zero();
+ vfloat samec_bs0(samec_pline.bs.lane<0>());
+ vfloat samec_bs1(samec_pline.bs.lane<1>());
+ vfloat samec_bs2(samec_pline.bs.lane<2>());
+
+ vfloatacc rgbl_errv = vfloatacc::zero();
+ vfloat rgbl_bs0(rgbl_pline.bs.lane<0>());
+ vfloat rgbl_bs1(rgbl_pline.bs.lane<1>());
+ vfloat rgbl_bs2(rgbl_pline.bs.lane<2>());
+
+ vfloat rgbl_amod0(rgbl_pline.amod.lane<0>());
+ vfloat rgbl_amod1(rgbl_pline.amod.lane<1>());
+ vfloat rgbl_amod2(rgbl_pline.amod.lane<2>());
+
+ vfloatacc l_errv = vfloatacc::zero();
+ vfloat l_bs0(l_pline.bs.lane<0>());
+ vfloat l_bs1(l_pline.bs.lane<1>());
+ vfloat l_bs2(l_pline.bs.lane<2>());
+
+ vint lane_ids = vint::lane_id();
+ for (unsigned int i = 0; i < texel_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ vint tix(texel_indexes + i);
+
+ vmask mask = lane_ids < vint(texel_count);
+ lane_ids += vint(ASTCENC_SIMD_WIDTH);
+
+ // Compute the error that arises from just ditching alpha
+ vfloat data_a = gatherf(blk.data_a, tix);
+ vfloat alpha_diff = data_a - default_a;
+ alpha_diff = alpha_diff * alpha_diff;
+
+ haccumulate(a_drop_errv, alpha_diff, mask);
+
+ vfloat data_r = gatherf(blk.data_r, tix);
+ vfloat data_g = gatherf(blk.data_g, tix);
+ vfloat data_b = gatherf(blk.data_b, tix);
+
+ // Compute uncorrelated error
+ vfloat param = data_r * uncor_bs0
+ + data_g * uncor_bs1
+ + data_b * uncor_bs2;
+
+ vfloat dist0 = (uncor_amod0 + param * uncor_bs0) - data_r;
+ vfloat dist1 = (uncor_amod1 + param * uncor_bs1) - data_g;
+ vfloat dist2 = (uncor_amod2 + param * uncor_bs2) - data_b;
+
+ vfloat error = dist0 * dist0 * ews.lane<0>()
+ + dist1 * dist1 * ews.lane<1>()
+ + dist2 * dist2 * ews.lane<2>();
+
+ haccumulate(uncor_errv, error, mask);
+
+ // Compute same chroma error - no "amod", its always zero
+ param = data_r * samec_bs0
+ + data_g * samec_bs1
+ + data_b * samec_bs2;
+
+ dist0 = (param * samec_bs0) - data_r;
+ dist1 = (param * samec_bs1) - data_g;
+ dist2 = (param * samec_bs2) - data_b;
+
+ error = dist0 * dist0 * ews.lane<0>()
+ + dist1 * dist1 * ews.lane<1>()
+ + dist2 * dist2 * ews.lane<2>();
+
+ haccumulate(samec_errv, error, mask);
+
+ // Compute rgbl error
+ param = data_r * rgbl_bs0
+ + data_g * rgbl_bs1
+ + data_b * rgbl_bs2;
+
+ dist0 = (rgbl_amod0 + param * rgbl_bs0) - data_r;
+ dist1 = (rgbl_amod1 + param * rgbl_bs1) - data_g;
+ dist2 = (rgbl_amod2 + param * rgbl_bs2) - data_b;
+
+ error = dist0 * dist0 * ews.lane<0>()
+ + dist1 * dist1 * ews.lane<1>()
+ + dist2 * dist2 * ews.lane<2>();
+
+ haccumulate(rgbl_errv, error, mask);
+
+ // Compute luma error - no "amod", its always zero
+ param = data_r * l_bs0
+ + data_g * l_bs1
+ + data_b * l_bs2;
+
+ dist0 = (param * l_bs0) - data_r;
+ dist1 = (param * l_bs1) - data_g;
+ dist2 = (param * l_bs2) - data_b;
+
+ error = dist0 * dist0 * ews.lane<0>()
+ + dist1 * dist1 * ews.lane<1>()
+ + dist2 * dist2 * ews.lane<2>();
+
+ haccumulate(l_errv, error, mask);
+ }
+
+ a_drop_err = hadd_s(a_drop_errv) * ews.lane<3>();
+ uncor_err = hadd_s(uncor_errv);
+ samec_err = hadd_s(samec_errv);
+ rgbl_err = hadd_s(rgbl_errv);
+ l_err = hadd_s(l_errv);
+}
+
+/**
+ * @brief For a given set of input colors and partitioning determine endpoint encode errors.
+ *
+ * This function determines the color error that results from RGB-scale encoding (LDR only),
+ * RGB-lumashift encoding (HDR only), luminance-encoding, and alpha drop. Also determines whether
+ * the endpoints are eligible for offset encoding or blue-contraction
+ *
+ * @param blk The image block.
+ * @param pi The partition info data.
+ * @param ep The idealized endpoints.
+ * @param[out] eci The resulting encoding choice error metrics.
+ */
+static void compute_encoding_choice_errors(
+ const image_block& blk,
+ const partition_info& pi,
+ const endpoints& ep,
+ encoding_choice_errors eci[BLOCK_MAX_PARTITIONS])
+{
+ int partition_count = pi.partition_count;
+ promise(partition_count > 0);
+
+ partition_metrics pms[BLOCK_MAX_PARTITIONS];
+
+ compute_avgs_and_dirs_3_comp_rgb(pi, blk, pms);
+
+ for (int i = 0; i < partition_count; i++)
+ {
+ partition_metrics& pm = pms[i];
+
+ line3 uncor_rgb_lines;
+ line3 samec_rgb_lines; // for LDR-RGB-scale
+ line3 rgb_luma_lines; // for HDR-RGB-scale
+
+ processed_line3 uncor_rgb_plines;
+ processed_line3 samec_rgb_plines;
+ processed_line3 rgb_luma_plines;
+ processed_line3 luminance_plines;
+
+ float uncorr_rgb_error;
+ float samechroma_rgb_error;
+ float rgb_luma_error;
+ float luminance_rgb_error;
+ float alpha_drop_error;
+
+ uncor_rgb_lines.a = pm.avg;
+ uncor_rgb_lines.b = normalize_safe(pm.dir, unit3());
+
+ samec_rgb_lines.a = vfloat4::zero();
+ samec_rgb_lines.b = normalize_safe(pm.avg, unit3());
+
+ rgb_luma_lines.a = pm.avg;
+ rgb_luma_lines.b = unit3();
+
+ uncor_rgb_plines.amod = uncor_rgb_lines.a - uncor_rgb_lines.b * dot3(uncor_rgb_lines.a, uncor_rgb_lines.b);
+ uncor_rgb_plines.bs = uncor_rgb_lines.b;
+
+ // Same chroma always goes though zero, so this is simpler than the others
+ samec_rgb_plines.amod = vfloat4::zero();
+ samec_rgb_plines.bs = samec_rgb_lines.b;
+
+ rgb_luma_plines.amod = rgb_luma_lines.a - rgb_luma_lines.b * dot3(rgb_luma_lines.a, rgb_luma_lines.b);
+ rgb_luma_plines.bs = rgb_luma_lines.b;
+
+ // Luminance always goes though zero, so this is simpler than the others
+ luminance_plines.amod = vfloat4::zero();
+ luminance_plines.bs = unit3();
+
+ compute_error_squared_rgb_single_partition(
+ pi, i, blk,
+ uncor_rgb_plines, uncorr_rgb_error,
+ samec_rgb_plines, samechroma_rgb_error,
+ rgb_luma_plines, rgb_luma_error,
+ luminance_plines, luminance_rgb_error,
+ alpha_drop_error);
+
+ // Determine if we can offset encode RGB lanes
+ vfloat4 endpt0 = ep.endpt0[i];
+ vfloat4 endpt1 = ep.endpt1[i];
+ vfloat4 endpt_diff = abs(endpt1 - endpt0);
+ vmask4 endpt_can_offset = endpt_diff < vfloat4(0.12f * 65535.0f);
+ bool can_offset_encode = (mask(endpt_can_offset) & 0x7) == 0x7;
+
+ // Store out the settings
+ eci[i].rgb_scale_error = (samechroma_rgb_error - uncorr_rgb_error) * 0.7f; // empirical
+ eci[i].rgb_luma_error = (rgb_luma_error - uncorr_rgb_error) * 1.5f; // wild guess
+ eci[i].luminance_error = (luminance_rgb_error - uncorr_rgb_error) * 3.0f; // empirical
+ eci[i].alpha_drop_error = alpha_drop_error * 3.0f;
+ eci[i].can_offset_encode = can_offset_encode;
+ eci[i].can_blue_contract = !blk.is_luminance();
+ }
+}
+
+/**
+ * @brief For a given partition compute the error for every endpoint integer count and quant level.
+ *
+ * @param encode_hdr_rgb @c true if using HDR for RGB, @c false for LDR.
+ * @param encode_hdr_alpha @c true if using HDR for alpha, @c false for LDR.
+ * @param partition_index The partition index.
+ * @param pi The partition info.
+ * @param eci The encoding choice error metrics.
+ * @param ep The idealized endpoints.
+ * @param error_weight The resulting encoding choice error metrics.
+ * @param[out] best_error The best error for each integer count and quant level.
+ * @param[out] format_of_choice The preferred endpoint format for each integer count and quant level.
+ */
+static void compute_color_error_for_every_integer_count_and_quant_level(
+ bool encode_hdr_rgb,
+ bool encode_hdr_alpha,
+ int partition_index,
+ const partition_info& pi,
+ const encoding_choice_errors& eci,
+ const endpoints& ep,
+ vfloat4 error_weight,
+ float best_error[21][4],
+ uint8_t format_of_choice[21][4]
+) {
+ int partition_size = pi.partition_texel_count[partition_index];
+
+ static const float baseline_quant_error[21 - QUANT_6] {
+ (65536.0f * 65536.0f / 18.0f) / (5 * 5),
+ (65536.0f * 65536.0f / 18.0f) / (7 * 7),
+ (65536.0f * 65536.0f / 18.0f) / (9 * 9),
+ (65536.0f * 65536.0f / 18.0f) / (11 * 11),
+ (65536.0f * 65536.0f / 18.0f) / (15 * 15),
+ (65536.0f * 65536.0f / 18.0f) / (19 * 19),
+ (65536.0f * 65536.0f / 18.0f) / (23 * 23),
+ (65536.0f * 65536.0f / 18.0f) / (31 * 31),
+ (65536.0f * 65536.0f / 18.0f) / (39 * 39),
+ (65536.0f * 65536.0f / 18.0f) / (47 * 47),
+ (65536.0f * 65536.0f / 18.0f) / (63 * 63),
+ (65536.0f * 65536.0f / 18.0f) / (79 * 79),
+ (65536.0f * 65536.0f / 18.0f) / (95 * 95),
+ (65536.0f * 65536.0f / 18.0f) / (127 * 127),
+ (65536.0f * 65536.0f / 18.0f) / (159 * 159),
+ (65536.0f * 65536.0f / 18.0f) / (191 * 191),
+ (65536.0f * 65536.0f / 18.0f) / (255 * 255)
+ };
+
+ vfloat4 ep0 = ep.endpt0[partition_index];
+ vfloat4 ep1 = ep.endpt1[partition_index];
+
+ float ep1_min = hmin_rgb_s(ep1);
+ ep1_min = astc::max(ep1_min, 0.0f);
+
+ float error_weight_rgbsum = hadd_rgb_s(error_weight);
+
+ float range_upper_limit_rgb = encode_hdr_rgb ? 61440.0f : 65535.0f;
+ float range_upper_limit_alpha = encode_hdr_alpha ? 61440.0f : 65535.0f;
+
+ // It is possible to get endpoint colors significantly outside [0,upper-limit] even if the
+ // input data are safely contained in [0,upper-limit]; we need to add an error term for this
+ vfloat4 offset(range_upper_limit_rgb, range_upper_limit_rgb, range_upper_limit_rgb, range_upper_limit_alpha);
+ vfloat4 ep0_range_error_high = max(ep0 - offset, 0.0f);
+ vfloat4 ep1_range_error_high = max(ep1 - offset, 0.0f);
+
+ vfloat4 ep0_range_error_low = min(ep0, 0.0f);
+ vfloat4 ep1_range_error_low = min(ep1, 0.0f);
+
+ vfloat4 sum_range_error =
+ (ep0_range_error_low * ep0_range_error_low) +
+ (ep1_range_error_low * ep1_range_error_low) +
+ (ep0_range_error_high * ep0_range_error_high) +
+ (ep1_range_error_high * ep1_range_error_high);
+
+ float rgb_range_error = dot3_s(sum_range_error, error_weight)
+ * 0.5f * static_cast<float>(partition_size);
+ float alpha_range_error = sum_range_error.lane<3>() * error_weight.lane<3>()
+ * 0.5f * static_cast<float>(partition_size);
+
+ if (encode_hdr_rgb)
+ {
+
+ // Collect some statistics
+ float af, cf;
+ if (ep1.lane<0>() > ep1.lane<1>() && ep1.lane<0>() > ep1.lane<2>())
+ {
+ af = ep1.lane<0>();
+ cf = ep1.lane<0>() - ep0.lane<0>();
+ }
+ else if (ep1.lane<1>() > ep1.lane<2>())
+ {
+ af = ep1.lane<1>();
+ cf = ep1.lane<1>() - ep0.lane<1>();
+ }
+ else
+ {
+ af = ep1.lane<2>();
+ cf = ep1.lane<2>() - ep0.lane<2>();
+ }
+
+ // Estimate of color-component spread in high endpoint color
+ float bf = af - ep1_min;
+ vfloat4 prd = (ep1 - vfloat4(cf)).swz<0, 1, 2>();
+ vfloat4 pdif = prd - ep0.swz<0, 1, 2>();
+ // Estimate of color-component spread in low endpoint color
+ float df = hmax_s(abs(pdif));
+
+ int b = static_cast<int>(bf);
+ int c = static_cast<int>(cf);
+ int d = static_cast<int>(df);
+
+ // Determine which one of the 6 submodes is likely to be used in case of an RGBO-mode
+ int rgbo_mode = 5; // 7 bits per component
+ // mode 4: 8 7 6
+ if (b < 32768 && c < 16384)
+ {
+ rgbo_mode = 4;
+ }
+
+ // mode 3: 9 6 7
+ if (b < 8192 && c < 16384)
+ {
+ rgbo_mode = 3;
+ }
+
+ // mode 2: 10 5 8
+ if (b < 2048 && c < 16384)
+ {
+ rgbo_mode = 2;
+ }
+
+ // mode 1: 11 6 5
+ if (b < 2048 && c < 1024)
+ {
+ rgbo_mode = 1;
+ }
+
+ // mode 0: 11 5 7
+ if (b < 1024 && c < 4096)
+ {
+ rgbo_mode = 0;
+ }
+
+ // Determine which one of the 9 submodes is likely to be used in case of an RGB-mode.
+ int rgb_mode = 8; // 8 bits per component, except 7 bits for blue
+
+ // mode 0: 9 7 6 7
+ if (b < 16384 && c < 8192 && d < 8192)
+ {
+ rgb_mode = 0;
+ }
+
+ // mode 1: 9 8 6 6
+ if (b < 32768 && c < 8192 && d < 4096)
+ {
+ rgb_mode = 1;
+ }
+
+ // mode 2: 10 6 7 7
+ if (b < 4096 && c < 8192 && d < 4096)
+ {
+ rgb_mode = 2;
+ }
+
+ // mode 3: 10 7 7 6
+ if (b < 8192 && c < 8192 && d < 2048)
+ {
+ rgb_mode = 3;
+ }
+
+ // mode 4: 11 8 6 5
+ if (b < 8192 && c < 2048 && d < 512)
+ {
+ rgb_mode = 4;
+ }
+
+ // mode 5: 11 6 8 6
+ if (b < 2048 && c < 8192 && d < 1024)
+ {
+ rgb_mode = 5;
+ }
+
+ // mode 6: 12 7 7 5
+ if (b < 2048 && c < 2048 && d < 256)
+ {
+ rgb_mode = 6;
+ }
+
+ // mode 7: 12 6 7 6
+ if (b < 1024 && c < 2048 && d < 512)
+ {
+ rgb_mode = 7;
+ }
+
+ static const float rgbo_error_scales[6] { 4.0f, 4.0f, 16.0f, 64.0f, 256.0f, 1024.0f };
+ static const float rgb_error_scales[9] { 64.0f, 64.0f, 16.0f, 16.0f, 4.0f, 4.0f, 1.0f, 1.0f, 384.0f };
+
+ float mode7mult = rgbo_error_scales[rgbo_mode] * 0.0015f; // Empirically determined ....
+ float mode11mult = rgb_error_scales[rgb_mode] * 0.010f; // Empirically determined ....
+
+
+ float lum_high = hadd_rgb_s(ep1) * (1.0f / 3.0f);
+ float lum_low = hadd_rgb_s(ep0) * (1.0f / 3.0f);
+ float lumdif = lum_high - lum_low;
+ float mode23mult = lumdif < 960 ? 4.0f : lumdif < 3968 ? 16.0f : 128.0f;
+
+ mode23mult *= 0.0005f; // Empirically determined ....
+
+ // Pick among the available HDR endpoint modes
+ for (int i = QUANT_2; i < QUANT_16; i++)
+ {
+ best_error[i][3] = ERROR_CALC_DEFAULT;
+ best_error[i][2] = ERROR_CALC_DEFAULT;
+ best_error[i][1] = ERROR_CALC_DEFAULT;
+ best_error[i][0] = ERROR_CALC_DEFAULT;
+
+ format_of_choice[i][3] = static_cast<uint8_t>(encode_hdr_alpha ? FMT_HDR_RGBA : FMT_HDR_RGB_LDR_ALPHA);
+ format_of_choice[i][2] = FMT_HDR_RGB;
+ format_of_choice[i][1] = FMT_HDR_RGB_SCALE;
+ format_of_choice[i][0] = FMT_HDR_LUMINANCE_LARGE_RANGE;
+ }
+
+ for (int i = QUANT_16; i <= QUANT_256; i++)
+ {
+ // The base_quant_error should depend on the scale-factor that would be used during
+ // actual encode of the color value
+
+ float base_quant_error = baseline_quant_error[i - QUANT_6] * static_cast<float>(partition_size);
+ float rgb_quantization_error = error_weight_rgbsum * base_quant_error * 2.0f;
+ float alpha_quantization_error = error_weight.lane<3>() * base_quant_error * 2.0f;
+ float rgba_quantization_error = rgb_quantization_error + alpha_quantization_error;
+
+ // For 8 integers, we have two encodings: one with HDR A and another one with LDR A
+
+ float full_hdr_rgba_error = rgba_quantization_error + rgb_range_error + alpha_range_error;
+ best_error[i][3] = full_hdr_rgba_error;
+ format_of_choice[i][3] = static_cast<uint8_t>(encode_hdr_alpha ? FMT_HDR_RGBA : FMT_HDR_RGB_LDR_ALPHA);
+
+ // For 6 integers, we have one HDR-RGB encoding
+ float full_hdr_rgb_error = (rgb_quantization_error * mode11mult) + rgb_range_error + eci.alpha_drop_error;
+ best_error[i][2] = full_hdr_rgb_error;
+ format_of_choice[i][2] = FMT_HDR_RGB;
+
+ // For 4 integers, we have one HDR-RGB-Scale encoding
+ float hdr_rgb_scale_error = (rgb_quantization_error * mode7mult) + rgb_range_error + eci.alpha_drop_error + eci.rgb_luma_error;
+
+ best_error[i][1] = hdr_rgb_scale_error;
+ format_of_choice[i][1] = FMT_HDR_RGB_SCALE;
+
+ // For 2 integers, we assume luminance-with-large-range
+ float hdr_luminance_error = (rgb_quantization_error * mode23mult) + rgb_range_error + eci.alpha_drop_error + eci.luminance_error;
+ best_error[i][0] = hdr_luminance_error;
+ format_of_choice[i][0] = FMT_HDR_LUMINANCE_LARGE_RANGE;
+ }
+ }
+ else
+ {
+ for (int i = QUANT_2; i < QUANT_6; i++)
+ {
+ best_error[i][3] = ERROR_CALC_DEFAULT;
+ best_error[i][2] = ERROR_CALC_DEFAULT;
+ best_error[i][1] = ERROR_CALC_DEFAULT;
+ best_error[i][0] = ERROR_CALC_DEFAULT;
+
+ format_of_choice[i][3] = FMT_RGBA;
+ format_of_choice[i][2] = FMT_RGB;
+ format_of_choice[i][1] = FMT_RGB_SCALE;
+ format_of_choice[i][0] = FMT_LUMINANCE;
+ }
+
+ float base_quant_error_rgb = error_weight_rgbsum * static_cast<float>(partition_size);
+ float base_quant_error_a = error_weight.lane<3>() * static_cast<float>(partition_size);
+ float base_quant_error_rgba = base_quant_error_rgb + base_quant_error_a;
+
+ float error_scale_bc_rgba = eci.can_blue_contract ? 0.625f : 1.0f;
+ float error_scale_oe_rgba = eci.can_offset_encode ? 0.5f : 1.0f;
+
+ float error_scale_bc_rgb = eci.can_blue_contract ? 0.5f : 1.0f;
+ float error_scale_oe_rgb = eci.can_offset_encode ? 0.25f : 1.0f;
+
+ // Pick among the available LDR endpoint modes
+ for (int i = QUANT_6; i <= QUANT_256; i++)
+ {
+ // Offset encoding not possible at higher quant levels
+ if (i >= QUANT_192)
+ {
+ error_scale_oe_rgba = 1.0f;
+ error_scale_oe_rgb = 1.0f;
+ }
+
+ float base_quant_error = baseline_quant_error[i - QUANT_6];
+ float quant_error_rgb = base_quant_error_rgb * base_quant_error;
+ float quant_error_rgba = base_quant_error_rgba * base_quant_error;
+
+ // 8 integers can encode as RGBA+RGBA
+ float full_ldr_rgba_error = quant_error_rgba
+ * error_scale_bc_rgba
+ * error_scale_oe_rgba
+ + rgb_range_error
+ + alpha_range_error;
+
+ best_error[i][3] = full_ldr_rgba_error;
+ format_of_choice[i][3] = FMT_RGBA;
+
+ // 6 integers can encode as RGB+RGB or RGBS+AA
+ float full_ldr_rgb_error = quant_error_rgb
+ * error_scale_bc_rgb
+ * error_scale_oe_rgb
+ + rgb_range_error
+ + eci.alpha_drop_error;
+
+ float rgbs_alpha_error = quant_error_rgba
+ + eci.rgb_scale_error
+ + rgb_range_error
+ + alpha_range_error;
+
+ if (rgbs_alpha_error < full_ldr_rgb_error)
+ {
+ best_error[i][2] = rgbs_alpha_error;
+ format_of_choice[i][2] = FMT_RGB_SCALE_ALPHA;
+ }
+ else
+ {
+ best_error[i][2] = full_ldr_rgb_error;
+ format_of_choice[i][2] = FMT_RGB;
+ }
+
+ // 4 integers can encode as RGBS or LA+LA
+ float ldr_rgbs_error = quant_error_rgb
+ + rgb_range_error
+ + eci.alpha_drop_error
+ + eci.rgb_scale_error;
+
+ float lum_alpha_error = quant_error_rgba
+ + rgb_range_error
+ + alpha_range_error
+ + eci.luminance_error;
+
+ if (ldr_rgbs_error < lum_alpha_error)
+ {
+ best_error[i][1] = ldr_rgbs_error;
+ format_of_choice[i][1] = FMT_RGB_SCALE;
+ }
+ else
+ {
+ best_error[i][1] = lum_alpha_error;
+ format_of_choice[i][1] = FMT_LUMINANCE_ALPHA;
+ }
+
+ // 2 integers can encode as L+L
+ float luminance_error = quant_error_rgb
+ + rgb_range_error
+ + eci.alpha_drop_error
+ + eci.luminance_error;
+
+ best_error[i][0] = luminance_error;
+ format_of_choice[i][0] = FMT_LUMINANCE;
+ }
+ }
+}
+
+/**
+ * @brief For one partition compute the best format and quantization for a given bit count.
+ *
+ * @param best_combined_error The best error for each quant level and integer count.
+ * @param best_combined_format The best format for each quant level and integer count.
+ * @param bits_available The number of bits available for encoding.
+ * @param[out] best_quant_level The output best color quant level.
+ * @param[out] best_format The output best color format.
+ *
+ * @return The output error for the best pairing.
+ */
+static float one_partition_find_best_combination_for_bitcount(
+ const float best_combined_error[21][4],
+ const uint8_t best_combined_format[21][4],
+ int bits_available,
+ uint8_t& best_quant_level,
+ uint8_t& best_format
+) {
+ int best_integer_count = 0;
+ float best_integer_count_error = ERROR_CALC_DEFAULT;
+
+ for (int integer_count = 1; integer_count <= 4; integer_count++)
+ {
+ // Compute the quantization level for a given number of integers and a given number of bits
+ int quant_level = quant_mode_table[integer_count][bits_available];
+
+ // Don't have enough bits to represent a given endpoint format at all!
+ if (quant_level < QUANT_6)
+ {
+ continue;
+ }
+
+ float integer_count_error = best_combined_error[quant_level][integer_count - 1];
+ if (integer_count_error < best_integer_count_error)
+ {
+ best_integer_count_error = integer_count_error;
+ best_integer_count = integer_count - 1;
+ }
+ }
+
+ int ql = quant_mode_table[best_integer_count + 1][bits_available];
+
+ best_quant_level = static_cast<uint8_t>(ql);
+ best_format = FMT_LUMINANCE;
+
+ if (ql >= QUANT_6)
+ {
+ best_format = best_combined_format[ql][best_integer_count];
+ }
+
+ return best_integer_count_error;
+}
+
+/**
+ * @brief For 2 partitions compute the best format combinations for every pair of quant mode and integer count.
+ *
+ * @param best_error The best error for a single endpoint quant level and integer count.
+ * @param best_format The best format for a single endpoint quant level and integer count.
+ * @param[out] best_combined_error The best combined error pairings for the 2 partitions.
+ * @param[out] best_combined_format The best combined format pairings for the 2 partitions.
+ */
+static void two_partitions_find_best_combination_for_every_quantization_and_integer_count(
+ const float best_error[2][21][4], // indexed by (partition, quant-level, integer-pair-count-minus-1)
+ const uint8_t best_format[2][21][4],
+ float best_combined_error[21][7], // indexed by (quant-level, integer-pair-count-minus-2)
+ uint8_t best_combined_format[21][7][2]
+) {
+ for (int i = QUANT_2; i <= QUANT_256; i++)
+ {
+ for (int j = 0; j < 7; j++)
+ {
+ best_combined_error[i][j] = ERROR_CALC_DEFAULT;
+ }
+ }
+
+ for (int quant = QUANT_6; quant <= QUANT_256; quant++)
+ {
+ for (int i = 0; i < 4; i++) // integer-count for first endpoint-pair
+ {
+ for (int j = 0; j < 4; j++) // integer-count for second endpoint-pair
+ {
+ int low2 = astc::min(i, j);
+ int high2 = astc::max(i, j);
+ if ((high2 - low2) > 1)
+ {
+ continue;
+ }
+
+ int intcnt = i + j;
+ float errorterm = astc::min(best_error[0][quant][i] + best_error[1][quant][j], 1e10f);
+ if (errorterm <= best_combined_error[quant][intcnt])
+ {
+ best_combined_error[quant][intcnt] = errorterm;
+ best_combined_format[quant][intcnt][0] = best_format[0][quant][i];
+ best_combined_format[quant][intcnt][1] = best_format[1][quant][j];
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @brief For 2 partitions compute the best format and quantization for a given bit count.
+ *
+ * @param best_combined_error The best error for each quant level and integer count.
+ * @param best_combined_format The best format for each quant level and integer count.
+ * @param bits_available The number of bits available for encoding.
+ * @param[out] best_quant_level The output best color quant level.
+ * @param[out] best_quant_level_mod The output best color quant level assuming two more bits are available.
+ * @param[out] best_formats The output best color formats.
+ *
+ * @return The output error for the best pairing.
+ */
+static float two_partitions_find_best_combination_for_bitcount(
+ float best_combined_error[21][7],
+ uint8_t best_combined_format[21][7][2],
+ int bits_available,
+ uint8_t& best_quant_level,
+ uint8_t& best_quant_level_mod,
+ uint8_t* best_formats
+) {
+ int best_integer_count = 0;
+ float best_integer_count_error = ERROR_CALC_DEFAULT;
+
+ for (int integer_count = 2; integer_count <= 8; integer_count++)
+ {
+ // Compute the quantization level for a given number of integers and a given number of bits
+ int quant_level = quant_mode_table[integer_count][bits_available];
+
+ // Don't have enough bits to represent a given endpoint format at all!
+ if (quant_level < QUANT_6)
+ {
+ break;
+ }
+
+ float integer_count_error = best_combined_error[quant_level][integer_count - 2];
+ if (integer_count_error < best_integer_count_error)
+ {
+ best_integer_count_error = integer_count_error;
+ best_integer_count = integer_count;
+ }
+ }
+
+ int ql = quant_mode_table[best_integer_count][bits_available];
+ int ql_mod = quant_mode_table[best_integer_count][bits_available + 2];
+
+ best_quant_level = static_cast<uint8_t>(ql);
+ best_quant_level_mod = static_cast<uint8_t>(ql_mod);
+
+ if (ql >= QUANT_6)
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ best_formats[i] = best_combined_format[ql][best_integer_count - 2][i];
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 2; i++)
+ {
+ best_formats[i] = FMT_LUMINANCE;
+ }
+ }
+
+ return best_integer_count_error;
+}
+
+/**
+ * @brief For 3 partitions compute the best format combinations for every pair of quant mode and integer count.
+ *
+ * @param best_error The best error for a single endpoint quant level and integer count.
+ * @param best_format The best format for a single endpoint quant level and integer count.
+ * @param[out] best_combined_error The best combined error pairings for the 3 partitions.
+ * @param[out] best_combined_format The best combined format pairings for the 3 partitions.
+ */
+static void three_partitions_find_best_combination_for_every_quantization_and_integer_count(
+ const float best_error[3][21][4], // indexed by (partition, quant-level, integer-count)
+ const uint8_t best_format[3][21][4],
+ float best_combined_error[21][10],
+ uint8_t best_combined_format[21][10][3]
+) {
+ for (int i = QUANT_2; i <= QUANT_256; i++)
+ {
+ for (int j = 0; j < 10; j++)
+ {
+ best_combined_error[i][j] = ERROR_CALC_DEFAULT;
+ }
+ }
+
+ for (int quant = QUANT_6; quant <= QUANT_256; quant++)
+ {
+ for (int i = 0; i < 4; i++) // integer-count for first endpoint-pair
+ {
+ for (int j = 0; j < 4; j++) // integer-count for second endpoint-pair
+ {
+ int low2 = astc::min(i, j);
+ int high2 = astc::max(i, j);
+ if ((high2 - low2) > 1)
+ {
+ continue;
+ }
+
+ for (int k = 0; k < 4; k++) // integer-count for third endpoint-pair
+ {
+ int low3 = astc::min(k, low2);
+ int high3 = astc::max(k, high2);
+ if ((high3 - low3) > 1)
+ {
+ continue;
+ }
+
+ int intcnt = i + j + k;
+ float errorterm = astc::min(best_error[0][quant][i] + best_error[1][quant][j] + best_error[2][quant][k], 1e10f);
+ if (errorterm <= best_combined_error[quant][intcnt])
+ {
+ best_combined_error[quant][intcnt] = errorterm;
+ best_combined_format[quant][intcnt][0] = best_format[0][quant][i];
+ best_combined_format[quant][intcnt][1] = best_format[1][quant][j];
+ best_combined_format[quant][intcnt][2] = best_format[2][quant][k];
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @brief For 3 partitions compute the best format and quantization for a given bit count.
+ *
+ * @param best_combined_error The best error for each quant level and integer count.
+ * @param best_combined_format The best format for each quant level and integer count.
+ * @param bits_available The number of bits available for encoding.
+ * @param[out] best_quant_level The output best color quant level.
+ * @param[out] best_quant_level_mod The output best color quant level assuming two more bits are available.
+ * @param[out] best_formats The output best color formats.
+ *
+ * @return The output error for the best pairing.
+ */
+static float three_partitions_find_best_combination_for_bitcount(
+ const float best_combined_error[21][10],
+ const uint8_t best_combined_format[21][10][3],
+ int bits_available,
+ uint8_t& best_quant_level,
+ uint8_t& best_quant_level_mod,
+ uint8_t* best_formats
+) {
+ int best_integer_count = 0;
+ float best_integer_count_error = ERROR_CALC_DEFAULT;
+
+ for (int integer_count = 3; integer_count <= 9; integer_count++)
+ {
+ // Compute the quantization level for a given number of integers and a given number of bits
+ int quant_level = quant_mode_table[integer_count][bits_available];
+
+ // Don't have enough bits to represent a given endpoint format at all!
+ if (quant_level < QUANT_6)
+ {
+ break;
+ }
+
+ float integer_count_error = best_combined_error[quant_level][integer_count - 3];
+ if (integer_count_error < best_integer_count_error)
+ {
+ best_integer_count_error = integer_count_error;
+ best_integer_count = integer_count;
+ }
+ }
+
+ int ql = quant_mode_table[best_integer_count][bits_available];
+ int ql_mod = quant_mode_table[best_integer_count][bits_available + 5];
+
+ best_quant_level = static_cast<uint8_t>(ql);
+ best_quant_level_mod = static_cast<uint8_t>(ql_mod);
+
+ if (ql >= QUANT_6)
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ best_formats[i] = best_combined_format[ql][best_integer_count - 3][i];
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 3; i++)
+ {
+ best_formats[i] = FMT_LUMINANCE;
+ }
+ }
+
+ return best_integer_count_error;
+}
+
+/**
+ * @brief For 4 partitions compute the best format combinations for every pair of quant mode and integer count.
+ *
+ * @param best_error The best error for a single endpoint quant level and integer count.
+ * @param best_format The best format for a single endpoint quant level and integer count.
+ * @param[out] best_combined_error The best combined error pairings for the 4 partitions.
+ * @param[out] best_combined_format The best combined format pairings for the 4 partitions.
+ */
+static void four_partitions_find_best_combination_for_every_quantization_and_integer_count(
+ const float best_error[4][21][4], // indexed by (partition, quant-level, integer-count)
+ const uint8_t best_format[4][21][4],
+ float best_combined_error[21][13],
+ uint8_t best_combined_format[21][13][4]
+) {
+ for (int i = QUANT_2; i <= QUANT_256; i++)
+ {
+ for (int j = 0; j < 13; j++)
+ {
+ best_combined_error[i][j] = ERROR_CALC_DEFAULT;
+ }
+ }
+
+ for (int quant = QUANT_6; quant <= QUANT_256; quant++)
+ {
+ for (int i = 0; i < 4; i++) // integer-count for first endpoint-pair
+ {
+ for (int j = 0; j < 4; j++) // integer-count for second endpoint-pair
+ {
+ int low2 = astc::min(i, j);
+ int high2 = astc::max(i, j);
+ if ((high2 - low2) > 1)
+ {
+ continue;
+ }
+
+ for (int k = 0; k < 4; k++) // integer-count for third endpoint-pair
+ {
+ int low3 = astc::min(k, low2);
+ int high3 = astc::max(k, high2);
+ if ((high3 - low3) > 1)
+ {
+ continue;
+ }
+
+ for (int l = 0; l < 4; l++) // integer-count for fourth endpoint-pair
+ {
+ int low4 = astc::min(l, low3);
+ int high4 = astc::max(l, high3);
+ if ((high4 - low4) > 1)
+ {
+ continue;
+ }
+
+ int intcnt = i + j + k + l;
+ float errorterm = astc::min(best_error[0][quant][i] + best_error[1][quant][j] + best_error[2][quant][k] + best_error[3][quant][l], 1e10f);
+ if (errorterm <= best_combined_error[quant][intcnt])
+ {
+ best_combined_error[quant][intcnt] = errorterm;
+ best_combined_format[quant][intcnt][0] = best_format[0][quant][i];
+ best_combined_format[quant][intcnt][1] = best_format[1][quant][j];
+ best_combined_format[quant][intcnt][2] = best_format[2][quant][k];
+ best_combined_format[quant][intcnt][3] = best_format[3][quant][l];
+ }
+ }
+ }
+ }
+ }
+ }
+}
+
+/**
+ * @brief For 4 partitions compute the best format and quantization for a given bit count.
+ *
+ * @param best_combined_error The best error for each quant level and integer count.
+ * @param best_combined_format The best format for each quant level and integer count.
+ * @param bits_available The number of bits available for encoding.
+ * @param[out] best_quant_level The output best color quant level.
+ * @param[out] best_quant_level_mod The output best color quant level assuming two more bits are available.
+ * @param[out] best_formats The output best color formats.
+ *
+ * @return best_error The output error for the best pairing.
+ */
+static float four_partitions_find_best_combination_for_bitcount(
+ const float best_combined_error[21][13],
+ const uint8_t best_combined_format[21][13][4],
+ int bits_available,
+ uint8_t& best_quant_level,
+ uint8_t& best_quant_level_mod,
+ uint8_t* best_formats
+) {
+ int best_integer_count = 0;
+ float best_integer_count_error = ERROR_CALC_DEFAULT;
+
+ for (int integer_count = 4; integer_count <= 9; integer_count++)
+ {
+ // Compute the quantization level for a given number of integers and a given number of bits
+ int quant_level = quant_mode_table[integer_count][bits_available];
+
+ // Don't have enough bits to represent a given endpoint format at all!
+ if (quant_level < QUANT_6)
+ {
+ break;
+ }
+
+ float integer_count_error = best_combined_error[quant_level][integer_count - 4];
+ if (integer_count_error < best_integer_count_error)
+ {
+ best_integer_count_error = integer_count_error;
+ best_integer_count = integer_count;
+ }
+ }
+
+ int ql = quant_mode_table[best_integer_count][bits_available];
+ int ql_mod = quant_mode_table[best_integer_count][bits_available + 8];
+
+ best_quant_level = static_cast<uint8_t>(ql);
+ best_quant_level_mod = static_cast<uint8_t>(ql_mod);
+
+ if (ql >= QUANT_6)
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ best_formats[i] = best_combined_format[ql][best_integer_count - 4][i];
+ }
+ }
+ else
+ {
+ for (int i = 0; i < 4; i++)
+ {
+ best_formats[i] = FMT_LUMINANCE;
+ }
+ }
+
+ return best_integer_count_error;
+}
+
+/* See header for documentation. */
+unsigned int compute_ideal_endpoint_formats(
+ const partition_info& pi,
+ const image_block& blk,
+ const endpoints& ep,
+ // bitcounts and errors computed for the various quantization methods
+ const int8_t* qwt_bitcounts,
+ const float* qwt_errors,
+ unsigned int tune_candidate_limit,
+ unsigned int start_block_mode,
+ unsigned int end_block_mode,
+ // output data
+ uint8_t partition_format_specifiers[TUNE_MAX_TRIAL_CANDIDATES][BLOCK_MAX_PARTITIONS],
+ int block_mode[TUNE_MAX_TRIAL_CANDIDATES],
+ quant_method quant_level[TUNE_MAX_TRIAL_CANDIDATES],
+ quant_method quant_level_mod[TUNE_MAX_TRIAL_CANDIDATES],
+ compression_working_buffers& tmpbuf
+) {
+ int partition_count = pi.partition_count;
+
+ promise(partition_count > 0);
+
+ bool encode_hdr_rgb = static_cast<bool>(blk.rgb_lns[0]);
+ bool encode_hdr_alpha = static_cast<bool>(blk.alpha_lns[0]);
+
+ // Compute the errors that result from various encoding choices (such as using luminance instead
+ // of RGB, discarding Alpha, using RGB-scale in place of two separate RGB endpoints and so on)
+ encoding_choice_errors eci[BLOCK_MAX_PARTITIONS];
+ compute_encoding_choice_errors(blk, pi, ep, eci);
+
+ float best_error[BLOCK_MAX_PARTITIONS][21][4];
+ uint8_t format_of_choice[BLOCK_MAX_PARTITIONS][21][4];
+ for (int i = 0; i < partition_count; i++)
+ {
+ compute_color_error_for_every_integer_count_and_quant_level(
+ encode_hdr_rgb, encode_hdr_alpha, i,
+ pi, eci[i], ep, blk.channel_weight, best_error[i],
+ format_of_choice[i]);
+ }
+
+ float* errors_of_best_combination = tmpbuf.errors_of_best_combination;
+ uint8_t* best_quant_levels = tmpbuf.best_quant_levels;
+ uint8_t* best_quant_levels_mod = tmpbuf.best_quant_levels_mod;
+ uint8_t (&best_ep_formats)[WEIGHTS_MAX_BLOCK_MODES][BLOCK_MAX_PARTITIONS] = tmpbuf.best_ep_formats;
+
+ // Ensure that the first iteration understep contains data that will never be picked
+ vfloat clear_error(ERROR_CALC_DEFAULT);
+ vint clear_quant(0);
+
+ unsigned int packed_start_block_mode = round_down_to_simd_multiple_vla(start_block_mode);
+ storea(clear_error, errors_of_best_combination + packed_start_block_mode);
+ store_nbytes(clear_quant, best_quant_levels + packed_start_block_mode);
+ store_nbytes(clear_quant, best_quant_levels_mod + packed_start_block_mode);
+
+ // Ensure that last iteration overstep contains data that will never be picked
+ unsigned int packed_end_block_mode = round_down_to_simd_multiple_vla(end_block_mode - 1);
+ storea(clear_error, errors_of_best_combination + packed_end_block_mode);
+ store_nbytes(clear_quant, best_quant_levels + packed_end_block_mode);
+ store_nbytes(clear_quant, best_quant_levels_mod + packed_end_block_mode);
+
+ // Track a scalar best to avoid expensive search at least once ...
+ float error_of_best_combination = ERROR_CALC_DEFAULT;
+ int index_of_best_combination = -1;
+
+ // The block contains 1 partition
+ if (partition_count == 1)
+ {
+ for (unsigned int i = start_block_mode; i < end_block_mode; i++)
+ {
+ if (qwt_errors[i] >= ERROR_CALC_DEFAULT)
+ {
+ errors_of_best_combination[i] = ERROR_CALC_DEFAULT;
+ continue;
+ }
+
+ float error_of_best = one_partition_find_best_combination_for_bitcount(
+ best_error[0], format_of_choice[0], qwt_bitcounts[i],
+ best_quant_levels[i], best_ep_formats[i][0]);
+
+ float total_error = error_of_best + qwt_errors[i];
+ errors_of_best_combination[i] = total_error;
+ best_quant_levels_mod[i] = best_quant_levels[i];
+
+ if (total_error < error_of_best_combination)
+ {
+ error_of_best_combination = total_error;
+ index_of_best_combination = i;
+ }
+ }
+ }
+ // The block contains 2 partitions
+ else if (partition_count == 2)
+ {
+ float combined_best_error[21][7];
+ uint8_t formats_of_choice[21][7][2];
+
+ two_partitions_find_best_combination_for_every_quantization_and_integer_count(
+ best_error, format_of_choice, combined_best_error, formats_of_choice);
+
+ assert(start_block_mode == 0);
+ for (unsigned int i = 0; i < end_block_mode; i++)
+ {
+ if (qwt_errors[i] >= ERROR_CALC_DEFAULT)
+ {
+ errors_of_best_combination[i] = ERROR_CALC_DEFAULT;
+ continue;
+ }
+
+ float error_of_best = two_partitions_find_best_combination_for_bitcount(
+ combined_best_error, formats_of_choice, qwt_bitcounts[i],
+ best_quant_levels[i], best_quant_levels_mod[i],
+ best_ep_formats[i]);
+
+ float total_error = error_of_best + qwt_errors[i];
+ errors_of_best_combination[i] = total_error;
+
+ if (total_error < error_of_best_combination)
+ {
+ error_of_best_combination = total_error;
+ index_of_best_combination = i;
+ }
+ }
+ }
+ // The block contains 3 partitions
+ else if (partition_count == 3)
+ {
+ float combined_best_error[21][10];
+ uint8_t formats_of_choice[21][10][3];
+
+ three_partitions_find_best_combination_for_every_quantization_and_integer_count(
+ best_error, format_of_choice, combined_best_error, formats_of_choice);
+
+ assert(start_block_mode == 0);
+ for (unsigned int i = 0; i < end_block_mode; i++)
+ {
+ if (qwt_errors[i] >= ERROR_CALC_DEFAULT)
+ {
+ errors_of_best_combination[i] = ERROR_CALC_DEFAULT;
+ continue;
+ }
+
+ float error_of_best = three_partitions_find_best_combination_for_bitcount(
+ combined_best_error, formats_of_choice, qwt_bitcounts[i],
+ best_quant_levels[i], best_quant_levels_mod[i],
+ best_ep_formats[i]);
+
+ float total_error = error_of_best + qwt_errors[i];
+ errors_of_best_combination[i] = total_error;
+
+ if (total_error < error_of_best_combination)
+ {
+ error_of_best_combination = total_error;
+ index_of_best_combination = i;
+ }
+ }
+ }
+ // The block contains 4 partitions
+ else // if (partition_count == 4)
+ {
+ assert(partition_count == 4);
+ float combined_best_error[21][13];
+ uint8_t formats_of_choice[21][13][4];
+
+ four_partitions_find_best_combination_for_every_quantization_and_integer_count(
+ best_error, format_of_choice, combined_best_error, formats_of_choice);
+
+ assert(start_block_mode == 0);
+ for (unsigned int i = 0; i < end_block_mode; i++)
+ {
+ if (qwt_errors[i] >= ERROR_CALC_DEFAULT)
+ {
+ errors_of_best_combination[i] = ERROR_CALC_DEFAULT;
+ continue;
+ }
+
+ float error_of_best = four_partitions_find_best_combination_for_bitcount(
+ combined_best_error, formats_of_choice, qwt_bitcounts[i],
+ best_quant_levels[i], best_quant_levels_mod[i],
+ best_ep_formats[i]);
+
+ float total_error = error_of_best + qwt_errors[i];
+ errors_of_best_combination[i] = total_error;
+
+ if (total_error < error_of_best_combination)
+ {
+ error_of_best_combination = total_error;
+ index_of_best_combination = i;
+ }
+ }
+ }
+
+ int best_error_weights[TUNE_MAX_TRIAL_CANDIDATES];
+
+ // Fast path the first result and avoid the list search for trial 0
+ best_error_weights[0] = index_of_best_combination;
+ if (index_of_best_combination >= 0)
+ {
+ errors_of_best_combination[index_of_best_combination] = ERROR_CALC_DEFAULT;
+ }
+
+ // Search the remaining results and pick the best candidate modes for trial 1+
+ for (unsigned int i = 1; i < tune_candidate_limit; i++)
+ {
+ vint vbest_error_index(-1);
+ vfloat vbest_ep_error(ERROR_CALC_DEFAULT);
+
+ start_block_mode = round_down_to_simd_multiple_vla(start_block_mode);
+ vint lane_ids = vint::lane_id() + vint(start_block_mode);
+ for (unsigned int j = start_block_mode; j < end_block_mode; j += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat err = vfloat(errors_of_best_combination + j);
+ vmask mask = err < vbest_ep_error;
+ vbest_ep_error = select(vbest_ep_error, err, mask);
+ vbest_error_index = select(vbest_error_index, lane_ids, mask);
+ lane_ids += vint(ASTCENC_SIMD_WIDTH);
+ }
+
+ // Pick best mode from the SIMD result, using lowest matching index to ensure invariance
+ vmask lanes_min_error = vbest_ep_error == hmin(vbest_ep_error);
+ vbest_error_index = select(vint(0x7FFFFFFF), vbest_error_index, lanes_min_error);
+ vbest_error_index = hmin(vbest_error_index);
+ int best_error_index = vbest_error_index.lane<0>();
+
+ best_error_weights[i] = best_error_index;
+
+ // Max the error for this candidate so we don't pick it again
+ if (best_error_index >= 0)
+ {
+ errors_of_best_combination[best_error_index] = ERROR_CALC_DEFAULT;
+ }
+ // Early-out if no more candidates are valid
+ else
+ {
+ break;
+ }
+ }
+
+ for (unsigned int i = 0; i < tune_candidate_limit; i++)
+ {
+ if (best_error_weights[i] < 0)
+ {
+ return i;
+ }
+
+ block_mode[i] = best_error_weights[i];
+
+ quant_level[i] = static_cast<quant_method>(best_quant_levels[best_error_weights[i]]);
+ quant_level_mod[i] = static_cast<quant_method>(best_quant_levels_mod[best_error_weights[i]]);
+
+ assert(quant_level[i] >= QUANT_6 && quant_level[i] <= QUANT_256);
+ assert(quant_level_mod[i] >= QUANT_6 && quant_level_mod[i] <= QUANT_256);
+
+ for (int j = 0; j < partition_count; j++)
+ {
+ partition_format_specifiers[i][j] = best_ep_formats[best_error_weights[i]][j];
+ }
+ }
+
+ return tune_candidate_limit;
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_platform_isa_detection.cpp b/thirdparty/astcenc/astcenc_platform_isa_detection.cpp
new file mode 100644
index 0000000000..8ed98437ea
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_platform_isa_detection.cpp
@@ -0,0 +1,166 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2020-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Platform-specific function implementations.
+ *
+ * This module contains functions for querying the host extended ISA support.
+ */
+
+// Include before the defines below to pick up any auto-setup based on compiler
+// built-in config, if not being set explicitly by the build system
+#include "astcenc_internal.h"
+
+#if (ASTCENC_SSE > 0) || (ASTCENC_AVX > 0) || \
+ (ASTCENC_POPCNT > 0) || (ASTCENC_F16C > 0)
+
+static bool g_init { false };
+
+/** Does this CPU support SSE 4.1? Set to -1 if not yet initialized. */
+static bool g_cpu_has_sse41 { false };
+
+/** Does this CPU support AVX2? Set to -1 if not yet initialized. */
+static bool g_cpu_has_avx2 { false };
+
+/** Does this CPU support POPCNT? Set to -1 if not yet initialized. */
+static bool g_cpu_has_popcnt { false };
+
+/** Does this CPU support F16C? Set to -1 if not yet initialized. */
+static bool g_cpu_has_f16c { false };
+
+/* ============================================================================
+ Platform code for Visual Studio
+============================================================================ */
+#if !defined(__clang__) && defined(_MSC_VER)
+#define WIN32_LEAN_AND_MEAN
+#include <windows.h>
+#include <intrin.h>
+
+/**
+ * @brief Detect platform CPU ISA support and update global trackers.
+ */
+static void detect_cpu_isa()
+{
+ int data[4];
+
+ __cpuid(data, 0);
+ int num_id = data[0];
+
+ if (num_id >= 1)
+ {
+ __cpuidex(data, 1, 0);
+ // SSE41 = Bank 1, ECX, bit 19
+ g_cpu_has_sse41 = data[2] & (1 << 19) ? true : false;
+ // POPCNT = Bank 1, ECX, bit 23
+ g_cpu_has_popcnt = data[2] & (1 << 23) ? true : false;
+ // F16C = Bank 1, ECX, bit 29
+ g_cpu_has_f16c = data[2] & (1 << 29) ? true : false;
+ }
+
+ if (num_id >= 7)
+ {
+ __cpuidex(data, 7, 0);
+ // AVX2 = Bank 7, EBX, bit 5
+ g_cpu_has_avx2 = data[1] & (1 << 5) ? true : false;
+ }
+
+ // Ensure state bits are updated before init flag is updated
+ MemoryBarrier();
+ g_init = true;
+}
+
+/* ============================================================================
+ Platform code for GCC and Clang
+============================================================================ */
+#else
+#include <cpuid.h>
+
+/**
+ * @brief Detect platform CPU ISA support and update global trackers.
+ */
+static void detect_cpu_isa()
+{
+ unsigned int data[4];
+
+ if (__get_cpuid_count(1, 0, &data[0], &data[1], &data[2], &data[3]))
+ {
+ // SSE41 = Bank 1, ECX, bit 19
+ g_cpu_has_sse41 = data[2] & (1 << 19) ? true : false;
+ // POPCNT = Bank 1, ECX, bit 23
+ g_cpu_has_popcnt = data[2] & (1 << 23) ? true : false;
+ // F16C = Bank 1, ECX, bit 29
+ g_cpu_has_f16c = data[2] & (1 << 29) ? true : false;
+ }
+
+ g_cpu_has_avx2 = 0;
+ if (__get_cpuid_count(7, 0, &data[0], &data[1], &data[2], &data[3]))
+ {
+ // AVX2 = Bank 7, EBX, bit 5
+ g_cpu_has_avx2 = data[1] & (1 << 5) ? true : false;
+ }
+
+ // Ensure state bits are updated before init flag is updated
+ __sync_synchronize();
+ g_init = true;
+}
+#endif
+
+/* See header for documentation. */
+bool cpu_supports_popcnt()
+{
+ if (!g_init)
+ {
+ detect_cpu_isa();
+ }
+
+ return g_cpu_has_popcnt;
+}
+
+/* See header for documentation. */
+bool cpu_supports_f16c()
+{
+ if (!g_init)
+ {
+ detect_cpu_isa();
+ }
+
+ return g_cpu_has_f16c;
+}
+
+/* See header for documentation. */
+bool cpu_supports_sse41()
+{
+ if (!g_init)
+ {
+ detect_cpu_isa();
+ }
+
+ return g_cpu_has_sse41;
+}
+
+/* See header for documentation. */
+bool cpu_supports_avx2()
+{
+ if (!g_init)
+ {
+ detect_cpu_isa();
+ }
+
+ return g_cpu_has_avx2;
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_quantization.cpp b/thirdparty/astcenc/astcenc_quantization.cpp
new file mode 100644
index 0000000000..478a21ead7
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_quantization.cpp
@@ -0,0 +1,904 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions and data tables for numeric quantization..
+ */
+
+#include "astcenc_internal.h"
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+// Starts from QUANT_6
+// Not scrambled
+const uint8_t color_unquant_to_uquant_tables[17][256] {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 153, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
+ 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
+ 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
+ 204, 204, 204, 204, 204, 204, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36, 36,
+ 36, 36, 36, 36, 36, 36, 36, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73,
+ 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 73, 109, 109, 109, 109,
+ 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109,
+ 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109, 109,
+ 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+ 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146, 146,
+ 146, 146, 146, 146, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182, 182,
+ 182, 182, 182, 182, 182, 182, 182, 182, 182, 219, 219, 219, 219, 219, 219, 219,
+ 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219,
+ 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 219, 255, 255, 255,
+ 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28,
+ 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 28, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56, 56,
+ 56, 56, 56, 56, 56, 56, 56, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84, 84,
+ 84, 84, 84, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113,
+ 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113, 113,
+ 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142,
+ 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 142, 171, 171, 171,
+ 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171, 171,
+ 171, 171, 171, 171, 171, 171, 171, 171, 171, 199, 199, 199, 199, 199, 199, 199,
+ 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199, 199,
+ 199, 199, 199, 199, 199, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227,
+ 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227, 227,
+ 227, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 23, 23, 23, 23,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 23, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 46,
+ 46, 46, 46, 46, 46, 46, 46, 46, 46, 46, 69, 69, 69, 69, 69, 69,
+ 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69, 69,
+ 69, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92, 92,
+ 92, 92, 92, 92, 92, 92, 92, 92, 92, 116, 116, 116, 116, 116, 116, 116,
+ 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116, 116,
+ 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139, 139,
+ 139, 139, 139, 139, 139, 139, 139, 163, 163, 163, 163, 163, 163, 163, 163, 163,
+ 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 163, 186,
+ 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186, 186,
+ 186, 186, 186, 186, 186, 186, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209,
+ 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 209, 232, 232, 232,
+ 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232, 232,
+ 232, 232, 232, 232, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 17, 17, 17, 17, 17, 17, 17,
+ 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 34, 34, 34, 34, 34, 34,
+ 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 34, 51, 51, 51, 51, 51,
+ 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 51, 68, 68, 68, 68,
+ 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 68, 85, 85, 85,
+ 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 85, 102, 102,
+ 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 102, 119,
+ 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119, 119,
+ 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136, 136,
+ 136, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153, 153,
+ 153, 153, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170, 170,
+ 170, 170, 170, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187, 187,
+ 187, 187, 187, 187, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204, 204,
+ 204, 204, 204, 204, 204, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221, 221,
+ 221, 221, 221, 221, 221, 221, 238, 238, 238, 238, 238, 238, 238, 238, 238, 238,
+ 238, 238, 238, 238, 238, 238, 238, 255, 255, 255, 255, 255, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27, 27,
+ 27, 27, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40, 40,
+ 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, 67, 67, 67,
+ 67, 67, 67, 67, 67, 67, 67, 67, 67, 67, 80, 80, 80, 80, 80, 80,
+ 80, 80, 80, 80, 80, 80, 80, 80, 94, 94, 94, 94, 94, 94, 94, 94,
+ 94, 94, 94, 94, 94, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107, 107,
+ 107, 107, 107, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 148, 148, 148,
+ 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 148, 161, 161, 161, 161, 161,
+ 161, 161, 161, 161, 161, 161, 161, 161, 175, 175, 175, 175, 175, 175, 175, 175,
+ 175, 175, 175, 175, 175, 175, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188,
+ 188, 188, 188, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201, 201,
+ 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 215, 228, 228,
+ 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 228, 242, 242, 242, 242, 242,
+ 242, 242, 242, 242, 242, 242, 242, 242, 242, 255, 255, 255, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 33, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 33, 44, 44, 44, 44, 44, 44, 44, 44, 44,
+ 44, 44, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 55, 66, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 66, 77, 77, 77, 77, 77, 77, 77, 77,
+ 77, 77, 77, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 88, 99, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 99, 110, 110, 110, 110, 110, 110, 110,
+ 110, 110, 110, 110, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121, 121,
+ 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 134, 145, 145, 145, 145,
+ 145, 145, 145, 145, 145, 145, 145, 156, 156, 156, 156, 156, 156, 156, 156, 156,
+ 156, 156, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 167, 178, 178, 178,
+ 178, 178, 178, 178, 178, 178, 178, 178, 189, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 189, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 200, 211, 211,
+ 211, 211, 211, 211, 211, 211, 211, 211, 211, 222, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 222, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 233, 244,
+ 244, 244, 244, 244, 244, 244, 244, 244, 244, 244, 255, 255, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 16, 16, 16,
+ 16, 16, 16, 16, 16, 24, 24, 24, 24, 24, 24, 24, 24, 33, 33, 33,
+ 33, 33, 33, 33, 33, 33, 41, 41, 41, 41, 41, 41, 41, 41, 49, 49,
+ 49, 49, 49, 49, 49, 49, 57, 57, 57, 57, 57, 57, 57, 57, 66, 66,
+ 66, 66, 66, 66, 66, 66, 66, 74, 74, 74, 74, 74, 74, 74, 74, 82,
+ 82, 82, 82, 82, 82, 82, 82, 90, 90, 90, 90, 90, 90, 90, 90, 99,
+ 99, 99, 99, 99, 99, 99, 99, 99, 107, 107, 107, 107, 107, 107, 107, 107,
+ 115, 115, 115, 115, 115, 115, 115, 115, 123, 123, 123, 123, 123, 123, 123, 123,
+ 132, 132, 132, 132, 132, 132, 132, 132, 140, 140, 140, 140, 140, 140, 140, 140,
+ 148, 148, 148, 148, 148, 148, 148, 148, 156, 156, 156, 156, 156, 156, 156, 156,
+ 156, 165, 165, 165, 165, 165, 165, 165, 165, 173, 173, 173, 173, 173, 173, 173,
+ 173, 181, 181, 181, 181, 181, 181, 181, 181, 189, 189, 189, 189, 189, 189, 189,
+ 189, 189, 198, 198, 198, 198, 198, 198, 198, 198, 206, 206, 206, 206, 206, 206,
+ 206, 206, 214, 214, 214, 214, 214, 214, 214, 214, 222, 222, 222, 222, 222, 222,
+ 222, 222, 222, 231, 231, 231, 231, 231, 231, 231, 231, 239, 239, 239, 239, 239,
+ 239, 239, 239, 247, 247, 247, 247, 247, 247, 247, 247, 255, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 0, 6, 6, 6, 6, 6, 6, 13, 13, 13, 13, 13, 13,
+ 13, 19, 19, 19, 19, 19, 19, 26, 26, 26, 26, 26, 26, 26, 32, 32,
+ 32, 32, 32, 32, 39, 39, 39, 39, 39, 39, 39, 45, 45, 45, 45, 45,
+ 45, 52, 52, 52, 52, 52, 52, 52, 58, 58, 58, 58, 58, 58, 65, 65,
+ 65, 65, 65, 65, 65, 71, 71, 71, 71, 71, 71, 78, 78, 78, 78, 78,
+ 78, 78, 84, 84, 84, 84, 84, 84, 91, 91, 91, 91, 91, 91, 91, 97,
+ 97, 97, 97, 97, 97, 104, 104, 104, 104, 104, 104, 104, 110, 110, 110, 110,
+ 110, 110, 117, 117, 117, 117, 117, 117, 117, 123, 123, 123, 123, 123, 123, 123,
+ 132, 132, 132, 132, 132, 132, 132, 138, 138, 138, 138, 138, 138, 138, 145, 145,
+ 145, 145, 145, 145, 151, 151, 151, 151, 151, 151, 151, 158, 158, 158, 158, 158,
+ 158, 164, 164, 164, 164, 164, 164, 164, 171, 171, 171, 171, 171, 171, 177, 177,
+ 177, 177, 177, 177, 177, 184, 184, 184, 184, 184, 184, 190, 190, 190, 190, 190,
+ 190, 190, 197, 197, 197, 197, 197, 197, 203, 203, 203, 203, 203, 203, 203, 210,
+ 210, 210, 210, 210, 210, 216, 216, 216, 216, 216, 216, 216, 223, 223, 223, 223,
+ 223, 223, 229, 229, 229, 229, 229, 229, 229, 236, 236, 236, 236, 236, 236, 242,
+ 242, 242, 242, 242, 242, 242, 249, 249, 249, 249, 249, 249, 255, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 5, 5, 5, 5, 5, 5, 11, 11, 11, 11, 11, 16, 16,
+ 16, 16, 16, 21, 21, 21, 21, 21, 21, 27, 27, 27, 27, 27, 32, 32,
+ 32, 32, 32, 32, 38, 38, 38, 38, 38, 43, 43, 43, 43, 43, 48, 48,
+ 48, 48, 48, 48, 54, 54, 54, 54, 54, 59, 59, 59, 59, 59, 59, 65,
+ 65, 65, 65, 65, 70, 70, 70, 70, 70, 70, 76, 76, 76, 76, 76, 81,
+ 81, 81, 81, 81, 86, 86, 86, 86, 86, 86, 92, 92, 92, 92, 92, 97,
+ 97, 97, 97, 97, 97, 103, 103, 103, 103, 103, 108, 108, 108, 108, 108, 113,
+ 113, 113, 113, 113, 113, 119, 119, 119, 119, 119, 124, 124, 124, 124, 124, 124,
+ 131, 131, 131, 131, 131, 131, 136, 136, 136, 136, 136, 142, 142, 142, 142, 142,
+ 142, 147, 147, 147, 147, 147, 152, 152, 152, 152, 152, 158, 158, 158, 158, 158,
+ 158, 163, 163, 163, 163, 163, 169, 169, 169, 169, 169, 169, 174, 174, 174, 174,
+ 174, 179, 179, 179, 179, 179, 185, 185, 185, 185, 185, 185, 190, 190, 190, 190,
+ 190, 196, 196, 196, 196, 196, 196, 201, 201, 201, 201, 201, 207, 207, 207, 207,
+ 207, 207, 212, 212, 212, 212, 212, 217, 217, 217, 217, 217, 223, 223, 223, 223,
+ 223, 223, 228, 228, 228, 228, 228, 234, 234, 234, 234, 234, 234, 239, 239, 239,
+ 239, 239, 244, 244, 244, 244, 244, 250, 250, 250, 250, 250, 250, 255, 255, 255
+ },
+ {
+ 0, 0, 0, 4, 4, 4, 4, 8, 8, 8, 8, 12, 12, 12, 12, 16,
+ 16, 16, 16, 20, 20, 20, 20, 24, 24, 24, 24, 28, 28, 28, 28, 32,
+ 32, 32, 32, 36, 36, 36, 36, 40, 40, 40, 40, 44, 44, 44, 44, 48,
+ 48, 48, 48, 52, 52, 52, 52, 56, 56, 56, 56, 60, 60, 60, 60, 65,
+ 65, 65, 65, 65, 69, 69, 69, 69, 73, 73, 73, 73, 77, 77, 77, 77,
+ 81, 81, 81, 81, 85, 85, 85, 85, 89, 89, 89, 89, 93, 93, 93, 93,
+ 97, 97, 97, 97, 101, 101, 101, 101, 105, 105, 105, 105, 109, 109, 109, 109,
+ 113, 113, 113, 113, 117, 117, 117, 117, 121, 121, 121, 121, 125, 125, 125, 125,
+ 130, 130, 130, 130, 134, 134, 134, 134, 138, 138, 138, 138, 142, 142, 142, 142,
+ 146, 146, 146, 146, 150, 150, 150, 150, 154, 154, 154, 154, 158, 158, 158, 158,
+ 162, 162, 162, 162, 166, 166, 166, 166, 170, 170, 170, 170, 174, 174, 174, 174,
+ 178, 178, 178, 178, 182, 182, 182, 182, 186, 186, 186, 186, 190, 190, 190, 190,
+ 190, 195, 195, 195, 195, 199, 199, 199, 199, 203, 203, 203, 203, 207, 207, 207,
+ 207, 211, 211, 211, 211, 215, 215, 215, 215, 219, 219, 219, 219, 223, 223, 223,
+ 223, 227, 227, 227, 227, 231, 231, 231, 231, 235, 235, 235, 235, 239, 239, 239,
+ 239, 243, 243, 243, 243, 247, 247, 247, 247, 251, 251, 251, 251, 255, 255, 255
+ },
+ {
+ 0, 0, 3, 3, 3, 6, 6, 6, 9, 9, 9, 9, 13, 13, 13, 16,
+ 16, 16, 19, 19, 19, 22, 22, 22, 25, 25, 25, 25, 29, 29, 29, 32,
+ 32, 32, 35, 35, 35, 38, 38, 38, 38, 42, 42, 42, 45, 45, 45, 48,
+ 48, 48, 51, 51, 51, 54, 54, 54, 54, 58, 58, 58, 61, 61, 61, 64,
+ 64, 64, 67, 67, 67, 67, 71, 71, 71, 74, 74, 74, 77, 77, 77, 80,
+ 80, 80, 83, 83, 83, 83, 87, 87, 87, 90, 90, 90, 93, 93, 93, 96,
+ 96, 96, 96, 100, 100, 100, 103, 103, 103, 106, 106, 106, 109, 109, 109, 112,
+ 112, 112, 112, 116, 116, 116, 119, 119, 119, 122, 122, 122, 125, 125, 125, 125,
+ 130, 130, 130, 130, 133, 133, 133, 136, 136, 136, 139, 139, 139, 143, 143, 143,
+ 143, 146, 146, 146, 149, 149, 149, 152, 152, 152, 155, 155, 155, 159, 159, 159,
+ 159, 162, 162, 162, 165, 165, 165, 168, 168, 168, 172, 172, 172, 172, 175, 175,
+ 175, 178, 178, 178, 181, 181, 181, 184, 184, 184, 188, 188, 188, 188, 191, 191,
+ 191, 194, 194, 194, 197, 197, 197, 201, 201, 201, 201, 204, 204, 204, 207, 207,
+ 207, 210, 210, 210, 213, 213, 213, 217, 217, 217, 217, 220, 220, 220, 223, 223,
+ 223, 226, 226, 226, 230, 230, 230, 230, 233, 233, 233, 236, 236, 236, 239, 239,
+ 239, 242, 242, 242, 246, 246, 246, 246, 249, 249, 249, 252, 252, 252, 255, 255
+ },
+ {
+ 0, 0, 2, 2, 5, 5, 5, 8, 8, 8, 10, 10, 13, 13, 13, 16,
+ 16, 16, 18, 18, 21, 21, 21, 24, 24, 24, 26, 26, 29, 29, 29, 32,
+ 32, 32, 35, 35, 35, 37, 37, 40, 40, 40, 43, 43, 43, 45, 45, 48,
+ 48, 48, 51, 51, 51, 53, 53, 56, 56, 56, 59, 59, 59, 61, 61, 64,
+ 64, 64, 67, 67, 67, 70, 70, 70, 72, 72, 75, 75, 75, 78, 78, 78,
+ 80, 80, 83, 83, 83, 86, 86, 86, 88, 88, 91, 91, 91, 94, 94, 94,
+ 96, 96, 99, 99, 99, 102, 102, 102, 104, 104, 107, 107, 107, 110, 110, 110,
+ 112, 112, 115, 115, 115, 118, 118, 118, 120, 120, 123, 123, 123, 126, 126, 126,
+ 129, 129, 129, 132, 132, 132, 135, 135, 137, 137, 137, 140, 140, 140, 143, 143,
+ 145, 145, 145, 148, 148, 148, 151, 151, 153, 153, 153, 156, 156, 156, 159, 159,
+ 161, 161, 161, 164, 164, 164, 167, 167, 169, 169, 169, 172, 172, 172, 175, 175,
+ 177, 177, 177, 180, 180, 180, 183, 183, 185, 185, 185, 188, 188, 188, 191, 191,
+ 191, 194, 194, 196, 196, 196, 199, 199, 199, 202, 202, 204, 204, 204, 207, 207,
+ 207, 210, 210, 212, 212, 212, 215, 215, 215, 218, 218, 220, 220, 220, 223, 223,
+ 223, 226, 226, 226, 229, 229, 231, 231, 231, 234, 234, 234, 237, 237, 239, 239,
+ 239, 242, 242, 242, 245, 245, 247, 247, 247, 250, 250, 250, 253, 253, 255, 255
+ },
+ {
+ 0, 0, 2, 2, 4, 4, 6, 6, 8, 8, 10, 10, 12, 12, 14, 14,
+ 16, 16, 18, 18, 20, 20, 22, 22, 24, 24, 26, 26, 28, 28, 30, 30,
+ 32, 32, 34, 34, 36, 36, 38, 38, 40, 40, 42, 42, 44, 44, 46, 46,
+ 48, 48, 50, 50, 52, 52, 54, 54, 56, 56, 58, 58, 60, 60, 62, 62,
+ 64, 64, 66, 66, 68, 68, 70, 70, 72, 72, 74, 74, 76, 76, 78, 78,
+ 80, 80, 82, 82, 84, 84, 86, 86, 88, 88, 90, 90, 92, 92, 94, 94,
+ 96, 96, 98, 98, 100, 100, 102, 102, 104, 104, 106, 106, 108, 108, 110, 110,
+ 112, 112, 114, 114, 116, 116, 118, 118, 120, 120, 122, 122, 124, 124, 126, 126,
+ 129, 129, 131, 131, 133, 133, 135, 135, 137, 137, 139, 139, 141, 141, 143, 143,
+ 145, 145, 147, 147, 149, 149, 151, 151, 153, 153, 155, 155, 157, 157, 159, 159,
+ 161, 161, 163, 163, 165, 165, 167, 167, 169, 169, 171, 171, 173, 173, 175, 175,
+ 177, 177, 179, 179, 181, 181, 183, 183, 185, 185, 187, 187, 189, 189, 191, 191,
+ 193, 193, 195, 195, 197, 197, 199, 199, 201, 201, 203, 203, 205, 205, 207, 207,
+ 209, 209, 211, 211, 213, 213, 215, 215, 217, 217, 219, 219, 221, 221, 223, 223,
+ 225, 225, 227, 227, 229, 229, 231, 231, 233, 233, 235, 235, 237, 237, 239, 239,
+ 241, 241, 243, 243, 245, 245, 247, 247, 249, 249, 251, 251, 253, 253, 255, 255
+ },
+ {
+ 0, 1, 1, 3, 4, 4, 6, 6, 8, 9, 9, 11, 12, 12, 14, 14,
+ 16, 17, 17, 19, 20, 20, 22, 22, 24, 25, 25, 27, 28, 28, 30, 30,
+ 32, 33, 33, 35, 36, 36, 38, 38, 40, 41, 41, 43, 44, 44, 46, 46,
+ 48, 49, 49, 51, 52, 52, 54, 54, 56, 57, 57, 59, 60, 60, 62, 62,
+ 64, 65, 65, 67, 68, 68, 70, 70, 72, 73, 73, 75, 76, 76, 78, 78,
+ 80, 81, 81, 83, 84, 84, 86, 86, 88, 89, 89, 91, 92, 92, 94, 94,
+ 96, 97, 97, 99, 100, 100, 102, 102, 104, 105, 105, 107, 108, 108, 110, 110,
+ 112, 113, 113, 115, 116, 116, 118, 118, 120, 121, 121, 123, 124, 124, 126, 126,
+ 129, 129, 131, 131, 132, 134, 134, 135, 137, 137, 139, 139, 140, 142, 142, 143,
+ 145, 145, 147, 147, 148, 150, 150, 151, 153, 153, 155, 155, 156, 158, 158, 159,
+ 161, 161, 163, 163, 164, 166, 166, 167, 169, 169, 171, 171, 172, 174, 174, 175,
+ 177, 177, 179, 179, 180, 182, 182, 183, 185, 185, 187, 187, 188, 190, 190, 191,
+ 193, 193, 195, 195, 196, 198, 198, 199, 201, 201, 203, 203, 204, 206, 206, 207,
+ 209, 209, 211, 211, 212, 214, 214, 215, 217, 217, 219, 219, 220, 222, 222, 223,
+ 225, 225, 227, 227, 228, 230, 230, 231, 233, 233, 235, 235, 236, 238, 238, 239,
+ 241, 241, 243, 243, 244, 246, 246, 247, 249, 249, 251, 251, 252, 254, 254, 255
+ },
+ {
+ 0, 1, 2, 2, 4, 5, 6, 6, 8, 9, 10, 10, 12, 13, 14, 14,
+ 16, 17, 18, 18, 20, 21, 22, 22, 24, 25, 26, 26, 28, 29, 30, 30,
+ 32, 33, 34, 34, 36, 37, 38, 38, 40, 41, 42, 42, 44, 45, 46, 46,
+ 48, 49, 50, 50, 52, 53, 54, 54, 56, 57, 58, 58, 60, 61, 62, 62,
+ 64, 65, 66, 66, 68, 69, 70, 70, 72, 73, 74, 74, 76, 77, 78, 78,
+ 80, 81, 82, 82, 84, 85, 86, 86, 88, 89, 90, 90, 92, 93, 94, 94,
+ 96, 97, 98, 98, 100, 101, 102, 102, 104, 105, 106, 106, 108, 109, 110, 110,
+ 112, 113, 114, 114, 116, 117, 118, 118, 120, 121, 122, 122, 124, 125, 126, 126,
+ 129, 129, 130, 131, 133, 133, 134, 135, 137, 137, 138, 139, 141, 141, 142, 143,
+ 145, 145, 146, 147, 149, 149, 150, 151, 153, 153, 154, 155, 157, 157, 158, 159,
+ 161, 161, 162, 163, 165, 165, 166, 167, 169, 169, 170, 171, 173, 173, 174, 175,
+ 177, 177, 178, 179, 181, 181, 182, 183, 185, 185, 186, 187, 189, 189, 190, 191,
+ 193, 193, 194, 195, 197, 197, 198, 199, 201, 201, 202, 203, 205, 205, 206, 207,
+ 209, 209, 210, 211, 213, 213, 214, 215, 217, 217, 218, 219, 221, 221, 222, 223,
+ 225, 225, 226, 227, 229, 229, 230, 231, 233, 233, 234, 235, 237, 237, 238, 239,
+ 241, 241, 242, 243, 245, 245, 246, 247, 249, 249, 250, 251, 253, 253, 254, 255
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+ }
+};
+
+// Starts from QUANT_6
+// Scrambled
+const uint8_t color_uquant_to_scrambled_pquant_tables[17][256] {
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
+ 2, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1,
+ 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 7,
+ 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9,
+ 9, 9, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, 15
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 0, 4, 4, 4, 4, 4, 4, 4, 4, 4,
+ 4, 4, 4, 4, 4, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 8, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12, 12,
+ 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 6, 6, 6, 6, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 10, 10, 10, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18,
+ 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, 11, 11, 11, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 7, 7, 7, 7, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17,
+ 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 13, 9, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 5, 5, 5, 5, 5,
+ 5, 5, 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, 1, 1, 1, 1
+ },
+ {
+ 0, 0, 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8,
+ 8, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 16, 2, 2, 2, 2,
+ 2, 2, 2, 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 10, 10,
+ 10, 10, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 18, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 4, 4, 12, 12, 12, 12, 12, 12, 12, 12,
+ 12, 12, 12, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 6, 6,
+ 6, 6, 6, 6, 6, 6, 6, 6, 6, 14, 14, 14, 14, 14, 14, 14,
+ 14, 14, 14, 14, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22,
+ 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 23, 15, 15, 15, 15,
+ 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7, 7, 7, 7, 7,
+ 7, 7, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 21, 13, 13, 13,
+ 13, 13, 13, 13, 13, 13, 13, 13, 5, 5, 5, 5, 5, 5, 5, 5,
+ 5, 5, 5, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 19, 11, 11,
+ 11, 11, 11, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3, 3, 3, 3,
+ 3, 3, 3, 3, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 17, 9,
+ 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1, 1, 1
+ },
+ {
+ 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2,
+ 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6,
+ 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8,
+ 8, 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 10,
+ 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12,
+ 12, 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15,
+ 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17,
+ 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, 19,
+ 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21,
+ 21, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, 23,
+ 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25,
+ 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27,
+ 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29,
+ 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31
+ },
+ {
+ 0, 0, 0, 0, 8, 8, 8, 8, 8, 8, 16, 16, 16, 16, 16, 16,
+ 16, 24, 24, 24, 24, 24, 24, 32, 32, 32, 32, 32, 32, 32, 2, 2,
+ 2, 2, 2, 2, 10, 10, 10, 10, 10, 10, 10, 18, 18, 18, 18, 18,
+ 18, 26, 26, 26, 26, 26, 26, 26, 34, 34, 34, 34, 34, 34, 4, 4,
+ 4, 4, 4, 4, 4, 12, 12, 12, 12, 12, 12, 20, 20, 20, 20, 20,
+ 20, 20, 28, 28, 28, 28, 28, 28, 36, 36, 36, 36, 36, 36, 36, 6,
+ 6, 6, 6, 6, 6, 14, 14, 14, 14, 14, 14, 14, 22, 22, 22, 22,
+ 22, 22, 30, 30, 30, 30, 30, 30, 30, 38, 38, 38, 38, 38, 38, 38,
+ 39, 39, 39, 39, 39, 39, 39, 31, 31, 31, 31, 31, 31, 31, 23, 23,
+ 23, 23, 23, 23, 15, 15, 15, 15, 15, 15, 15, 7, 7, 7, 7, 7,
+ 7, 37, 37, 37, 37, 37, 37, 37, 29, 29, 29, 29, 29, 29, 21, 21,
+ 21, 21, 21, 21, 21, 13, 13, 13, 13, 13, 13, 5, 5, 5, 5, 5,
+ 5, 5, 35, 35, 35, 35, 35, 35, 27, 27, 27, 27, 27, 27, 27, 19,
+ 19, 19, 19, 19, 19, 11, 11, 11, 11, 11, 11, 11, 3, 3, 3, 3,
+ 3, 3, 33, 33, 33, 33, 33, 33, 33, 25, 25, 25, 25, 25, 25, 17,
+ 17, 17, 17, 17, 17, 17, 9, 9, 9, 9, 9, 9, 1, 1, 1, 1
+ },
+ {
+ 0, 0, 0, 16, 16, 16, 16, 16, 16, 32, 32, 32, 32, 32, 2, 2,
+ 2, 2, 2, 18, 18, 18, 18, 18, 18, 34, 34, 34, 34, 34, 4, 4,
+ 4, 4, 4, 4, 20, 20, 20, 20, 20, 36, 36, 36, 36, 36, 6, 6,
+ 6, 6, 6, 6, 22, 22, 22, 22, 22, 38, 38, 38, 38, 38, 38, 8,
+ 8, 8, 8, 8, 24, 24, 24, 24, 24, 24, 40, 40, 40, 40, 40, 10,
+ 10, 10, 10, 10, 26, 26, 26, 26, 26, 26, 42, 42, 42, 42, 42, 12,
+ 12, 12, 12, 12, 12, 28, 28, 28, 28, 28, 44, 44, 44, 44, 44, 14,
+ 14, 14, 14, 14, 14, 30, 30, 30, 30, 30, 46, 46, 46, 46, 46, 46,
+ 47, 47, 47, 47, 47, 47, 31, 31, 31, 31, 31, 15, 15, 15, 15, 15,
+ 15, 45, 45, 45, 45, 45, 29, 29, 29, 29, 29, 13, 13, 13, 13, 13,
+ 13, 43, 43, 43, 43, 43, 27, 27, 27, 27, 27, 27, 11, 11, 11, 11,
+ 11, 41, 41, 41, 41, 41, 25, 25, 25, 25, 25, 25, 9, 9, 9, 9,
+ 9, 39, 39, 39, 39, 39, 39, 23, 23, 23, 23, 23, 7, 7, 7, 7,
+ 7, 7, 37, 37, 37, 37, 37, 21, 21, 21, 21, 21, 5, 5, 5, 5,
+ 5, 5, 35, 35, 35, 35, 35, 19, 19, 19, 19, 19, 19, 3, 3, 3,
+ 3, 3, 33, 33, 33, 33, 33, 17, 17, 17, 17, 17, 17, 1, 1, 1
+ },
+ {
+ 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3, 4,
+ 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 8,
+ 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11, 12,
+ 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15, 16,
+ 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+ 20, 20, 20, 20, 21, 21, 21, 21, 22, 22, 22, 22, 23, 23, 23, 23,
+ 24, 24, 24, 24, 25, 25, 25, 25, 26, 26, 26, 26, 27, 27, 27, 27,
+ 28, 28, 28, 28, 29, 29, 29, 29, 30, 30, 30, 30, 31, 31, 31, 31,
+ 32, 32, 32, 32, 33, 33, 33, 33, 34, 34, 34, 34, 35, 35, 35, 35,
+ 36, 36, 36, 36, 37, 37, 37, 37, 38, 38, 38, 38, 39, 39, 39, 39,
+ 40, 40, 40, 40, 41, 41, 41, 41, 42, 42, 42, 42, 43, 43, 43, 43,
+ 44, 44, 44, 44, 45, 45, 45, 45, 46, 46, 46, 46, 47, 47, 47, 47,
+ 47, 48, 48, 48, 48, 49, 49, 49, 49, 50, 50, 50, 50, 51, 51, 51,
+ 51, 52, 52, 52, 52, 53, 53, 53, 53, 54, 54, 54, 54, 55, 55, 55,
+ 55, 56, 56, 56, 56, 57, 57, 57, 57, 58, 58, 58, 58, 59, 59, 59,
+ 59, 60, 60, 60, 60, 61, 61, 61, 61, 62, 62, 62, 62, 63, 63, 63
+ },
+ {
+ 0, 0, 16, 16, 16, 32, 32, 32, 48, 48, 48, 48, 64, 64, 64, 2,
+ 2, 2, 18, 18, 18, 34, 34, 34, 50, 50, 50, 50, 66, 66, 66, 4,
+ 4, 4, 20, 20, 20, 36, 36, 36, 36, 52, 52, 52, 68, 68, 68, 6,
+ 6, 6, 22, 22, 22, 38, 38, 38, 38, 54, 54, 54, 70, 70, 70, 8,
+ 8, 8, 24, 24, 24, 24, 40, 40, 40, 56, 56, 56, 72, 72, 72, 10,
+ 10, 10, 26, 26, 26, 26, 42, 42, 42, 58, 58, 58, 74, 74, 74, 12,
+ 12, 12, 12, 28, 28, 28, 44, 44, 44, 60, 60, 60, 76, 76, 76, 14,
+ 14, 14, 14, 30, 30, 30, 46, 46, 46, 62, 62, 62, 78, 78, 78, 78,
+ 79, 79, 79, 79, 63, 63, 63, 47, 47, 47, 31, 31, 31, 15, 15, 15,
+ 15, 77, 77, 77, 61, 61, 61, 45, 45, 45, 29, 29, 29, 13, 13, 13,
+ 13, 75, 75, 75, 59, 59, 59, 43, 43, 43, 27, 27, 27, 27, 11, 11,
+ 11, 73, 73, 73, 57, 57, 57, 41, 41, 41, 25, 25, 25, 25, 9, 9,
+ 9, 71, 71, 71, 55, 55, 55, 39, 39, 39, 39, 23, 23, 23, 7, 7,
+ 7, 69, 69, 69, 53, 53, 53, 37, 37, 37, 37, 21, 21, 21, 5, 5,
+ 5, 67, 67, 67, 51, 51, 51, 51, 35, 35, 35, 19, 19, 19, 3, 3,
+ 3, 65, 65, 65, 49, 49, 49, 49, 33, 33, 33, 17, 17, 17, 1, 1
+ },
+ {
+ 0, 0, 32, 32, 64, 64, 64, 2, 2, 2, 34, 34, 66, 66, 66, 4,
+ 4, 4, 36, 36, 68, 68, 68, 6, 6, 6, 38, 38, 70, 70, 70, 8,
+ 8, 8, 40, 40, 40, 72, 72, 10, 10, 10, 42, 42, 42, 74, 74, 12,
+ 12, 12, 44, 44, 44, 76, 76, 14, 14, 14, 46, 46, 46, 78, 78, 16,
+ 16, 16, 48, 48, 48, 80, 80, 80, 18, 18, 50, 50, 50, 82, 82, 82,
+ 20, 20, 52, 52, 52, 84, 84, 84, 22, 22, 54, 54, 54, 86, 86, 86,
+ 24, 24, 56, 56, 56, 88, 88, 88, 26, 26, 58, 58, 58, 90, 90, 90,
+ 28, 28, 60, 60, 60, 92, 92, 92, 30, 30, 62, 62, 62, 94, 94, 94,
+ 95, 95, 95, 63, 63, 63, 31, 31, 93, 93, 93, 61, 61, 61, 29, 29,
+ 91, 91, 91, 59, 59, 59, 27, 27, 89, 89, 89, 57, 57, 57, 25, 25,
+ 87, 87, 87, 55, 55, 55, 23, 23, 85, 85, 85, 53, 53, 53, 21, 21,
+ 83, 83, 83, 51, 51, 51, 19, 19, 81, 81, 81, 49, 49, 49, 17, 17,
+ 17, 79, 79, 47, 47, 47, 15, 15, 15, 77, 77, 45, 45, 45, 13, 13,
+ 13, 75, 75, 43, 43, 43, 11, 11, 11, 73, 73, 41, 41, 41, 9, 9,
+ 9, 71, 71, 71, 39, 39, 7, 7, 7, 69, 69, 69, 37, 37, 5, 5,
+ 5, 67, 67, 67, 35, 35, 3, 3, 3, 65, 65, 65, 33, 33, 1, 1
+ },
+ {
+ 0, 0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 6, 7, 7,
+ 8, 8, 9, 9, 10, 10, 11, 11, 12, 12, 13, 13, 14, 14, 15, 15,
+ 16, 16, 17, 17, 18, 18, 19, 19, 20, 20, 21, 21, 22, 22, 23, 23,
+ 24, 24, 25, 25, 26, 26, 27, 27, 28, 28, 29, 29, 30, 30, 31, 31,
+ 32, 32, 33, 33, 34, 34, 35, 35, 36, 36, 37, 37, 38, 38, 39, 39,
+ 40, 40, 41, 41, 42, 42, 43, 43, 44, 44, 45, 45, 46, 46, 47, 47,
+ 48, 48, 49, 49, 50, 50, 51, 51, 52, 52, 53, 53, 54, 54, 55, 55,
+ 56, 56, 57, 57, 58, 58, 59, 59, 60, 60, 61, 61, 62, 62, 63, 63,
+ 64, 64, 65, 65, 66, 66, 67, 67, 68, 68, 69, 69, 70, 70, 71, 71,
+ 72, 72, 73, 73, 74, 74, 75, 75, 76, 76, 77, 77, 78, 78, 79, 79,
+ 80, 80, 81, 81, 82, 82, 83, 83, 84, 84, 85, 85, 86, 86, 87, 87,
+ 88, 88, 89, 89, 90, 90, 91, 91, 92, 92, 93, 93, 94, 94, 95, 95,
+ 96, 96, 97, 97, 98, 98, 99, 99, 100, 100, 101, 101, 102, 102, 103, 103,
+ 104, 104, 105, 105, 106, 106, 107, 107, 108, 108, 109, 109, 110, 110, 111, 111,
+ 112, 112, 113, 113, 114, 114, 115, 115, 116, 116, 117, 117, 118, 118, 119, 119,
+ 120, 120, 121, 121, 122, 122, 123, 123, 124, 124, 125, 125, 126, 126, 127, 127
+ },
+ {
+ 0, 32, 32, 64, 96, 96, 128, 128, 2, 34, 34, 66, 98, 98, 130, 130,
+ 4, 36, 36, 68, 100, 100, 132, 132, 6, 38, 38, 70, 102, 102, 134, 134,
+ 8, 40, 40, 72, 104, 104, 136, 136, 10, 42, 42, 74, 106, 106, 138, 138,
+ 12, 44, 44, 76, 108, 108, 140, 140, 14, 46, 46, 78, 110, 110, 142, 142,
+ 16, 48, 48, 80, 112, 112, 144, 144, 18, 50, 50, 82, 114, 114, 146, 146,
+ 20, 52, 52, 84, 116, 116, 148, 148, 22, 54, 54, 86, 118, 118, 150, 150,
+ 24, 56, 56, 88, 120, 120, 152, 152, 26, 58, 58, 90, 122, 122, 154, 154,
+ 28, 60, 60, 92, 124, 124, 156, 156, 30, 62, 62, 94, 126, 126, 158, 158,
+ 159, 159, 127, 127, 95, 63, 63, 31, 157, 157, 125, 125, 93, 61, 61, 29,
+ 155, 155, 123, 123, 91, 59, 59, 27, 153, 153, 121, 121, 89, 57, 57, 25,
+ 151, 151, 119, 119, 87, 55, 55, 23, 149, 149, 117, 117, 85, 53, 53, 21,
+ 147, 147, 115, 115, 83, 51, 51, 19, 145, 145, 113, 113, 81, 49, 49, 17,
+ 143, 143, 111, 111, 79, 47, 47, 15, 141, 141, 109, 109, 77, 45, 45, 13,
+ 139, 139, 107, 107, 75, 43, 43, 11, 137, 137, 105, 105, 73, 41, 41, 9,
+ 135, 135, 103, 103, 71, 39, 39, 7, 133, 133, 101, 101, 69, 37, 37, 5,
+ 131, 131, 99, 99, 67, 35, 35, 3, 129, 129, 97, 97, 65, 33, 33, 1
+ },
+ {
+ 0, 64, 128, 128, 2, 66, 130, 130, 4, 68, 132, 132, 6, 70, 134, 134,
+ 8, 72, 136, 136, 10, 74, 138, 138, 12, 76, 140, 140, 14, 78, 142, 142,
+ 16, 80, 144, 144, 18, 82, 146, 146, 20, 84, 148, 148, 22, 86, 150, 150,
+ 24, 88, 152, 152, 26, 90, 154, 154, 28, 92, 156, 156, 30, 94, 158, 158,
+ 32, 96, 160, 160, 34, 98, 162, 162, 36, 100, 164, 164, 38, 102, 166, 166,
+ 40, 104, 168, 168, 42, 106, 170, 170, 44, 108, 172, 172, 46, 110, 174, 174,
+ 48, 112, 176, 176, 50, 114, 178, 178, 52, 116, 180, 180, 54, 118, 182, 182,
+ 56, 120, 184, 184, 58, 122, 186, 186, 60, 124, 188, 188, 62, 126, 190, 190,
+ 191, 191, 127, 63, 189, 189, 125, 61, 187, 187, 123, 59, 185, 185, 121, 57,
+ 183, 183, 119, 55, 181, 181, 117, 53, 179, 179, 115, 51, 177, 177, 113, 49,
+ 175, 175, 111, 47, 173, 173, 109, 45, 171, 171, 107, 43, 169, 169, 105, 41,
+ 167, 167, 103, 39, 165, 165, 101, 37, 163, 163, 99, 35, 161, 161, 97, 33,
+ 159, 159, 95, 31, 157, 157, 93, 29, 155, 155, 91, 27, 153, 153, 89, 25,
+ 151, 151, 87, 23, 149, 149, 85, 21, 147, 147, 83, 19, 145, 145, 81, 17,
+ 143, 143, 79, 15, 141, 141, 77, 13, 139, 139, 75, 11, 137, 137, 73, 9,
+ 135, 135, 71, 7, 133, 133, 69, 5, 131, 131, 67, 3, 129, 129, 65, 1
+ },
+ {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+ }
+};
+
+#endif
+
+// Starts from QUANT_6
+// Scrambled
+static const uint8_t color_scrambled_pquant_to_uquant_q6[6] {
+ 0, 255, 51, 204, 102, 153
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q8[8] {
+ 0, 36, 73, 109, 146, 182, 219, 255
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q10[10] {
+ 0, 255, 28, 227, 56, 199, 84, 171, 113, 142
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q12[12] {
+ 0, 255, 69, 186, 23, 232, 92, 163, 46, 209, 116, 139
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q16[16] {
+ 0, 17, 34, 51, 68, 85, 102, 119, 136, 153, 170, 187, 204, 221, 238, 255
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q20[20] {
+ 0, 255, 67, 188, 13, 242, 80, 175, 27, 228, 94, 161, 40, 215, 107, 148,
+ 54, 201, 121, 134
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q24[24] {
+ 0, 255, 33, 222, 66, 189, 99, 156, 11, 244, 44, 211, 77, 178, 110, 145,
+ 22, 233, 55, 200, 88, 167, 121, 134
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q32[32] {
+ 0, 8, 16, 24, 33, 41, 49, 57, 66, 74, 82, 90, 99, 107, 115, 123,
+ 132, 140, 148, 156, 165, 173, 181, 189, 198, 206, 214, 222, 231, 239, 247, 255
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q40[40] {
+ 0, 255, 32, 223, 65, 190, 97, 158, 6, 249, 39, 216, 71, 184, 104, 151,
+ 13, 242, 45, 210, 78, 177, 110, 145, 19, 236, 52, 203, 84, 171, 117, 138,
+ 26, 229, 58, 197, 91, 164, 123, 132
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q48[48] {
+ 0, 255, 16, 239, 32, 223, 48, 207, 65, 190, 81, 174, 97, 158, 113, 142,
+ 5, 250, 21, 234, 38, 217, 54, 201, 70, 185, 86, 169, 103, 152, 119, 136,
+ 11, 244, 27, 228, 43, 212, 59, 196, 76, 179, 92, 163, 108, 147, 124, 131
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q64[64] {
+ 0, 4, 8, 12, 16, 20, 24, 28, 32, 36, 40, 44, 48, 52, 56, 60,
+ 65, 69, 73, 77, 81, 85, 89, 93, 97, 101, 105, 109, 113, 117, 121, 125,
+ 130, 134, 138, 142, 146, 150, 154, 158, 162, 166, 170, 174, 178, 182, 186, 190,
+ 195, 199, 203, 207, 211, 215, 219, 223, 227, 231, 235, 239, 243, 247, 251, 255,
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q80[80] {
+ 0, 255, 16, 239, 32, 223, 48, 207, 64, 191, 80, 175, 96, 159, 112, 143,
+ 3, 252, 19, 236, 35, 220, 51, 204, 67, 188, 83, 172, 100, 155, 116, 139,
+ 6, 249, 22, 233, 38, 217, 54, 201, 71, 184, 87, 168, 103, 152, 119, 136,
+ 9, 246, 25, 230, 42, 213, 58, 197, 74, 181, 90, 165, 106, 149, 122, 133,
+ 13, 242, 29, 226, 45, 210, 61, 194, 77, 178, 93, 162, 109, 146, 125, 130
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q96[96] {
+ 0, 255, 8, 247, 16, 239, 24, 231, 32, 223, 40, 215, 48, 207, 56, 199,
+ 64, 191, 72, 183, 80, 175, 88, 167, 96, 159, 104, 151, 112, 143, 120, 135,
+ 2, 253, 10, 245, 18, 237, 26, 229, 35, 220, 43, 212, 51, 204, 59, 196,
+ 67, 188, 75, 180, 83, 172, 91, 164, 99, 156, 107, 148, 115, 140, 123, 132,
+ 5, 250, 13, 242, 21, 234, 29, 226, 37, 218, 45, 210, 53, 202, 61, 194,
+ 70, 185, 78, 177, 86, 169, 94, 161, 102, 153, 110, 145, 118, 137, 126, 129
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q128[128] {
+ 0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30,
+ 32, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62,
+ 64, 66, 68, 70, 72, 74, 76, 78, 80, 82, 84, 86, 88, 90, 92, 94,
+ 96, 98, 100, 102, 104, 106, 108, 110, 112, 114, 116, 118, 120, 122, 124, 126,
+ 129, 131, 133, 135, 137, 139, 141, 143, 145, 147, 149, 151, 153, 155, 157, 159,
+ 161, 163, 165, 167, 169, 171, 173, 175, 177, 179, 181, 183, 185, 187, 189, 191,
+ 193, 195, 197, 199, 201, 203, 205, 207, 209, 211, 213, 215, 217, 219, 221, 223,
+ 225, 227, 229, 231, 233, 235, 237, 239, 241, 243, 245, 247, 249, 251, 253, 255
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q160[160] {
+ 0, 255, 8, 247, 16, 239, 24, 231, 32, 223, 40, 215, 48, 207, 56, 199,
+ 64, 191, 72, 183, 80, 175, 88, 167, 96, 159, 104, 151, 112, 143, 120, 135,
+ 1, 254, 9, 246, 17, 238, 25, 230, 33, 222, 41, 214, 49, 206, 57, 198,
+ 65, 190, 73, 182, 81, 174, 89, 166, 97, 158, 105, 150, 113, 142, 121, 134,
+ 3, 252, 11, 244, 19, 236, 27, 228, 35, 220, 43, 212, 51, 204, 59, 196,
+ 67, 188, 75, 180, 83, 172, 91, 164, 99, 156, 107, 148, 115, 140, 123, 132,
+ 4, 251, 12, 243, 20, 235, 28, 227, 36, 219, 44, 211, 52, 203, 60, 195,
+ 68, 187, 76, 179, 84, 171, 92, 163, 100, 155, 108, 147, 116, 139, 124, 131,
+ 6, 249, 14, 241, 22, 233, 30, 225, 38, 217, 46, 209, 54, 201, 62, 193,
+ 70, 185, 78, 177, 86, 169, 94, 161, 102, 153, 110, 145, 118, 137, 126, 129
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q192[192] {
+ 0, 255, 4, 251, 8, 247, 12, 243, 16, 239, 20, 235, 24, 231, 28, 227,
+ 32, 223, 36, 219, 40, 215, 44, 211, 48, 207, 52, 203, 56, 199, 60, 195,
+ 64, 191, 68, 187, 72, 183, 76, 179, 80, 175, 84, 171, 88, 167, 92, 163,
+ 96, 159, 100, 155, 104, 151, 108, 147, 112, 143, 116, 139, 120, 135, 124, 131,
+ 1, 254, 5, 250, 9, 246, 13, 242, 17, 238, 21, 234, 25, 230, 29, 226,
+ 33, 222, 37, 218, 41, 214, 45, 210, 49, 206, 53, 202, 57, 198, 61, 194,
+ 65, 190, 69, 186, 73, 182, 77, 178, 81, 174, 85, 170, 89, 166, 93, 162,
+ 97, 158, 101, 154, 105, 150, 109, 146, 113, 142, 117, 138, 121, 134, 125, 130,
+ 2, 253, 6, 249, 10, 245, 14, 241, 18, 237, 22, 233, 26, 229, 30, 225,
+ 34, 221, 38, 217, 42, 213, 46, 209, 50, 205, 54, 201, 58, 197, 62, 193,
+ 66, 189, 70, 185, 74, 181, 78, 177, 82, 173, 86, 169, 90, 165, 94, 161,
+ 98, 157, 102, 153, 106, 149, 110, 145, 114, 141, 118, 137, 122, 133, 126, 129
+};
+
+static const uint8_t color_scrambled_pquant_to_uquant_q256[256] {
+ 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
+ 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
+ 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
+ 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
+ 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
+ 80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,
+ 96, 97, 98, 99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
+ 112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125, 126, 127,
+ 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143,
+ 144, 145, 146, 147, 148, 149, 150, 151, 152, 153, 154, 155, 156, 157, 158, 159,
+ 160, 161, 162, 163, 164, 165, 166, 167, 168, 169, 170, 171, 172, 173, 174, 175,
+ 176, 177, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191,
+ 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 203, 204, 205, 206, 207,
+ 208, 209, 210, 211, 212, 213, 214, 215, 216, 217, 218, 219, 220, 221, 222, 223,
+ 224, 225, 226, 227, 228, 229, 230, 231, 232, 233, 234, 235, 236, 237, 238, 239,
+ 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
+};
+
+const uint8_t* color_scrambled_pquant_to_uquant_tables[17] {
+ color_scrambled_pquant_to_uquant_q6,
+ color_scrambled_pquant_to_uquant_q8,
+ color_scrambled_pquant_to_uquant_q10,
+ color_scrambled_pquant_to_uquant_q12,
+ color_scrambled_pquant_to_uquant_q16,
+ color_scrambled_pquant_to_uquant_q20,
+ color_scrambled_pquant_to_uquant_q24,
+ color_scrambled_pquant_to_uquant_q32,
+ color_scrambled_pquant_to_uquant_q40,
+ color_scrambled_pquant_to_uquant_q48,
+ color_scrambled_pquant_to_uquant_q64,
+ color_scrambled_pquant_to_uquant_q80,
+ color_scrambled_pquant_to_uquant_q96,
+ color_scrambled_pquant_to_uquant_q128,
+ color_scrambled_pquant_to_uquant_q160,
+ color_scrambled_pquant_to_uquant_q192,
+ color_scrambled_pquant_to_uquant_q256
+};
+
+// The quant_mode_table[integer_count/2][bits] gives us the quantization level for a given integer
+// count and number of bits that the integer may fit into.
+const int8_t quant_mode_table[10][128] {
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1
+ },
+ {
+ -1, -1, 0, 0, 2, 3, 5, 6, 8, 9, 11, 12, 14, 15, 17, 18,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
+ },
+ {
+ -1, -1, -1, -1, 0, 0, 0, 1, 2, 2, 3, 4, 5, 5, 6, 7,
+ 8, 8, 9, 10, 11, 11, 12, 13, 14, 14, 15, 16, 17, 17, 18, 19,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
+ },
+ {
+ -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 1, 1, 2, 2, 3, 3,
+ 4, 4, 5, 5, 6, 6, 7, 7, 8, 8, 9, 9, 10, 10, 11, 11,
+ 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 17, 17, 18, 18, 19, 19,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
+ },
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 1, 1, 1,
+ 2, 2, 2, 3, 3, 4, 4, 4, 5, 5, 5, 6, 6, 7, 7, 7,
+ 8, 8, 8, 9, 9, 10, 10, 10, 11, 11, 11, 12, 12, 13, 13, 13,
+ 14, 14, 14, 15, 15, 16, 16, 16, 17, 17, 17, 18, 18, 19, 19, 19,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
+ },
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0, 0, 0,
+ 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 4, 4, 4, 4, 5, 5,
+ 5, 5, 6, 6, 7, 7, 7, 7, 8, 8, 8, 8, 9, 9, 10, 10,
+ 10, 10, 11, 11, 11, 11, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14,
+ 15, 15, 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 19, 19, 19, 19,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
+ },
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0, 0, 0,
+ 0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 2, 3, 3, 3, 3,
+ 4, 4, 4, 4, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7,
+ 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 11, 11, 11, 11,
+ 12, 12, 12, 12, 13, 13, 13, 13, 14, 14, 14, 14, 15, 15, 15, 15,
+ 16, 16, 16, 16, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
+ },
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 0, 0,
+ 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 2, 2, 2, 2,
+ 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 6,
+ 6, 6, 6, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 9, 9, 9,
+ 9, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13,
+ 13, 13, 13, 13, 14, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16,
+ 16, 16, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 19,
+ 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20, 20
+ },
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1,
+ 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 4, 4, 4, 4, 4, 4,
+ 5, 5, 5, 5, 5, 5, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7,
+ 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 10, 10, 10, 10, 10, 10,
+ 11, 11, 11, 11, 11, 11, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13,
+ 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16,
+ 17, 17, 17, 17, 17, 17, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19
+ },
+ {
+ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
+ -1, -1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1,
+ 1, 1, 1, 1, 2, 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 4,
+ 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 6, 6, 6, 6,
+ 6, 7, 7, 7, 7, 7, 7, 7, 8, 8, 8, 8, 8, 8, 9, 9,
+ 9, 9, 9, 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11,
+ 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 14, 14, 14, 14,
+ 14, 14, 15, 15, 15, 15, 15, 16, 16, 16, 16, 16, 16, 16, 17, 17
+ }
+};
diff --git a/thirdparty/astcenc/astcenc_symbolic_physical.cpp b/thirdparty/astcenc/astcenc_symbolic_physical.cpp
new file mode 100644
index 0000000000..80221a6013
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_symbolic_physical.cpp
@@ -0,0 +1,534 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Functions for converting between symbolic and physical encodings.
+ */
+
+#include "astcenc_internal.h"
+
+#include <cassert>
+
+/**
+ * @brief Write up to 8 bits at an arbitrary bit offset.
+ *
+ * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so
+ * may span two separate bytes in memory.
+ *
+ * @param value The value to write.
+ * @param bitcount The number of bits to write, starting from LSB.
+ * @param bitoffset The bit offset to store at, between 0 and 7.
+ * @param[in,out] ptr The data pointer to write to.
+ */
+static inline void write_bits(
+ int value,
+ int bitcount,
+ int bitoffset,
+ uint8_t* ptr
+) {
+ int mask = (1 << bitcount) - 1;
+ value &= mask;
+ ptr += bitoffset >> 3;
+ bitoffset &= 7;
+ value <<= bitoffset;
+ mask <<= bitoffset;
+ mask = ~mask;
+
+ ptr[0] &= mask;
+ ptr[0] |= value;
+ ptr[1] &= mask >> 8;
+ ptr[1] |= value >> 8;
+}
+
+/**
+ * @brief Read up to 8 bits at an arbitrary bit offset.
+ *
+ * The stored value is at most 8 bits, but can be stored at an offset of between 0 and 7 bits so may
+ * span two separate bytes in memory.
+ *
+ * @param bitcount The number of bits to read.
+ * @param bitoffset The bit offset to read from, between 0 and 7.
+ * @param[in,out] ptr The data pointer to read from.
+ *
+ * @return The read value.
+ */
+static inline int read_bits(
+ int bitcount,
+ int bitoffset,
+ const uint8_t* ptr
+) {
+ int mask = (1 << bitcount) - 1;
+ ptr += bitoffset >> 3;
+ bitoffset &= 7;
+ int value = ptr[0] | (ptr[1] << 8);
+ value >>= bitoffset;
+ value &= mask;
+ return value;
+}
+
+/**
+ * @brief Reverse bits in a byte.
+ *
+ * @param p The value to reverse.
+ *
+ * @return The reversed result.
+ */
+static inline int bitrev8(int p)
+{
+ p = ((p & 0x0F) << 4) | ((p >> 4) & 0x0F);
+ p = ((p & 0x33) << 2) | ((p >> 2) & 0x33);
+ p = ((p & 0x55) << 1) | ((p >> 1) & 0x55);
+ return p;
+}
+
+/* See header for documentation. */
+void symbolic_to_physical(
+ const block_size_descriptor& bsd,
+ const symbolic_compressed_block& scb,
+ physical_compressed_block& pcb
+) {
+ assert(scb.block_type != SYM_BTYPE_ERROR);
+
+ // Constant color block using UNORM16 colors
+ if (scb.block_type == SYM_BTYPE_CONST_U16)
+ {
+ // There is currently no attempt to coalesce larger void-extents
+ static const uint8_t cbytes[8] { 0xFC, 0xFD, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ for (unsigned int i = 0; i < 8; i++)
+ {
+ pcb.data[i] = cbytes[i];
+ }
+
+ for (unsigned int i = 0; i < BLOCK_MAX_COMPONENTS; i++)
+ {
+ pcb.data[2 * i + 8] = scb.constant_color[i] & 0xFF;
+ pcb.data[2 * i + 9] = (scb.constant_color[i] >> 8) & 0xFF;
+ }
+
+ return;
+ }
+
+ // Constant color block using FP16 colors
+ if (scb.block_type == SYM_BTYPE_CONST_F16)
+ {
+ // There is currently no attempt to coalesce larger void-extents
+ static const uint8_t cbytes[8] { 0xFC, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF };
+ for (unsigned int i = 0; i < 8; i++)
+ {
+ pcb.data[i] = cbytes[i];
+ }
+
+ for (unsigned int i = 0; i < BLOCK_MAX_COMPONENTS; i++)
+ {
+ pcb.data[2 * i + 8] = scb.constant_color[i] & 0xFF;
+ pcb.data[2 * i + 9] = (scb.constant_color[i] >> 8) & 0xFF;
+ }
+
+ return;
+ }
+
+ unsigned int partition_count = scb.partition_count;
+
+ // Compress the weights.
+ // They are encoded as an ordinary integer-sequence, then bit-reversed
+ uint8_t weightbuf[16] { 0 };
+
+ const auto& bm = bsd.get_block_mode(scb.block_mode);
+ const auto& di = bsd.get_decimation_info(bm.decimation_mode);
+ int weight_count = di.weight_count;
+ quant_method weight_quant_method = bm.get_weight_quant_mode();
+ float weight_quant_levels = static_cast<float>(get_quant_level(weight_quant_method));
+ int is_dual_plane = bm.is_dual_plane;
+
+ const auto& qat = quant_and_xfer_tables[weight_quant_method];
+
+ int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count;
+
+ int bits_for_weights = get_ise_sequence_bitcount(real_weight_count, weight_quant_method);
+
+ uint8_t weights[64];
+ if (is_dual_plane)
+ {
+ for (int i = 0; i < weight_count; i++)
+ {
+ float uqw = static_cast<float>(scb.weights[i]);
+ float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);
+ int qwi = static_cast<int>(qw + 0.5f);
+ weights[2 * i] = qat.scramble_map[qwi];
+
+ uqw = static_cast<float>(scb.weights[i + WEIGHTS_PLANE2_OFFSET]);
+ qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);
+ qwi = static_cast<int>(qw + 0.5f);
+ weights[2 * i + 1] = qat.scramble_map[qwi];
+ }
+ }
+ else
+ {
+ for (int i = 0; i < weight_count; i++)
+ {
+ float uqw = static_cast<float>(scb.weights[i]);
+ float qw = (uqw / 64.0f) * (weight_quant_levels - 1.0f);
+ int qwi = static_cast<int>(qw + 0.5f);
+ weights[i] = qat.scramble_map[qwi];
+ }
+ }
+
+ encode_ise(weight_quant_method, real_weight_count, weights, weightbuf, 0);
+
+ for (int i = 0; i < 16; i++)
+ {
+ pcb.data[i] = static_cast<uint8_t>(bitrev8(weightbuf[15 - i]));
+ }
+
+ write_bits(scb.block_mode, 11, 0, pcb.data);
+ write_bits(partition_count - 1, 2, 11, pcb.data);
+
+ int below_weights_pos = 128 - bits_for_weights;
+
+ // Encode partition index and color endpoint types for blocks with 2+ partitions
+ if (partition_count > 1)
+ {
+ write_bits(scb.partition_index, 6, 13, pcb.data);
+ write_bits(scb.partition_index >> 6, PARTITION_INDEX_BITS - 6, 19, pcb.data);
+
+ if (scb.color_formats_matched)
+ {
+ write_bits(scb.color_formats[0] << 2, 6, 13 + PARTITION_INDEX_BITS, pcb.data);
+ }
+ else
+ {
+ // Check endpoint types for each partition to determine the lowest class present
+ int low_class = 4;
+
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ int class_of_format = scb.color_formats[i] >> 2;
+ low_class = astc::min(class_of_format, low_class);
+ }
+
+ if (low_class == 3)
+ {
+ low_class = 2;
+ }
+
+ int encoded_type = low_class + 1;
+ int bitpos = 2;
+
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ int classbit_of_format = (scb.color_formats[i] >> 2) - low_class;
+ encoded_type |= classbit_of_format << bitpos;
+ bitpos++;
+ }
+
+ for (unsigned int i = 0; i < partition_count; i++)
+ {
+ int lowbits_of_format = scb.color_formats[i] & 3;
+ encoded_type |= lowbits_of_format << bitpos;
+ bitpos += 2;
+ }
+
+ int encoded_type_lowpart = encoded_type & 0x3F;
+ int encoded_type_highpart = encoded_type >> 6;
+ int encoded_type_highpart_size = (3 * partition_count) - 4;
+ int encoded_type_highpart_pos = 128 - bits_for_weights - encoded_type_highpart_size;
+ write_bits(encoded_type_lowpart, 6, 13 + PARTITION_INDEX_BITS, pcb.data);
+ write_bits(encoded_type_highpart, encoded_type_highpart_size, encoded_type_highpart_pos, pcb.data);
+ below_weights_pos -= encoded_type_highpart_size;
+ }
+ }
+ else
+ {
+ write_bits(scb.color_formats[0], 4, 13, pcb.data);
+ }
+
+ // In dual-plane mode, encode the color component of the second plane of weights
+ if (is_dual_plane)
+ {
+ write_bits(scb.plane2_component, 2, below_weights_pos - 2, pcb.data);
+ }
+
+ // Encode the color components
+ uint8_t values_to_encode[32];
+ int valuecount_to_encode = 0;
+
+ const uint8_t* pack_table = color_uquant_to_scrambled_pquant_tables[scb.quant_mode - QUANT_6];
+ for (unsigned int i = 0; i < scb.partition_count; i++)
+ {
+ int vals = 2 * (scb.color_formats[i] >> 2) + 2;
+ assert(vals <= 8);
+ for (int j = 0; j < vals; j++)
+ {
+ values_to_encode[j + valuecount_to_encode] = pack_table[scb.color_values[i][j]];
+ }
+ valuecount_to_encode += vals;
+ }
+
+ encode_ise(scb.get_color_quant_mode(), valuecount_to_encode, values_to_encode, pcb.data,
+ scb.partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS);
+}
+
+/* See header for documentation. */
+void physical_to_symbolic(
+ const block_size_descriptor& bsd,
+ const physical_compressed_block& pcb,
+ symbolic_compressed_block& scb
+) {
+ uint8_t bswapped[16];
+
+ scb.block_type = SYM_BTYPE_NONCONST;
+
+ // Extract header fields
+ int block_mode = read_bits(11, 0, pcb.data);
+ if ((block_mode & 0x1FF) == 0x1FC)
+ {
+ // Constant color block
+
+ // Check what format the data has
+ if (block_mode & 0x200)
+ {
+ scb.block_type = SYM_BTYPE_CONST_F16;
+ }
+ else
+ {
+ scb.block_type = SYM_BTYPE_CONST_U16;
+ }
+
+ scb.partition_count = 0;
+ for (int i = 0; i < 4; i++)
+ {
+ scb.constant_color[i] = pcb.data[2 * i + 8] | (pcb.data[2 * i + 9] << 8);
+ }
+
+ // Additionally, check that the void-extent
+ if (bsd.zdim == 1)
+ {
+ // 2D void-extent
+ int rsvbits = read_bits(2, 10, pcb.data);
+ if (rsvbits != 3)
+ {
+ scb.block_type = SYM_BTYPE_ERROR;
+ return;
+ }
+
+ int vx_low_s = read_bits(8, 12, pcb.data) | (read_bits(5, 12 + 8, pcb.data) << 8);
+ int vx_high_s = read_bits(8, 25, pcb.data) | (read_bits(5, 25 + 8, pcb.data) << 8);
+ int vx_low_t = read_bits(8, 38, pcb.data) | (read_bits(5, 38 + 8, pcb.data) << 8);
+ int vx_high_t = read_bits(8, 51, pcb.data) | (read_bits(5, 51 + 8, pcb.data) << 8);
+
+ int all_ones = vx_low_s == 0x1FFF && vx_high_s == 0x1FFF && vx_low_t == 0x1FFF && vx_high_t == 0x1FFF;
+
+ if ((vx_low_s >= vx_high_s || vx_low_t >= vx_high_t) && !all_ones)
+ {
+ scb.block_type = SYM_BTYPE_ERROR;
+ return;
+ }
+ }
+ else
+ {
+ // 3D void-extent
+ int vx_low_s = read_bits(9, 10, pcb.data);
+ int vx_high_s = read_bits(9, 19, pcb.data);
+ int vx_low_t = read_bits(9, 28, pcb.data);
+ int vx_high_t = read_bits(9, 37, pcb.data);
+ int vx_low_p = read_bits(9, 46, pcb.data);
+ int vx_high_p = read_bits(9, 55, pcb.data);
+
+ int all_ones = vx_low_s == 0x1FF && vx_high_s == 0x1FF && vx_low_t == 0x1FF && vx_high_t == 0x1FF && vx_low_p == 0x1FF && vx_high_p == 0x1FF;
+
+ if ((vx_low_s >= vx_high_s || vx_low_t >= vx_high_t || vx_low_p >= vx_high_p) && !all_ones)
+ {
+ scb.block_type = SYM_BTYPE_ERROR;
+ return;
+ }
+ }
+
+ return;
+ }
+
+ unsigned int packed_index = bsd.block_mode_packed_index[block_mode];
+ if (packed_index == BLOCK_BAD_BLOCK_MODE)
+ {
+ scb.block_type = SYM_BTYPE_ERROR;
+ return;
+ }
+
+ const auto& bm = bsd.get_block_mode(block_mode);
+ const auto& di = bsd.get_decimation_info(bm.decimation_mode);
+
+ int weight_count = di.weight_count;
+ promise(weight_count > 0);
+
+ quant_method weight_quant_method = static_cast<quant_method>(bm.quant_mode);
+ int is_dual_plane = bm.is_dual_plane;
+
+ int real_weight_count = is_dual_plane ? 2 * weight_count : weight_count;
+
+ int partition_count = read_bits(2, 11, pcb.data) + 1;
+ promise(partition_count > 0);
+
+ scb.block_mode = static_cast<uint16_t>(block_mode);
+ scb.partition_count = static_cast<uint8_t>(partition_count);
+
+ for (int i = 0; i < 16; i++)
+ {
+ bswapped[i] = static_cast<uint8_t>(bitrev8(pcb.data[15 - i]));
+ }
+
+ int bits_for_weights = get_ise_sequence_bitcount(real_weight_count, weight_quant_method);
+
+ int below_weights_pos = 128 - bits_for_weights;
+
+ uint8_t indices[64];
+ const auto& qat = quant_and_xfer_tables[weight_quant_method];
+
+ decode_ise(weight_quant_method, real_weight_count, bswapped, indices, 0);
+
+ if (is_dual_plane)
+ {
+ for (int i = 0; i < weight_count; i++)
+ {
+ scb.weights[i] = qat.unscramble_and_unquant_map[indices[2 * i]];
+ scb.weights[i + WEIGHTS_PLANE2_OFFSET] = qat.unscramble_and_unquant_map[indices[2 * i + 1]];
+ }
+ }
+ else
+ {
+ for (int i = 0; i < weight_count; i++)
+ {
+ scb.weights[i] = qat.unscramble_and_unquant_map[indices[i]];
+ }
+ }
+
+ if (is_dual_plane && partition_count == 4)
+ {
+ scb.block_type = SYM_BTYPE_ERROR;
+ return;
+ }
+
+ scb.color_formats_matched = 0;
+
+ // Determine the format of each endpoint pair
+ int color_formats[BLOCK_MAX_PARTITIONS];
+ int encoded_type_highpart_size = 0;
+ if (partition_count == 1)
+ {
+ color_formats[0] = read_bits(4, 13, pcb.data);
+ scb.partition_index = 0;
+ }
+ else
+ {
+ encoded_type_highpart_size = (3 * partition_count) - 4;
+ below_weights_pos -= encoded_type_highpart_size;
+ int encoded_type = read_bits(6, 13 + PARTITION_INDEX_BITS, pcb.data) | (read_bits(encoded_type_highpart_size, below_weights_pos, pcb.data) << 6);
+ int baseclass = encoded_type & 0x3;
+ if (baseclass == 0)
+ {
+ for (int i = 0; i < partition_count; i++)
+ {
+ color_formats[i] = (encoded_type >> 2) & 0xF;
+ }
+
+ below_weights_pos += encoded_type_highpart_size;
+ scb.color_formats_matched = 1;
+ encoded_type_highpart_size = 0;
+ }
+ else
+ {
+ int bitpos = 2;
+ baseclass--;
+
+ for (int i = 0; i < partition_count; i++)
+ {
+ color_formats[i] = (((encoded_type >> bitpos) & 1) + baseclass) << 2;
+ bitpos++;
+ }
+
+ for (int i = 0; i < partition_count; i++)
+ {
+ color_formats[i] |= (encoded_type >> bitpos) & 3;
+ bitpos += 2;
+ }
+ }
+ scb.partition_index = static_cast<uint16_t>(read_bits(6, 13, pcb.data) | (read_bits(PARTITION_INDEX_BITS - 6, 19, pcb.data) << 6));
+ }
+
+ for (int i = 0; i < partition_count; i++)
+ {
+ scb.color_formats[i] = static_cast<uint8_t>(color_formats[i]);
+ }
+
+ // Determine number of color endpoint integers
+ int color_integer_count = 0;
+ for (int i = 0; i < partition_count; i++)
+ {
+ int endpoint_class = color_formats[i] >> 2;
+ color_integer_count += (endpoint_class + 1) * 2;
+ }
+
+ if (color_integer_count > 18)
+ {
+ scb.block_type = SYM_BTYPE_ERROR;
+ return;
+ }
+
+ // Determine the color endpoint format to use
+ static const int color_bits_arr[5] { -1, 115 - 4, 113 - 4 - PARTITION_INDEX_BITS, 113 - 4 - PARTITION_INDEX_BITS, 113 - 4 - PARTITION_INDEX_BITS };
+ int color_bits = color_bits_arr[partition_count] - bits_for_weights - encoded_type_highpart_size;
+ if (is_dual_plane)
+ {
+ color_bits -= 2;
+ }
+
+ if (color_bits < 0)
+ {
+ color_bits = 0;
+ }
+
+ int color_quant_level = quant_mode_table[color_integer_count >> 1][color_bits];
+ if (color_quant_level < QUANT_6)
+ {
+ scb.block_type = SYM_BTYPE_ERROR;
+ return;
+ }
+
+ // Unpack the integer color values and assign to endpoints
+ scb.quant_mode = static_cast<quant_method>(color_quant_level);
+
+ uint8_t values_to_decode[32];
+ decode_ise(static_cast<quant_method>(color_quant_level), color_integer_count, pcb.data,
+ values_to_decode, (partition_count == 1 ? 17 : 19 + PARTITION_INDEX_BITS));
+
+ int valuecount_to_decode = 0;
+ const uint8_t* unpack_table = color_scrambled_pquant_to_uquant_tables[scb.quant_mode - QUANT_6];
+ for (int i = 0; i < partition_count; i++)
+ {
+ int vals = 2 * (color_formats[i] >> 2) + 2;
+ for (int j = 0; j < vals; j++)
+ {
+ scb.color_values[i][j] = unpack_table[values_to_decode[j + valuecount_to_decode]];
+ }
+ valuecount_to_decode += vals;
+ }
+
+ // Fetch component for second-plane in the case of dual plane of weights.
+ scb.plane2_component = -1;
+ if (is_dual_plane)
+ {
+ scb.plane2_component = static_cast<int8_t>(read_bits(2, below_weights_pos - 2, pcb.data));
+ }
+}
diff --git a/thirdparty/astcenc/astcenc_vecmathlib.h b/thirdparty/astcenc/astcenc_vecmathlib.h
new file mode 100644
index 0000000000..d48f1d73ea
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_vecmathlib.h
@@ -0,0 +1,570 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2019-2022 Arm Limited
+// Copyright 2008 Jose Fonseca
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/*
+ * This module implements vector support for floats, ints, and vector lane
+ * control masks. It provides access to both explicit vector width types, and
+ * flexible N-wide types where N can be determined at compile time.
+ *
+ * The design of this module encourages use of vector length agnostic code, via
+ * the vint, vfloat, and vmask types. These will take on the widest SIMD vector
+ * with that is available at compile time. The current vector width is
+ * accessible for e.g. loop strides via the ASTCENC_SIMD_WIDTH constant.
+ *
+ * Explicit scalar types are accessible via the vint1, vfloat1, vmask1 types.
+ * These are provided primarily for prototyping and algorithm debug of VLA
+ * implementations.
+ *
+ * Explicit 4-wide types are accessible via the vint4, vfloat4, and vmask4
+ * types. These are provided for use by VLA code, but are also expected to be
+ * used as a fixed-width type and will supported a reference C++ fallback for
+ * use on platforms without SIMD intrinsics.
+ *
+ * Explicit 8-wide types are accessible via the vint8, vfloat8, and vmask8
+ * types. These are provide for use by VLA code, and are not expected to be
+ * used as a fixed-width type in normal code. No reference C implementation is
+ * provided on platforms without underlying SIMD intrinsics.
+ *
+ * With the current implementation ISA support is provided for:
+ *
+ * * 1-wide for scalar reference.
+ * * 4-wide for Armv8-A NEON.
+ * * 4-wide for x86-64 SSE2.
+ * * 4-wide for x86-64 SSE4.1.
+ * * 8-wide for x86-64 AVX2.
+ */
+
+#ifndef ASTC_VECMATHLIB_H_INCLUDED
+#define ASTC_VECMATHLIB_H_INCLUDED
+
+#if ASTCENC_SSE != 0 || ASTCENC_AVX != 0
+ #include <immintrin.h>
+#elif ASTCENC_NEON != 0
+ #include <arm_neon.h>
+#endif
+
+#if !defined(__clang__) && defined(_MSC_VER)
+ #define ASTCENC_SIMD_INLINE __forceinline
+ #define ASTCENC_NO_INLINE
+#elif defined(__GNUC__) && !defined(__clang__)
+ #define ASTCENC_SIMD_INLINE __attribute__((always_inline)) inline
+ #define ASTCENC_NO_INLINE __attribute__ ((noinline))
+#else
+ #define ASTCENC_SIMD_INLINE __attribute__((always_inline, nodebug)) inline
+ #define ASTCENC_NO_INLINE __attribute__ ((noinline))
+#endif
+
+#if ASTCENC_AVX >= 2
+ /* If we have AVX2 expose 8-wide VLA. */
+ #include "astcenc_vecmathlib_sse_4.h"
+ #include "astcenc_vecmathlib_common_4.h"
+ #include "astcenc_vecmathlib_avx2_8.h"
+
+ #define ASTCENC_SIMD_WIDTH 8
+
+ using vfloat = vfloat8;
+
+ #if defined(ASTCENC_NO_INVARIANCE)
+ using vfloatacc = vfloat8;
+ #else
+ using vfloatacc = vfloat4;
+ #endif
+
+ using vint = vint8;
+ using vmask = vmask8;
+
+ constexpr auto loada = vfloat8::loada;
+ constexpr auto load1 = vfloat8::load1;
+
+#elif ASTCENC_SSE >= 20
+ /* If we have SSE expose 4-wide VLA, and 4-wide fixed width. */
+ #include "astcenc_vecmathlib_sse_4.h"
+ #include "astcenc_vecmathlib_common_4.h"
+
+ #define ASTCENC_SIMD_WIDTH 4
+
+ using vfloat = vfloat4;
+ using vfloatacc = vfloat4;
+ using vint = vint4;
+ using vmask = vmask4;
+
+ constexpr auto loada = vfloat4::loada;
+ constexpr auto load1 = vfloat4::load1;
+
+#elif ASTCENC_NEON > 0
+ /* If we have NEON expose 4-wide VLA. */
+ #include "astcenc_vecmathlib_neon_4.h"
+ #include "astcenc_vecmathlib_common_4.h"
+
+ #define ASTCENC_SIMD_WIDTH 4
+
+ using vfloat = vfloat4;
+ using vfloatacc = vfloat4;
+ using vint = vint4;
+ using vmask = vmask4;
+
+ constexpr auto loada = vfloat4::loada;
+ constexpr auto load1 = vfloat4::load1;
+
+#else
+ // If we have nothing expose 4-wide VLA, and 4-wide fixed width.
+
+ // Note: We no longer expose the 1-wide scalar fallback because it is not
+ // invariant with the 4-wide path due to algorithms that use horizontal
+ // operations that accumulate a local vector sum before accumulating into
+ // a running sum.
+ //
+ // For 4 items adding into an accumulator using 1-wide vectors the sum is:
+ //
+ // result = ((((sum + l0) + l1) + l2) + l3)
+ //
+ // ... whereas the accumulator for a 4-wide vector sum is:
+ //
+ // result = sum + ((l0 + l2) + (l1 + l3))
+ //
+ // In "normal maths" this is the same, but the floating point reassociation
+ // differences mean that these will not produce the same result.
+
+ #include "astcenc_vecmathlib_none_4.h"
+ #include "astcenc_vecmathlib_common_4.h"
+
+ #define ASTCENC_SIMD_WIDTH 4
+
+ using vfloat = vfloat4;
+ using vfloatacc = vfloat4;
+ using vint = vint4;
+ using vmask = vmask4;
+
+ constexpr auto loada = vfloat4::loada;
+ constexpr auto load1 = vfloat4::load1;
+#endif
+
+/**
+ * @brief Round a count down to the largest multiple of 8.
+ *
+ * @param count The unrounded value.
+ *
+ * @return The rounded value.
+ */
+ASTCENC_SIMD_INLINE unsigned int round_down_to_simd_multiple_8(unsigned int count)
+{
+ return count & static_cast<unsigned int>(~(8 - 1));
+}
+
+/**
+ * @brief Round a count down to the largest multiple of 4.
+ *
+ * @param count The unrounded value.
+ *
+ * @return The rounded value.
+ */
+ASTCENC_SIMD_INLINE unsigned int round_down_to_simd_multiple_4(unsigned int count)
+{
+ return count & static_cast<unsigned int>(~(4 - 1));
+}
+
+/**
+ * @brief Round a count down to the largest multiple of the SIMD width.
+ *
+ * Assumption that the vector width is a power of two ...
+ *
+ * @param count The unrounded value.
+ *
+ * @return The rounded value.
+ */
+ASTCENC_SIMD_INLINE unsigned int round_down_to_simd_multiple_vla(unsigned int count)
+{
+ return count & static_cast<unsigned int>(~(ASTCENC_SIMD_WIDTH - 1));
+}
+
+/**
+ * @brief Round a count up to the largest multiple of the SIMD width.
+ *
+ * Assumption that the vector width is a power of two ...
+ *
+ * @param count The unrounded value.
+ *
+ * @return The rounded value.
+ */
+ASTCENC_SIMD_INLINE unsigned int round_up_to_simd_multiple_vla(unsigned int count)
+{
+ unsigned int multiples = (count + ASTCENC_SIMD_WIDTH - 1) / ASTCENC_SIMD_WIDTH;
+ return multiples * ASTCENC_SIMD_WIDTH;
+}
+
+/**
+ * @brief Return @c a with lanes negated if the @c b lane is negative.
+ */
+ASTCENC_SIMD_INLINE vfloat change_sign(vfloat a, vfloat b)
+{
+ vint ia = float_as_int(a);
+ vint ib = float_as_int(b);
+ vint sign_mask(static_cast<int>(0x80000000));
+ vint r = ia ^ (ib & sign_mask);
+ return int_as_float(r);
+}
+
+/**
+ * @brief Return fast, but approximate, vector atan(x).
+ *
+ * Max error of this implementation is 0.004883.
+ */
+ASTCENC_SIMD_INLINE vfloat atan(vfloat x)
+{
+ vmask c = abs(x) > vfloat(1.0f);
+ vfloat z = change_sign(vfloat(astc::PI_OVER_TWO), x);
+ vfloat y = select(x, vfloat(1.0f) / x, c);
+ y = y / (y * y * vfloat(0.28f) + vfloat(1.0f));
+ return select(y, z - y, c);
+}
+
+/**
+ * @brief Return fast, but approximate, vector atan2(x, y).
+ */
+ASTCENC_SIMD_INLINE vfloat atan2(vfloat y, vfloat x)
+{
+ vfloat z = atan(abs(y / x));
+ vmask xmask = vmask(float_as_int(x).m);
+ return change_sign(select_msb(z, vfloat(astc::PI) - z, xmask), y);
+}
+
+/*
+ * @brief Factory that returns a unit length 4 component vfloat4.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 unit4()
+{
+ return vfloat4(0.5f);
+}
+
+/**
+ * @brief Factory that returns a unit length 3 component vfloat4.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 unit3()
+{
+ float val = 0.577350258827209473f;
+ return vfloat4(val, val, val, 0.0f);
+}
+
+/**
+ * @brief Factory that returns a unit length 2 component vfloat4.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 unit2()
+{
+ float val = 0.707106769084930420f;
+ return vfloat4(val, val, 0.0f, 0.0f);
+}
+
+/**
+ * @brief Factory that returns a 3 component vfloat4.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 vfloat3(float a, float b, float c)
+{
+ return vfloat4(a, b, c, 0.0f);
+}
+
+/**
+ * @brief Factory that returns a 2 component vfloat4.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 vfloat2(float a, float b)
+{
+ return vfloat4(a, b, 0.0f, 0.0f);
+}
+
+/**
+ * @brief Normalize a non-zero length vector to unit length.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 normalize(vfloat4 a)
+{
+ vfloat4 length = dot(a, a);
+ return a / sqrt(length);
+}
+
+/**
+ * @brief Normalize a vector, returning @c safe if len is zero.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 normalize_safe(vfloat4 a, vfloat4 safe)
+{
+ vfloat4 length = dot(a, a);
+ if (length.lane<0>() != 0.0f)
+ {
+ return a / sqrt(length);
+ }
+
+ return safe;
+}
+
+
+
+#define POLY0(x, c0) ( c0)
+#define POLY1(x, c0, c1) ((POLY0(x, c1) * x) + c0)
+#define POLY2(x, c0, c1, c2) ((POLY1(x, c1, c2) * x) + c0)
+#define POLY3(x, c0, c1, c2, c3) ((POLY2(x, c1, c2, c3) * x) + c0)
+#define POLY4(x, c0, c1, c2, c3, c4) ((POLY3(x, c1, c2, c3, c4) * x) + c0)
+#define POLY5(x, c0, c1, c2, c3, c4, c5) ((POLY4(x, c1, c2, c3, c4, c5) * x) + c0)
+
+/**
+ * @brief Compute an approximate exp2(x) for each lane in the vector.
+ *
+ * Based on 5th degree minimax polynomials, ported from this blog
+ * https://jrfonseca.blogspot.com/2008/09/fast-sse2-pow-tables-or-polynomials.html
+ */
+static ASTCENC_SIMD_INLINE vfloat4 exp2(vfloat4 x)
+{
+ x = clamp(-126.99999f, 129.0f, x);
+
+ vint4 ipart = float_to_int(x - 0.5f);
+ vfloat4 fpart = x - int_to_float(ipart);
+
+ // Integer contrib, using 1 << ipart
+ vfloat4 iexp = int_as_float(lsl<23>(ipart + 127));
+
+ // Fractional contrib, using polynomial fit of 2^x in range [-0.5, 0.5)
+ vfloat4 fexp = POLY5(fpart,
+ 9.9999994e-1f,
+ 6.9315308e-1f,
+ 2.4015361e-1f,
+ 5.5826318e-2f,
+ 8.9893397e-3f,
+ 1.8775767e-3f);
+
+ return iexp * fexp;
+}
+
+/**
+ * @brief Compute an approximate log2(x) for each lane in the vector.
+ *
+ * Based on 5th degree minimax polynomials, ported from this blog
+ * https://jrfonseca.blogspot.com/2008/09/fast-sse2-pow-tables-or-polynomials.html
+ */
+static ASTCENC_SIMD_INLINE vfloat4 log2(vfloat4 x)
+{
+ vint4 exp(0x7F800000);
+ vint4 mant(0x007FFFFF);
+ vint4 one(0x3F800000);
+
+ vint4 i = float_as_int(x);
+
+ vfloat4 e = int_to_float(lsr<23>(i & exp) - 127);
+
+ vfloat4 m = int_as_float((i & mant) | one);
+
+ // Polynomial fit of log2(x)/(x - 1), for x in range [1, 2)
+ vfloat4 p = POLY4(m,
+ 2.8882704548164776201f,
+ -2.52074962577807006663f,
+ 1.48116647521213171641f,
+ -0.465725644288844778798f,
+ 0.0596515482674574969533f);
+
+ // Increases the polynomial degree, but ensures that log2(1) == 0
+ p = p * (m - 1.0f);
+
+ return p + e;
+}
+
+/**
+ * @brief Compute an approximate pow(x, y) for each lane in the vector.
+ *
+ * Power function based on the exp2(log2(x) * y) transform.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 pow(vfloat4 x, vfloat4 y)
+{
+ vmask4 zero_mask = y == vfloat4(0.0f);
+ vfloat4 estimate = exp2(log2(x) * y);
+
+ // Guarantee that y == 0 returns exactly 1.0f
+ return select(estimate, vfloat4(1.0f), zero_mask);
+}
+
+/**
+ * @brief Count the leading zeros for each lane in @c a.
+ *
+ * Valid for all data values of @c a; will return a per-lane value [0, 32].
+ */
+static ASTCENC_SIMD_INLINE vint4 clz(vint4 a)
+{
+ // This function is a horrible abuse of floating point exponents to convert
+ // the original integer value into a 2^N encoding we can recover easily.
+
+ // Convert to float without risk of rounding up by keeping only top 8 bits.
+ // This trick is is guaranteed to keep top 8 bits and clear the 9th.
+ a = (~lsr<8>(a)) & a;
+ a = float_as_int(int_to_float(a));
+
+ // Extract and unbias exponent
+ a = vint4(127 + 31) - lsr<23>(a);
+
+ // Clamp result to a valid 32-bit range
+ return clamp(0, 32, a);
+}
+
+/**
+ * @brief Return lanewise 2^a for each lane in @c a.
+ *
+ * Use of signed int means that this is only valid for values in range [0, 31].
+ */
+static ASTCENC_SIMD_INLINE vint4 two_to_the_n(vint4 a)
+{
+ // 2^30 is the largest signed number than can be represented
+ assert(all(a < vint4(31)));
+
+ // This function is a horrible abuse of floating point to use the exponent
+ // and float conversion to generate a 2^N multiple.
+
+ // Bias the exponent
+ vint4 exp = a + 127;
+ exp = lsl<23>(exp);
+
+ // Reinterpret the bits as a float, and then convert to an int
+ vfloat4 f = int_as_float(exp);
+ return float_to_int(f);
+}
+
+/**
+ * @brief Convert unorm16 [0, 65535] to float16 in range [0, 1].
+ */
+static ASTCENC_SIMD_INLINE vint4 unorm16_to_sf16(vint4 p)
+{
+ vint4 fp16_one = vint4(0x3C00);
+ vint4 fp16_small = lsl<8>(p);
+
+ vmask4 is_one = p == vint4(0xFFFF);
+ vmask4 is_small = p < vint4(4);
+
+ // Manually inline clz() on Visual Studio to avoid release build codegen bug
+ // see https://github.com/ARM-software/astc-encoder/issues/259
+#if !defined(__clang__) && defined(_MSC_VER)
+ vint4 a = (~lsr<8>(p)) & p;
+ a = float_as_int(int_to_float(a));
+ a = vint4(127 + 31) - lsr<23>(a);
+ vint4 lz = clamp(0, 32, a) - 16;
+#else
+ vint4 lz = clz(p) - 16;
+#endif
+
+ p = p * two_to_the_n(lz + 1);
+ p = p & vint4(0xFFFF);
+
+ p = lsr<6>(p);
+
+ p = p | lsl<10>(vint4(14) - lz);
+
+ vint4 r = select(p, fp16_one, is_one);
+ r = select(r, fp16_small, is_small);
+ return r;
+}
+
+/**
+ * @brief Convert 16-bit LNS to float16.
+ */
+static ASTCENC_SIMD_INLINE vint4 lns_to_sf16(vint4 p)
+{
+ vint4 mc = p & 0x7FF;
+ vint4 ec = lsr<11>(p);
+
+ vint4 mc_512 = mc * 3;
+ vmask4 mask_512 = mc < vint4(512);
+
+ vint4 mc_1536 = mc * 4 - 512;
+ vmask4 mask_1536 = mc < vint4(1536);
+
+ vint4 mc_else = mc * 5 - 2048;
+
+ vint4 mt = mc_else;
+ mt = select(mt, mc_1536, mask_1536);
+ mt = select(mt, mc_512, mask_512);
+
+ vint4 res = lsl<10>(ec) | lsr<3>(mt);
+ return min(res, vint4(0x7BFF));
+}
+
+/**
+ * @brief Extract mantissa and exponent of a float value.
+ *
+ * @param a The input value.
+ * @param[out] exp The output exponent.
+ *
+ * @return The mantissa.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 frexp(vfloat4 a, vint4& exp)
+{
+ // Interpret the bits as an integer
+ vint4 ai = float_as_int(a);
+
+ // Extract and unbias the exponent
+ exp = (lsr<23>(ai) & 0xFF) - 126;
+
+ // Extract and unbias the mantissa
+ vint4 manti = (ai & static_cast<int>(0x807FFFFF)) | 0x3F000000;
+ return int_as_float(manti);
+}
+
+/**
+ * @brief Convert float to 16-bit LNS.
+ */
+static ASTCENC_SIMD_INLINE vfloat4 float_to_lns(vfloat4 a)
+{
+ vint4 exp;
+ vfloat4 mant = frexp(a, exp);
+
+ // Do these early before we start messing about ...
+ vmask4 mask_underflow_nan = ~(a > vfloat4(1.0f / 67108864.0f));
+ vmask4 mask_infinity = a >= vfloat4(65536.0f);
+
+ // If input is smaller than 2^-14, multiply by 2^25 and don't bias.
+ vmask4 exp_lt_m13 = exp < vint4(-13);
+
+ vfloat4 a1a = a * 33554432.0f;
+ vint4 expa = vint4::zero();
+
+ vfloat4 a1b = (mant - 0.5f) * 4096;
+ vint4 expb = exp + 14;
+
+ a = select(a1b, a1a, exp_lt_m13);
+ exp = select(expb, expa, exp_lt_m13);
+
+ vmask4 a_lt_384 = a < vfloat4(384.0f);
+ vmask4 a_lt_1408 = a <= vfloat4(1408.0f);
+
+ vfloat4 a2a = a * (4.0f / 3.0f);
+ vfloat4 a2b = a + 128.0f;
+ vfloat4 a2c = (a + 512.0f) * (4.0f / 5.0f);
+
+ a = a2c;
+ a = select(a, a2b, a_lt_1408);
+ a = select(a, a2a, a_lt_384);
+
+ a = a + (int_to_float(exp) * 2048.0f) + 1.0f;
+
+ a = select(a, vfloat4(65535.0f), mask_infinity);
+ a = select(a, vfloat4::zero(), mask_underflow_nan);
+
+ return a;
+}
+
+namespace astc
+{
+
+static ASTCENC_SIMD_INLINE float pow(float x, float y)
+{
+ return pow(vfloat4(x), vfloat4(y)).lane<0>();
+}
+
+}
+
+#endif // #ifndef ASTC_VECMATHLIB_H_INCLUDED
diff --git a/thirdparty/astcenc/astcenc_vecmathlib_avx2_8.h b/thirdparty/astcenc/astcenc_vecmathlib_avx2_8.h
new file mode 100644
index 0000000000..a785aca75b
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_vecmathlib_avx2_8.h
@@ -0,0 +1,1204 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2019-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief 8x32-bit vectors, implemented using AVX2.
+ *
+ * This module implements 8-wide 32-bit float, int, and mask vectors for x86
+ * AVX2.
+ *
+ * There is a baseline level of functionality provided by all vector widths and
+ * implementations. This is implemented using identical function signatures,
+ * modulo data type, so we can use them as substitutable implementations in VLA
+ * code.
+ */
+
+#ifndef ASTC_VECMATHLIB_AVX2_8_H_INCLUDED
+#define ASTC_VECMATHLIB_AVX2_8_H_INCLUDED
+
+#ifndef ASTCENC_SIMD_INLINE
+ #error "Include astcenc_vecmathlib.h, do not include directly"
+#endif
+
+#include <cstdio>
+
+// Define convenience intrinsics that are missing on older compilers
+#define astcenc_mm256_set_m128i(m, n) _mm256_insertf128_si256(_mm256_castsi128_si256((n)), (m), 1)
+
+// ============================================================================
+// vfloat8 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 8-wide floats.
+ */
+struct vfloat8
+{
+ /**
+ * @brief Construct from zero-initialized value.
+ */
+ ASTCENC_SIMD_INLINE vfloat8() = default;
+
+ /**
+ * @brief Construct from 4 values loaded from an unaligned address.
+ *
+ * Consider using loada() which is better with vectors if data is aligned
+ * to vector length.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat8(const float *p)
+ {
+ m = _mm256_loadu_ps(p);
+ }
+
+ /**
+ * @brief Construct from 1 scalar value replicated across all lanes.
+ *
+ * Consider using zero() for constexpr zeros.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat8(float a)
+ {
+ m = _mm256_set1_ps(a);
+ }
+
+ /**
+ * @brief Construct from 8 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat8(
+ float a, float b, float c, float d,
+ float e, float f, float g, float h)
+ {
+ m = _mm256_set_ps(h, g, f, e, d, c, b, a);
+ }
+
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat8(__m256 a)
+ {
+ m = a;
+ }
+
+ /**
+ * @brief Get the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE float lane() const
+ {
+ #if !defined(__clang__) && defined(_MSC_VER)
+ return m.m256_f32[l];
+ #else
+ union { __m256 m; float f[8]; } cvt;
+ cvt.m = m;
+ return cvt.f[l];
+ #endif
+ }
+
+ /**
+ * @brief Factory that returns a vector of zeros.
+ */
+ static ASTCENC_SIMD_INLINE vfloat8 zero()
+ {
+ return vfloat8(_mm256_setzero_ps());
+ }
+
+ /**
+ * @brief Factory that returns a replicated scalar loaded from memory.
+ */
+ static ASTCENC_SIMD_INLINE vfloat8 load1(const float* p)
+ {
+ return vfloat8(_mm256_broadcast_ss(p));
+ }
+
+ /**
+ * @brief Factory that returns a vector loaded from 32B aligned memory.
+ */
+ static ASTCENC_SIMD_INLINE vfloat8 loada(const float* p)
+ {
+ return vfloat8(_mm256_load_ps(p));
+ }
+
+ /**
+ * @brief Factory that returns a vector containing the lane IDs.
+ */
+ static ASTCENC_SIMD_INLINE vfloat8 lane_id()
+ {
+ return vfloat8(_mm256_set_ps(7, 6, 5, 4, 3, 2, 1, 0));
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ __m256 m;
+};
+
+// ============================================================================
+// vint8 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 8-wide ints.
+ */
+struct vint8
+{
+ /**
+ * @brief Construct from zero-initialized value.
+ */
+ ASTCENC_SIMD_INLINE vint8() = default;
+
+ /**
+ * @brief Construct from 8 values loaded from an unaligned address.
+ *
+ * Consider using loada() which is better with vectors if data is aligned
+ * to vector length.
+ */
+ ASTCENC_SIMD_INLINE explicit vint8(const int *p)
+ {
+ m = _mm256_loadu_si256(reinterpret_cast<const __m256i*>(p));
+ }
+
+ /**
+ * @brief Construct from 8 uint8_t loaded from an unaligned address.
+ */
+ ASTCENC_SIMD_INLINE explicit vint8(const uint8_t *p)
+ {
+ // _mm_loadu_si64 would be nicer syntax, but missing on older GCC
+ m = _mm256_cvtepu8_epi32(_mm_cvtsi64_si128(*reinterpret_cast<const long long*>(p)));
+ }
+
+ /**
+ * @brief Construct from 1 scalar value replicated across all lanes.
+ *
+ * Consider using vfloat4::zero() for constexpr zeros.
+ */
+ ASTCENC_SIMD_INLINE explicit vint8(int a)
+ {
+ m = _mm256_set1_epi32(a);
+ }
+
+ /**
+ * @brief Construct from 8 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vint8(
+ int a, int b, int c, int d,
+ int e, int f, int g, int h)
+ {
+ m = _mm256_set_epi32(h, g, f, e, d, c, b, a);
+ }
+
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vint8(__m256i a)
+ {
+ m = a;
+ }
+
+ /**
+ * @brief Get the scalar from a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE int lane() const
+ {
+ #if !defined(__clang__) && defined(_MSC_VER)
+ return m.m256i_i32[l];
+ #else
+ union { __m256i m; int f[8]; } cvt;
+ cvt.m = m;
+ return cvt.f[l];
+ #endif
+ }
+
+ /**
+ * @brief Factory that returns a vector of zeros.
+ */
+ static ASTCENC_SIMD_INLINE vint8 zero()
+ {
+ return vint8(_mm256_setzero_si256());
+ }
+
+ /**
+ * @brief Factory that returns a replicated scalar loaded from memory.
+ */
+ static ASTCENC_SIMD_INLINE vint8 load1(const int* p)
+ {
+ __m128i a = _mm_set1_epi32(*p);
+ return vint8(_mm256_broadcastd_epi32(a));
+ }
+
+ /**
+ * @brief Factory that returns a vector loaded from 32B aligned memory.
+ */
+ static ASTCENC_SIMD_INLINE vint8 loada(const int* p)
+ {
+ return vint8(_mm256_load_si256(reinterpret_cast<const __m256i*>(p)));
+ }
+
+ /**
+ * @brief Factory that returns a vector containing the lane IDs.
+ */
+ static ASTCENC_SIMD_INLINE vint8 lane_id()
+ {
+ return vint8(_mm256_set_epi32(7, 6, 5, 4, 3, 2, 1, 0));
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ __m256i m;
+};
+
+// ============================================================================
+// vmask8 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 8-wide control plane masks.
+ */
+struct vmask8
+{
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask8(__m256 a)
+ {
+ m = a;
+ }
+
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask8(__m256i a)
+ {
+ m = _mm256_castsi256_ps(a);
+ }
+
+ /**
+ * @brief Construct from 1 scalar value.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask8(bool a)
+ {
+ vint8 mask(a == false ? 0 : -1);
+ m = _mm256_castsi256_ps(mask.m);
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ __m256 m;
+};
+
+// ============================================================================
+// vmask8 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: mask union (or).
+ */
+ASTCENC_SIMD_INLINE vmask8 operator|(vmask8 a, vmask8 b)
+{
+ return vmask8(_mm256_or_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask intersect (and).
+ */
+ASTCENC_SIMD_INLINE vmask8 operator&(vmask8 a, vmask8 b)
+{
+ return vmask8(_mm256_and_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask difference (xor).
+ */
+ASTCENC_SIMD_INLINE vmask8 operator^(vmask8 a, vmask8 b)
+{
+ return vmask8(_mm256_xor_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask invert (not).
+ */
+ASTCENC_SIMD_INLINE vmask8 operator~(vmask8 a)
+{
+ return vmask8(_mm256_xor_si256(_mm256_castps_si256(a.m), _mm256_set1_epi32(-1)));
+}
+
+/**
+ * @brief Return a 8-bit mask code indicating mask status.
+ *
+ * bit0 = lane 0
+ */
+ASTCENC_SIMD_INLINE unsigned int mask(vmask8 a)
+{
+ return static_cast<unsigned int>(_mm256_movemask_ps(a.m));
+}
+
+/**
+ * @brief True if any lanes are enabled, false otherwise.
+ */
+ASTCENC_SIMD_INLINE bool any(vmask8 a)
+{
+ return mask(a) != 0;
+}
+
+/**
+ * @brief True if all lanes are enabled, false otherwise.
+ */
+ASTCENC_SIMD_INLINE bool all(vmask8 a)
+{
+ return mask(a) == 0xFF;
+}
+
+// ============================================================================
+// vint8 operators and functions
+// ============================================================================
+/**
+ * @brief Overload: vector by vector addition.
+ */
+ASTCENC_SIMD_INLINE vint8 operator+(vint8 a, vint8 b)
+{
+ return vint8(_mm256_add_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector incremental addition.
+ */
+ASTCENC_SIMD_INLINE vint8& operator+=(vint8& a, const vint8& b)
+{
+ a = a + b;
+ return a;
+}
+
+/**
+ * @brief Overload: vector by vector subtraction.
+ */
+ASTCENC_SIMD_INLINE vint8 operator-(vint8 a, vint8 b)
+{
+ return vint8(_mm256_sub_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vint8 operator*(vint8 a, vint8 b)
+{
+ return vint8(_mm256_mullo_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector bit invert.
+ */
+ASTCENC_SIMD_INLINE vint8 operator~(vint8 a)
+{
+ return vint8(_mm256_xor_si256(a.m, _mm256_set1_epi32(-1)));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise or.
+ */
+ASTCENC_SIMD_INLINE vint8 operator|(vint8 a, vint8 b)
+{
+ return vint8(_mm256_or_si256(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise and.
+ */
+ASTCENC_SIMD_INLINE vint8 operator&(vint8 a, vint8 b)
+{
+ return vint8(_mm256_and_si256(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise xor.
+ */
+ASTCENC_SIMD_INLINE vint8 operator^(vint8 a, vint8 b)
+{
+ return vint8(_mm256_xor_si256(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector equality.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator==(vint8 a, vint8 b)
+{
+ return vmask8(_mm256_cmpeq_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector inequality.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator!=(vint8 a, vint8 b)
+{
+ return ~vmask8(_mm256_cmpeq_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector less than.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator<(vint8 a, vint8 b)
+{
+ return vmask8(_mm256_cmpgt_epi32(b.m, a.m));
+}
+
+/**
+ * @brief Overload: vector by vector greater than.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator>(vint8 a, vint8 b)
+{
+ return vmask8(_mm256_cmpgt_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Logical shift left.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint8 lsl(vint8 a)
+{
+ return vint8(_mm256_slli_epi32(a.m, s));
+}
+
+/**
+ * @brief Arithmetic shift right.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint8 asr(vint8 a)
+{
+ return vint8(_mm256_srai_epi32(a.m, s));
+}
+
+/**
+ * @brief Logical shift right.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint8 lsr(vint8 a)
+{
+ return vint8(_mm256_srli_epi32(a.m, s));
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ */
+ASTCENC_SIMD_INLINE vint8 min(vint8 a, vint8 b)
+{
+ return vint8(_mm256_min_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Return the max vector of two vectors.
+ */
+ASTCENC_SIMD_INLINE vint8 max(vint8 a, vint8 b)
+{
+ return vint8(_mm256_max_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE vint8 hmin(vint8 a)
+{
+ __m128i m = _mm_min_epi32(_mm256_extracti128_si256(a.m, 0), _mm256_extracti128_si256(a.m, 1));
+ m = _mm_min_epi32(m, _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,3,2)));
+ m = _mm_min_epi32(m, _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,0,1)));
+ m = _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,0,0));
+
+ __m256i r = astcenc_mm256_set_m128i(m, m);
+ vint8 vmin(r);
+ return vmin;
+}
+
+/**
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE vint8 hmax(vint8 a)
+{
+ __m128i m = _mm_max_epi32(_mm256_extracti128_si256(a.m, 0), _mm256_extracti128_si256(a.m, 1));
+ m = _mm_max_epi32(m, _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,3,2)));
+ m = _mm_max_epi32(m, _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,0,1)));
+ m = _mm_shuffle_epi32(m, _MM_SHUFFLE(0,0,0,0));
+
+ __m256i r = astcenc_mm256_set_m128i(m, m);
+ vint8 vmax(r);
+ return vmax;
+}
+
+/**
+ * @brief Store a vector to a 16B aligned memory address.
+ */
+ASTCENC_SIMD_INLINE void storea(vint8 a, int* p)
+{
+ _mm256_store_si256(reinterpret_cast<__m256i*>(p), a.m);
+}
+
+/**
+ * @brief Store a vector to an unaligned memory address.
+ */
+ASTCENC_SIMD_INLINE void store(vint8 a, int* p)
+{
+ _mm256_storeu_si256(reinterpret_cast<__m256i*>(p), a.m);
+}
+
+/**
+ * @brief Store lowest N (vector width) bytes into an unaligned address.
+ */
+ASTCENC_SIMD_INLINE void store_nbytes(vint8 a, uint8_t* p)
+{
+ // This is the most logical implementation, but the convenience intrinsic
+ // is missing on older compilers (supported in g++ 9 and clang++ 9).
+ // _mm_storeu_si64(ptr, _mm256_extracti128_si256(v.m, 0))
+ _mm_storel_epi64(reinterpret_cast<__m128i*>(p), _mm256_extracti128_si256(a.m, 0));
+}
+
+/**
+ * @brief Gather N (vector width) indices from the array.
+ */
+ASTCENC_SIMD_INLINE vint8 gatheri(const int* base, vint8 indices)
+{
+ return vint8(_mm256_i32gather_epi32(base, indices.m, 4));
+}
+
+/**
+ * @brief Pack low 8 bits of N (vector width) lanes into bottom of vector.
+ */
+ASTCENC_SIMD_INLINE vint8 pack_low_bytes(vint8 v)
+{
+ __m256i shuf = _mm256_set_epi8(0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 28, 24, 20, 16,
+ 0, 0, 0, 0, 0, 0, 0, 0,
+ 0, 0, 0, 0, 12, 8, 4, 0);
+ __m256i a = _mm256_shuffle_epi8(v.m, shuf);
+ __m128i a0 = _mm256_extracti128_si256(a, 0);
+ __m128i a1 = _mm256_extracti128_si256(a, 1);
+ __m128i b = _mm_unpacklo_epi32(a0, a1);
+
+ __m256i r = astcenc_mm256_set_m128i(b, b);
+ return vint8(r);
+}
+
+/**
+ * @brief Return lanes from @c b if @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vint8 select(vint8 a, vint8 b, vmask8 cond)
+{
+ __m256i condi = _mm256_castps_si256(cond.m);
+ return vint8(_mm256_blendv_epi8(a.m, b.m, condi));
+}
+
+// ============================================================================
+// vfloat4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by vector addition.
+ */
+ASTCENC_SIMD_INLINE vfloat8 operator+(vfloat8 a, vfloat8 b)
+{
+ return vfloat8(_mm256_add_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector incremental addition.
+ */
+ASTCENC_SIMD_INLINE vfloat8& operator+=(vfloat8& a, const vfloat8& b)
+{
+ a = a + b;
+ return a;
+}
+
+/**
+ * @brief Overload: vector by vector subtraction.
+ */
+ASTCENC_SIMD_INLINE vfloat8 operator-(vfloat8 a, vfloat8 b)
+{
+ return vfloat8(_mm256_sub_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vfloat8 operator*(vfloat8 a, vfloat8 b)
+{
+ return vfloat8(_mm256_mul_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by scalar multiplication.
+ */
+ASTCENC_SIMD_INLINE vfloat8 operator*(vfloat8 a, float b)
+{
+ return vfloat8(_mm256_mul_ps(a.m, _mm256_set1_ps(b)));
+}
+
+/**
+ * @brief Overload: scalar by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vfloat8 operator*(float a, vfloat8 b)
+{
+ return vfloat8(_mm256_mul_ps(_mm256_set1_ps(a), b.m));
+}
+
+/**
+ * @brief Overload: vector by vector division.
+ */
+ASTCENC_SIMD_INLINE vfloat8 operator/(vfloat8 a, vfloat8 b)
+{
+ return vfloat8(_mm256_div_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by scalar division.
+ */
+ASTCENC_SIMD_INLINE vfloat8 operator/(vfloat8 a, float b)
+{
+ return vfloat8(_mm256_div_ps(a.m, _mm256_set1_ps(b)));
+}
+
+
+/**
+ * @brief Overload: scalar by vector division.
+ */
+ASTCENC_SIMD_INLINE vfloat8 operator/(float a, vfloat8 b)
+{
+ return vfloat8(_mm256_div_ps(_mm256_set1_ps(a), b.m));
+}
+
+
+/**
+ * @brief Overload: vector by vector equality.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator==(vfloat8 a, vfloat8 b)
+{
+ return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_EQ_OQ));
+}
+
+/**
+ * @brief Overload: vector by vector inequality.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator!=(vfloat8 a, vfloat8 b)
+{
+ return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_NEQ_OQ));
+}
+
+/**
+ * @brief Overload: vector by vector less than.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator<(vfloat8 a, vfloat8 b)
+{
+ return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_LT_OQ));
+}
+
+/**
+ * @brief Overload: vector by vector greater than.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator>(vfloat8 a, vfloat8 b)
+{
+ return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_GT_OQ));
+}
+
+/**
+ * @brief Overload: vector by vector less than or equal.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator<=(vfloat8 a, vfloat8 b)
+{
+ return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_LE_OQ));
+}
+
+/**
+ * @brief Overload: vector by vector greater than or equal.
+ */
+ASTCENC_SIMD_INLINE vmask8 operator>=(vfloat8 a, vfloat8 b)
+{
+ return vmask8(_mm256_cmp_ps(a.m, b.m, _CMP_GE_OQ));
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat8 min(vfloat8 a, vfloat8 b)
+{
+ return vfloat8(_mm256_min_ps(a.m, b.m));
+}
+
+/**
+ * @brief Return the min vector of a vector and a scalar.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat8 min(vfloat8 a, float b)
+{
+ return min(a, vfloat8(b));
+}
+
+/**
+ * @brief Return the max vector of two vectors.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat8 max(vfloat8 a, vfloat8 b)
+{
+ return vfloat8(_mm256_max_ps(a.m, b.m));
+}
+
+/**
+ * @brief Return the max vector of a vector and a scalar.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat8 max(vfloat8 a, float b)
+{
+ return max(a, vfloat8(b));
+}
+
+/**
+ * @brief Return the clamped value between min and max.
+ *
+ * It is assumed that neither @c min nor @c max are NaN values. If @c a is NaN
+ * then @c min will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat8 clamp(float min, float max, vfloat8 a)
+{
+ // Do not reorder - second operand will return if either is NaN
+ a.m = _mm256_max_ps(a.m, _mm256_set1_ps(min));
+ a.m = _mm256_min_ps(a.m, _mm256_set1_ps(max));
+ return a;
+}
+
+/**
+ * @brief Return a clamped value between 0.0f and max.
+ *
+ * It is assumed that @c max is not a NaN value. If @c a is NaN then zero will
+ * be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat8 clampz(float max, vfloat8 a)
+{
+ a.m = _mm256_max_ps(a.m, _mm256_setzero_ps());
+ a.m = _mm256_min_ps(a.m, _mm256_set1_ps(max));
+ return a;
+}
+
+/**
+ * @brief Return a clamped value between 0.0f and 1.0f.
+ *
+ * If @c a is NaN then zero will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat8 clampzo(vfloat8 a)
+{
+ a.m = _mm256_max_ps(a.m, _mm256_setzero_ps());
+ a.m = _mm256_min_ps(a.m, _mm256_set1_ps(1.0f));
+ return a;
+}
+
+/**
+ * @brief Return the absolute value of the float vector.
+ */
+ASTCENC_SIMD_INLINE vfloat8 abs(vfloat8 a)
+{
+ __m256 msk = _mm256_castsi256_ps(_mm256_set1_epi32(0x7fffffff));
+ return vfloat8(_mm256_and_ps(a.m, msk));
+}
+
+/**
+ * @brief Return a float rounded to the nearest integer value.
+ */
+ASTCENC_SIMD_INLINE vfloat8 round(vfloat8 a)
+{
+ constexpr int flags = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
+ return vfloat8(_mm256_round_ps(a.m, flags));
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE vfloat8 hmin(vfloat8 a)
+{
+ __m128 vlow = _mm256_castps256_ps128(a.m);
+ __m128 vhigh = _mm256_extractf128_ps(a.m, 1);
+ vlow = _mm_min_ps(vlow, vhigh);
+
+ // First do an horizontal reduction.
+ __m128 shuf = _mm_shuffle_ps(vlow, vlow, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128 mins = _mm_min_ps(vlow, shuf);
+ shuf = _mm_movehl_ps(shuf, mins);
+ mins = _mm_min_ss(mins, shuf);
+
+ // This is the most logical implementation, but the convenience intrinsic
+ // is missing on older compilers (supported in g++ 9 and clang++ 9).
+ //__m256i r = _mm256_set_m128(m, m)
+ __m256 r = _mm256_insertf128_ps(_mm256_castps128_ps256(mins), mins, 1);
+
+ return vfloat8(_mm256_permute_ps(r, 0));
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE float hmin_s(vfloat8 a)
+{
+ return hmin(a).lane<0>();
+}
+
+/**
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE vfloat8 hmax(vfloat8 a)
+{
+ __m128 vlow = _mm256_castps256_ps128(a.m);
+ __m128 vhigh = _mm256_extractf128_ps(a.m, 1);
+ vhigh = _mm_max_ps(vlow, vhigh);
+
+ // First do an horizontal reduction.
+ __m128 shuf = _mm_shuffle_ps(vhigh, vhigh, _MM_SHUFFLE(2, 3, 0, 1));
+ __m128 maxs = _mm_max_ps(vhigh, shuf);
+ shuf = _mm_movehl_ps(shuf,maxs);
+ maxs = _mm_max_ss(maxs, shuf);
+
+ // This is the most logical implementation, but the convenience intrinsic
+ // is missing on older compilers (supported in g++ 9 and clang++ 9).
+ //__m256i r = _mm256_set_m128(m, m)
+ __m256 r = _mm256_insertf128_ps(_mm256_castps128_ps256(maxs), maxs, 1);
+ return vfloat8(_mm256_permute_ps(r, 0));
+}
+
+/**
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE float hmax_s(vfloat8 a)
+{
+ return hmax(a).lane<0>();
+}
+
+/**
+ * @brief Return the horizontal sum of a vector.
+ */
+ASTCENC_SIMD_INLINE float hadd_s(vfloat8 a)
+{
+ // Two sequential 4-wide adds gives invariance with 4-wide code
+ vfloat4 lo(_mm256_extractf128_ps(a.m, 0));
+ vfloat4 hi(_mm256_extractf128_ps(a.m, 1));
+ return hadd_s(lo) + hadd_s(hi);
+}
+
+/**
+ * @brief Return lanes from @c b if @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vfloat8 select(vfloat8 a, vfloat8 b, vmask8 cond)
+{
+ return vfloat8(_mm256_blendv_ps(a.m, b.m, cond.m));
+}
+
+/**
+ * @brief Return lanes from @c b if MSB of @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vfloat8 select_msb(vfloat8 a, vfloat8 b, vmask8 cond)
+{
+ return vfloat8(_mm256_blendv_ps(a.m, b.m, cond.m));
+}
+
+/**
+ * @brief Accumulate lane-wise sums for a vector, folded 4-wide.
+ *
+ * This is invariant with 4-wide implementations.
+ */
+ASTCENC_SIMD_INLINE void haccumulate(vfloat4& accum, vfloat8 a)
+{
+ vfloat4 lo(_mm256_extractf128_ps(a.m, 0));
+ haccumulate(accum, lo);
+
+ vfloat4 hi(_mm256_extractf128_ps(a.m, 1));
+ haccumulate(accum, hi);
+}
+
+/**
+ * @brief Accumulate lane-wise sums for a vector.
+ *
+ * This is NOT invariant with 4-wide implementations.
+ */
+ASTCENC_SIMD_INLINE void haccumulate(vfloat8& accum, vfloat8 a)
+{
+ accum += a;
+}
+
+/**
+ * @brief Accumulate masked lane-wise sums for a vector, folded 4-wide.
+ *
+ * This is invariant with 4-wide implementations.
+ */
+ASTCENC_SIMD_INLINE void haccumulate(vfloat4& accum, vfloat8 a, vmask8 m)
+{
+ a = select(vfloat8::zero(), a, m);
+ haccumulate(accum, a);
+}
+
+/**
+ * @brief Accumulate masked lane-wise sums for a vector.
+ *
+ * This is NOT invariant with 4-wide implementations.
+ */
+ASTCENC_SIMD_INLINE void haccumulate(vfloat8& accum, vfloat8 a, vmask8 m)
+{
+ a = select(vfloat8::zero(), a, m);
+ haccumulate(accum, a);
+}
+
+/**
+ * @brief Return the sqrt of the lanes in the vector.
+ */
+ASTCENC_SIMD_INLINE vfloat8 sqrt(vfloat8 a)
+{
+ return vfloat8(_mm256_sqrt_ps(a.m));
+}
+
+/**
+ * @brief Load a vector of gathered results from an array;
+ */
+ASTCENC_SIMD_INLINE vfloat8 gatherf(const float* base, vint8 indices)
+{
+ return vfloat8(_mm256_i32gather_ps(base, indices.m, 4));
+}
+
+/**
+ * @brief Store a vector to an unaligned memory address.
+ */
+ASTCENC_SIMD_INLINE void store(vfloat8 a, float* p)
+{
+ _mm256_storeu_ps(p, a.m);
+}
+
+/**
+ * @brief Store a vector to a 32B aligned memory address.
+ */
+ASTCENC_SIMD_INLINE void storea(vfloat8 a, float* p)
+{
+ _mm256_store_ps(p, a.m);
+}
+
+/**
+ * @brief Return a integer value for a float vector, using truncation.
+ */
+ASTCENC_SIMD_INLINE vint8 float_to_int(vfloat8 a)
+{
+ return vint8(_mm256_cvttps_epi32(a.m));
+}
+
+/**
+ * @brief Return a integer value for a float vector, using round-to-nearest.
+ */
+ASTCENC_SIMD_INLINE vint8 float_to_int_rtn(vfloat8 a)
+{
+ a = round(a);
+ return vint8(_mm256_cvttps_epi32(a.m));
+}
+
+
+/**
+ * @brief Return a float value for an integer vector.
+ */
+ASTCENC_SIMD_INLINE vfloat8 int_to_float(vint8 a)
+{
+ return vfloat8(_mm256_cvtepi32_ps(a.m));
+}
+
+/**
+ * @brief Return a float value as an integer bit pattern (i.e. no conversion).
+ *
+ * It is a common trick to convert floats into integer bit patterns, perform
+ * some bit hackery based on knowledge they are IEEE 754 layout, and then
+ * convert them back again. This is the first half of that flip.
+ */
+ASTCENC_SIMD_INLINE vint8 float_as_int(vfloat8 a)
+{
+ return vint8(_mm256_castps_si256(a.m));
+}
+
+/**
+ * @brief Return a integer value as a float bit pattern (i.e. no conversion).
+ *
+ * It is a common trick to convert floats into integer bit patterns, perform
+ * some bit hackery based on knowledge they are IEEE 754 layout, and then
+ * convert them back again. This is the second half of that flip.
+ */
+ASTCENC_SIMD_INLINE vfloat8 int_as_float(vint8 a)
+{
+ return vfloat8(_mm256_castsi256_ps(a.m));
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint8& t0p)
+{
+ // AVX2 duplicates the table within each 128-bit lane
+ __m128i t0n = t0.m;
+ t0p = vint8(astcenc_mm256_set_m128i(t0n, t0n));
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint8& t0p, vint8& t1p)
+{
+ // AVX2 duplicates the table within each 128-bit lane
+ __m128i t0n = t0.m;
+ t0p = vint8(astcenc_mm256_set_m128i(t0n, t0n));
+
+ __m128i t1n = _mm_xor_si128(t0.m, t1.m);
+ t1p = vint8(astcenc_mm256_set_m128i(t1n, t1n));
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(
+ vint4 t0, vint4 t1, vint4 t2, vint4 t3,
+ vint8& t0p, vint8& t1p, vint8& t2p, vint8& t3p)
+{
+ // AVX2 duplicates the table within each 128-bit lane
+ __m128i t0n = t0.m;
+ t0p = vint8(astcenc_mm256_set_m128i(t0n, t0n));
+
+ __m128i t1n = _mm_xor_si128(t0.m, t1.m);
+ t1p = vint8(astcenc_mm256_set_m128i(t1n, t1n));
+
+ __m128i t2n = _mm_xor_si128(t1.m, t2.m);
+ t2p = vint8(astcenc_mm256_set_m128i(t2n, t2n));
+
+ __m128i t3n = _mm_xor_si128(t2.m, t3.m);
+ t3p = vint8(astcenc_mm256_set_m128i(t3n, t3n));
+}
+
+/**
+ * @brief Perform an 8-bit 16-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint8 vtable_8bt_32bi(vint8 t0, vint8 idx)
+{
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m256i idxx = _mm256_or_si256(idx.m, _mm256_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+ __m256i result = _mm256_shuffle_epi8(t0.m, idxx);
+ return vint8(result);
+}
+
+/**
+ * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint8 vtable_8bt_32bi(vint8 t0, vint8 t1, vint8 idx)
+{
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m256i idxx = _mm256_or_si256(idx.m, _mm256_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+ __m256i result = _mm256_shuffle_epi8(t0.m, idxx);
+ idxx = _mm256_sub_epi8(idxx, _mm256_set1_epi8(16));
+
+ __m256i result2 = _mm256_shuffle_epi8(t1.m, idxx);
+ result = _mm256_xor_si256(result, result2);
+ return vint8(result);
+}
+
+/**
+ * @brief Perform an 8-bit 64-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint8 vtable_8bt_32bi(vint8 t0, vint8 t1, vint8 t2, vint8 t3, vint8 idx)
+{
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m256i idxx = _mm256_or_si256(idx.m, _mm256_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+ __m256i result = _mm256_shuffle_epi8(t0.m, idxx);
+ idxx = _mm256_sub_epi8(idxx, _mm256_set1_epi8(16));
+
+ __m256i result2 = _mm256_shuffle_epi8(t1.m, idxx);
+ result = _mm256_xor_si256(result, result2);
+ idxx = _mm256_sub_epi8(idxx, _mm256_set1_epi8(16));
+
+ result2 = _mm256_shuffle_epi8(t2.m, idxx);
+ result = _mm256_xor_si256(result, result2);
+ idxx = _mm256_sub_epi8(idxx, _mm256_set1_epi8(16));
+
+ result2 = _mm256_shuffle_epi8(t3.m, idxx);
+ result = _mm256_xor_si256(result, result2);
+
+ return vint8(result);
+}
+
+/**
+ * @brief Return a vector of interleaved RGBA data.
+ *
+ * Input vectors have the value stored in the bottom 8 bits of each lane,
+ * with high bits set to zero.
+ *
+ * Output vector stores a single RGBA texel packed in each lane.
+ */
+ASTCENC_SIMD_INLINE vint8 interleave_rgba8(vint8 r, vint8 g, vint8 b, vint8 a)
+{
+ return r + lsl<8>(g) + lsl<16>(b) + lsl<24>(a);
+}
+
+/**
+ * @brief Store a vector, skipping masked lanes.
+ *
+ * All masked lanes must be at the end of vector, after all non-masked lanes.
+ */
+ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint8 data, vmask8 mask)
+{
+ _mm256_maskstore_epi32(base, _mm256_castps_si256(mask.m), data.m);
+}
+
+/**
+ * @brief Debug function to print a vector of ints.
+ */
+ASTCENC_SIMD_INLINE void print(vint8 a)
+{
+ alignas(ASTCENC_VECALIGN) int v[8];
+ storea(a, v);
+ printf("v8_i32:\n %8d %8d %8d %8d %8d %8d %8d %8d\n",
+ v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+}
+
+/**
+ * @brief Debug function to print a vector of ints.
+ */
+ASTCENC_SIMD_INLINE void printx(vint8 a)
+{
+ alignas(ASTCENC_VECALIGN) int v[8];
+ storea(a, v);
+ printf("v8_i32:\n %08x %08x %08x %08x %08x %08x %08x %08x\n",
+ v[0], v[1], v[2], v[3], v[4], v[5], v[6], v[7]);
+}
+
+/**
+ * @brief Debug function to print a vector of floats.
+ */
+ASTCENC_SIMD_INLINE void print(vfloat8 a)
+{
+ alignas(ASTCENC_VECALIGN) float v[8];
+ storea(a, v);
+ printf("v8_f32:\n %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f %0.4f\n",
+ static_cast<double>(v[0]), static_cast<double>(v[1]),
+ static_cast<double>(v[2]), static_cast<double>(v[3]),
+ static_cast<double>(v[4]), static_cast<double>(v[5]),
+ static_cast<double>(v[6]), static_cast<double>(v[7]));
+}
+
+/**
+ * @brief Debug function to print a vector of masks.
+ */
+ASTCENC_SIMD_INLINE void print(vmask8 a)
+{
+ print(select(vint8(0), vint8(1), a));
+}
+
+#endif // #ifndef ASTC_VECMATHLIB_AVX2_8_H_INCLUDED
diff --git a/thirdparty/astcenc/astcenc_vecmathlib_common_4.h b/thirdparty/astcenc/astcenc_vecmathlib_common_4.h
new file mode 100644
index 0000000000..86ee4fd3e1
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_vecmathlib_common_4.h
@@ -0,0 +1,423 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2020-2021 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Generic 4x32-bit vector functions.
+ *
+ * This module implements generic 4-wide vector functions that are valid for
+ * all instruction sets, typically implemented using lower level 4-wide
+ * operations that are ISA-specific.
+ */
+
+#ifndef ASTC_VECMATHLIB_COMMON_4_H_INCLUDED
+#define ASTC_VECMATHLIB_COMMON_4_H_INCLUDED
+
+#ifndef ASTCENC_SIMD_INLINE
+ #error "Include astcenc_vecmathlib.h, do not include directly"
+#endif
+
+#include <cstdio>
+
+// ============================================================================
+// vmask4 operators and functions
+// ============================================================================
+
+/**
+ * @brief True if any lanes are enabled, false otherwise.
+ */
+ASTCENC_SIMD_INLINE bool any(vmask4 a)
+{
+ return mask(a) != 0;
+}
+
+/**
+ * @brief True if all lanes are enabled, false otherwise.
+ */
+ASTCENC_SIMD_INLINE bool all(vmask4 a)
+{
+ return mask(a) == 0xF;
+}
+
+// ============================================================================
+// vint4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by scalar addition.
+ */
+ASTCENC_SIMD_INLINE vint4 operator+(vint4 a, int b)
+{
+ return a + vint4(b);
+}
+
+/**
+ * @brief Overload: vector by vector incremental addition.
+ */
+ASTCENC_SIMD_INLINE vint4& operator+=(vint4& a, const vint4& b)
+{
+ a = a + b;
+ return a;
+}
+
+/**
+ * @brief Overload: vector by scalar subtraction.
+ */
+ASTCENC_SIMD_INLINE vint4 operator-(vint4 a, int b)
+{
+ return a - vint4(b);
+}
+
+/**
+ * @brief Overload: vector by scalar multiplication.
+ */
+ASTCENC_SIMD_INLINE vint4 operator*(vint4 a, int b)
+{
+ return a * vint4(b);
+}
+
+/**
+ * @brief Overload: vector by scalar bitwise or.
+ */
+ASTCENC_SIMD_INLINE vint4 operator|(vint4 a, int b)
+{
+ return a | vint4(b);
+}
+
+/**
+ * @brief Overload: vector by scalar bitwise and.
+ */
+ASTCENC_SIMD_INLINE vint4 operator&(vint4 a, int b)
+{
+ return a & vint4(b);
+}
+
+/**
+ * @brief Overload: vector by scalar bitwise xor.
+ */
+ASTCENC_SIMD_INLINE vint4 operator^(vint4 a, int b)
+{
+ return a ^ vint4(b);
+}
+
+/**
+ * @brief Return the clamped value between min and max.
+ */
+ASTCENC_SIMD_INLINE vint4 clamp(int minv, int maxv, vint4 a)
+{
+ return min(max(a, vint4(minv)), vint4(maxv));
+}
+
+/**
+ * @brief Return the horizontal sum of RGB vector lanes as a scalar.
+ */
+ASTCENC_SIMD_INLINE int hadd_rgb_s(vint4 a)
+{
+ return a.lane<0>() + a.lane<1>() + a.lane<2>();
+}
+
+// ============================================================================
+// vfloat4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by vector incremental addition.
+ */
+ASTCENC_SIMD_INLINE vfloat4& operator+=(vfloat4& a, const vfloat4& b)
+{
+ a = a + b;
+ return a;
+}
+
+/**
+ * @brief Overload: vector by scalar addition.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator+(vfloat4 a, float b)
+{
+ return a + vfloat4(b);
+}
+
+/**
+ * @brief Overload: vector by scalar subtraction.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator-(vfloat4 a, float b)
+{
+ return a - vfloat4(b);
+}
+
+/**
+ * @brief Overload: vector by scalar multiplication.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator*(vfloat4 a, float b)
+{
+ return a * vfloat4(b);
+}
+
+/**
+ * @brief Overload: scalar by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator*(float a, vfloat4 b)
+{
+ return vfloat4(a) * b;
+}
+
+/**
+ * @brief Overload: vector by scalar division.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator/(vfloat4 a, float b)
+{
+ return a / vfloat4(b);
+}
+
+/**
+ * @brief Overload: scalar by vector division.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator/(float a, vfloat4 b)
+{
+ return vfloat4(a) / b;
+}
+
+/**
+ * @brief Return the min vector of a vector and a scalar.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 min(vfloat4 a, float b)
+{
+ return min(a, vfloat4(b));
+}
+
+/**
+ * @brief Return the max vector of a vector and a scalar.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 max(vfloat4 a, float b)
+{
+ return max(a, vfloat4(b));
+}
+
+/**
+ * @brief Return the clamped value between min and max.
+ *
+ * It is assumed that neither @c min nor @c max are NaN values. If @c a is NaN
+ * then @c min will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 clamp(float minv, float maxv, vfloat4 a)
+{
+ // Do not reorder - second operand will return if either is NaN
+ return min(max(a, minv), maxv);
+}
+
+/**
+ * @brief Return the clamped value between 0.0f and max.
+ *
+ * It is assumed that @c max is not a NaN value. If @c a is NaN then zero will
+ * be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 clampz(float maxv, vfloat4 a)
+{
+ // Do not reorder - second operand will return if either is NaN
+ return min(max(a, vfloat4::zero()), maxv);
+}
+
+/**
+ * @brief Return the clamped value between 0.0f and 1.0f.
+ *
+ * If @c a is NaN then zero will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 clampzo(vfloat4 a)
+{
+ // Do not reorder - second operand will return if either is NaN
+ return min(max(a, vfloat4::zero()), 1.0f);
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE float hmin_s(vfloat4 a)
+{
+ return hmin(a).lane<0>();
+}
+
+/**
+ * @brief Return the horizontal min of RGB vector lanes as a scalar.
+ */
+ASTCENC_SIMD_INLINE float hmin_rgb_s(vfloat4 a)
+{
+ a.set_lane<3>(a.lane<0>());
+ return hmin_s(a);
+}
+
+/**
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE float hmax_s(vfloat4 a)
+{
+ return hmax(a).lane<0>();
+}
+
+/**
+ * @brief Accumulate lane-wise sums for a vector.
+ */
+ASTCENC_SIMD_INLINE void haccumulate(vfloat4& accum, vfloat4 a)
+{
+ accum = accum + a;
+}
+
+/**
+ * @brief Accumulate lane-wise sums for a masked vector.
+ */
+ASTCENC_SIMD_INLINE void haccumulate(vfloat4& accum, vfloat4 a, vmask4 m)
+{
+ a = select(vfloat4::zero(), a, m);
+ haccumulate(accum, a);
+}
+
+/**
+ * @brief Return the horizontal sum of RGB vector lanes as a scalar.
+ */
+ASTCENC_SIMD_INLINE float hadd_rgb_s(vfloat4 a)
+{
+ return a.lane<0>() + a.lane<1>() + a.lane<2>();
+}
+
+#if !defined(ASTCENC_USE_NATIVE_DOT_PRODUCT)
+
+/**
+ * @brief Return the dot product for the full 4 lanes, returning scalar.
+ */
+ASTCENC_SIMD_INLINE float dot_s(vfloat4 a, vfloat4 b)
+{
+ vfloat4 m = a * b;
+ return hadd_s(m);
+}
+
+/**
+ * @brief Return the dot product for the full 4 lanes, returning vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 dot(vfloat4 a, vfloat4 b)
+{
+ vfloat4 m = a * b;
+ return vfloat4(hadd_s(m));
+}
+
+/**
+ * @brief Return the dot product for the bottom 3 lanes, returning scalar.
+ */
+ASTCENC_SIMD_INLINE float dot3_s(vfloat4 a, vfloat4 b)
+{
+ vfloat4 m = a * b;
+ return hadd_rgb_s(m);
+}
+
+/**
+ * @brief Return the dot product for the bottom 3 lanes, returning vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 dot3(vfloat4 a, vfloat4 b)
+{
+ vfloat4 m = a * b;
+ float d3 = hadd_rgb_s(m);
+ return vfloat4(d3, d3, d3, 0.0f);
+}
+
+#endif
+
+#if !defined(ASTCENC_USE_NATIVE_POPCOUNT)
+
+/**
+ * @brief Population bit count.
+ *
+ * @param v The value to population count.
+ *
+ * @return The number of 1 bits.
+ */
+static inline int popcount(uint64_t v)
+{
+ uint64_t mask1 = 0x5555555555555555ULL;
+ uint64_t mask2 = 0x3333333333333333ULL;
+ uint64_t mask3 = 0x0F0F0F0F0F0F0F0FULL;
+ v -= (v >> 1) & mask1;
+ v = (v & mask2) + ((v >> 2) & mask2);
+ v += v >> 4;
+ v &= mask3;
+ v *= 0x0101010101010101ULL;
+ v >>= 56;
+ return static_cast<int>(v);
+}
+
+#endif
+
+/**
+ * @brief Apply signed bit transfer.
+ *
+ * @param input0 The first encoded endpoint.
+ * @param input1 The second encoded endpoint.
+ */
+static ASTCENC_SIMD_INLINE void bit_transfer_signed(
+ vint4& input0,
+ vint4& input1
+) {
+ input1 = lsr<1>(input1) | (input0 & 0x80);
+ input0 = lsr<1>(input0) & 0x3F;
+
+ vmask4 mask = (input0 & 0x20) != vint4::zero();
+ input0 = select(input0, input0 - 0x40, mask);
+}
+
+/**
+ * @brief Debug function to print a vector of ints.
+ */
+ASTCENC_SIMD_INLINE void print(vint4 a)
+{
+ alignas(16) int v[4];
+ storea(a, v);
+ printf("v4_i32:\n %8d %8d %8d %8d\n",
+ v[0], v[1], v[2], v[3]);
+}
+
+/**
+ * @brief Debug function to print a vector of ints.
+ */
+ASTCENC_SIMD_INLINE void printx(vint4 a)
+{
+ alignas(16) int v[4];
+ storea(a, v);
+ printf("v4_i32:\n %08x %08x %08x %08x\n",
+ v[0], v[1], v[2], v[3]);
+}
+
+/**
+ * @brief Debug function to print a vector of floats.
+ */
+ASTCENC_SIMD_INLINE void print(vfloat4 a)
+{
+ alignas(16) float v[4];
+ storea(a, v);
+ printf("v4_f32:\n %0.4f %0.4f %0.4f %0.4f\n",
+ static_cast<double>(v[0]), static_cast<double>(v[1]),
+ static_cast<double>(v[2]), static_cast<double>(v[3]));
+}
+
+/**
+ * @brief Debug function to print a vector of masks.
+ */
+ASTCENC_SIMD_INLINE void print(vmask4 a)
+{
+ print(select(vint4(0), vint4(1), a));
+}
+
+#endif // #ifndef ASTC_VECMATHLIB_COMMON_4_H_INCLUDED
diff --git a/thirdparty/astcenc/astcenc_vecmathlib_neon_4.h b/thirdparty/astcenc/astcenc_vecmathlib_neon_4.h
new file mode 100644
index 0000000000..e742eae6cb
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_vecmathlib_neon_4.h
@@ -0,0 +1,1072 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2019-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief 4x32-bit vectors, implemented using Armv8-A NEON.
+ *
+ * This module implements 4-wide 32-bit float, int, and mask vectors for
+ * Armv8-A NEON.
+ *
+ * There is a baseline level of functionality provided by all vector widths and
+ * implementations. This is implemented using identical function signatures,
+ * modulo data type, so we can use them as substitutable implementations in VLA
+ * code.
+ *
+ * The 4-wide vectors are also used as a fixed-width type, and significantly
+ * extend the functionality above that available to VLA code.
+ */
+
+#ifndef ASTC_VECMATHLIB_NEON_4_H_INCLUDED
+#define ASTC_VECMATHLIB_NEON_4_H_INCLUDED
+
+#ifndef ASTCENC_SIMD_INLINE
+ #error "Include astcenc_vecmathlib.h, do not include directly"
+#endif
+
+#include <cstdio>
+
+// ============================================================================
+// vfloat4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide floats.
+ */
+struct vfloat4
+{
+ /**
+ * @brief Construct from zero-initialized value.
+ */
+ ASTCENC_SIMD_INLINE vfloat4() = default;
+
+ /**
+ * @brief Construct from 4 values loaded from an unaligned address.
+ *
+ * Consider using loada() which is better with vectors if data is aligned
+ * to vector length.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(const float *p)
+ {
+ m = vld1q_f32(p);
+ }
+
+ /**
+ * @brief Construct from 1 scalar value replicated across all lanes.
+ *
+ * Consider using zero() for constexpr zeros.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(float a)
+ {
+ m = vdupq_n_f32(a);
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(float a, float b, float c, float d)
+ {
+ float v[4] { a, b, c, d };
+ m = vld1q_f32(v);
+ }
+
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(float32x4_t a)
+ {
+ m = a;
+ }
+
+ /**
+ * @brief Get the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE float lane() const
+ {
+ return vgetq_lane_f32(m, l);
+ }
+
+ /**
+ * @brief Set the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE void set_lane(float a)
+ {
+ m = vsetq_lane_f32(a, m, l);
+ }
+
+ /**
+ * @brief Factory that returns a vector of zeros.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 zero()
+ {
+ return vfloat4(vdupq_n_f32(0.0f));
+ }
+
+ /**
+ * @brief Factory that returns a replicated scalar loaded from memory.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 load1(const float* p)
+ {
+ return vfloat4(vld1q_dup_f32(p));
+ }
+
+ /**
+ * @brief Factory that returns a vector loaded from 16B aligned memory.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 loada(const float* p)
+ {
+ return vfloat4(vld1q_f32(p));
+ }
+
+ /**
+ * @brief Factory that returns a vector containing the lane IDs.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 lane_id()
+ {
+ alignas(16) float data[4] { 0.0f, 1.0f, 2.0f, 3.0f };
+ return vfloat4(vld1q_f32(data));
+ }
+
+ /**
+ * @brief Return a swizzled float 2.
+ */
+ template <int l0, int l1> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ return vfloat4(lane<l0>(), lane<l1>(), 0.0f, 0.0f);
+ }
+
+ /**
+ * @brief Return a swizzled float 3.
+ */
+ template <int l0, int l1, int l2> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ return vfloat4(lane<l0>(), lane<l1>(), lane<l2>(), 0.0f);
+ }
+
+ /**
+ * @brief Return a swizzled float 4.
+ */
+ template <int l0, int l1, int l2, int l3> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ return vfloat4(lane<l0>(), lane<l1>(), lane<l2>(), lane<l3>());
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ float32x4_t m;
+};
+
+// ============================================================================
+// vint4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide ints.
+ */
+struct vint4
+{
+ /**
+ * @brief Construct from zero-initialized value.
+ */
+ ASTCENC_SIMD_INLINE vint4() = default;
+
+ /**
+ * @brief Construct from 4 values loaded from an unaligned address.
+ *
+ * Consider using loada() which is better with vectors if data is aligned
+ * to vector length.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(const int *p)
+ {
+ m = vld1q_s32(p);
+ }
+
+ /**
+ * @brief Construct from 4 uint8_t loaded from an unaligned address.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(const uint8_t *p)
+ {
+ // Cast is safe - NEON loads are allowed to be unaligned
+ uint32x2_t t8 = vld1_dup_u32(reinterpret_cast<const uint32_t*>(p));
+ uint16x4_t t16 = vget_low_u16(vmovl_u8(vreinterpret_u8_u32(t8)));
+ m = vreinterpretq_s32_u32(vmovl_u16(t16));
+ }
+
+ /**
+ * @brief Construct from 1 scalar value replicated across all lanes.
+ *
+ * Consider using vfloat4::zero() for constexpr zeros.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(int a)
+ {
+ m = vdupq_n_s32(a);
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(int a, int b, int c, int d)
+ {
+ int v[4] { a, b, c, d };
+ m = vld1q_s32(v);
+ }
+
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(int32x4_t a)
+ {
+ m = a;
+ }
+
+ /**
+ * @brief Get the scalar from a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE int lane() const
+ {
+ return vgetq_lane_s32(m, l);
+ }
+
+ /**
+ * @brief Set the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE void set_lane(int a)
+ {
+ m = vsetq_lane_s32(a, m, l);
+ }
+
+ /**
+ * @brief Factory that returns a vector of zeros.
+ */
+ static ASTCENC_SIMD_INLINE vint4 zero()
+ {
+ return vint4(0);
+ }
+
+ /**
+ * @brief Factory that returns a replicated scalar loaded from memory.
+ */
+ static ASTCENC_SIMD_INLINE vint4 load1(const int* p)
+ {
+ return vint4(*p);
+ }
+
+ /**
+ * @brief Factory that returns a vector loaded from 16B aligned memory.
+ */
+ static ASTCENC_SIMD_INLINE vint4 loada(const int* p)
+ {
+ return vint4(p);
+ }
+
+ /**
+ * @brief Factory that returns a vector containing the lane IDs.
+ */
+ static ASTCENC_SIMD_INLINE vint4 lane_id()
+ {
+ alignas(16) static const int data[4] { 0, 1, 2, 3 };
+ return vint4(vld1q_s32(data));
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ int32x4_t m;
+};
+
+// ============================================================================
+// vmask4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide control plane masks.
+ */
+struct vmask4
+{
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(uint32x4_t a)
+ {
+ m = a;
+ }
+
+#if !defined(_MSC_VER)
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(int32x4_t a)
+ {
+ m = vreinterpretq_u32_s32(a);
+ }
+#endif
+
+ /**
+ * @brief Construct from 1 scalar value.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(bool a)
+ {
+ m = vreinterpretq_u32_s32(vdupq_n_s32(a == true ? -1 : 0));
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(bool a, bool b, bool c, bool d)
+ {
+ int v[4] {
+ a == true ? -1 : 0,
+ b == true ? -1 : 0,
+ c == true ? -1 : 0,
+ d == true ? -1 : 0
+ };
+
+ int32x4_t ms = vld1q_s32(v);
+ m = vreinterpretq_u32_s32(ms);
+ }
+
+ /**
+ * @brief Get the scalar from a single lane.
+ */
+ template <int32_t l> ASTCENC_SIMD_INLINE uint32_t lane() const
+ {
+ return vgetq_lane_u32(m, l);
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ uint32x4_t m;
+};
+
+// ============================================================================
+// vmask4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: mask union (or).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator|(vmask4 a, vmask4 b)
+{
+ return vmask4(vorrq_u32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask intersect (and).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator&(vmask4 a, vmask4 b)
+{
+ return vmask4(vandq_u32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask difference (xor).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator^(vmask4 a, vmask4 b)
+{
+ return vmask4(veorq_u32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask invert (not).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator~(vmask4 a)
+{
+ return vmask4(vmvnq_u32(a.m));
+}
+
+/**
+ * @brief Return a 4-bit mask code indicating mask status.
+ *
+ * bit0 = lane 0
+ */
+ASTCENC_SIMD_INLINE unsigned int mask(vmask4 a)
+{
+ static const int shifta[4] { 0, 1, 2, 3 };
+ static const int32x4_t shift = vld1q_s32(shifta);
+
+ uint32x4_t tmp = vshrq_n_u32(a.m, 31);
+ return vaddvq_u32(vshlq_u32(tmp, shift));
+}
+
+// ============================================================================
+// vint4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by vector addition.
+ */
+ASTCENC_SIMD_INLINE vint4 operator+(vint4 a, vint4 b)
+{
+ return vint4(vaddq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector subtraction.
+ */
+ASTCENC_SIMD_INLINE vint4 operator-(vint4 a, vint4 b)
+{
+ return vint4(vsubq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vint4 operator*(vint4 a, vint4 b)
+{
+ return vint4(vmulq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector bit invert.
+ */
+ASTCENC_SIMD_INLINE vint4 operator~(vint4 a)
+{
+ return vint4(vmvnq_s32(a.m));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise or.
+ */
+ASTCENC_SIMD_INLINE vint4 operator|(vint4 a, vint4 b)
+{
+ return vint4(vorrq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise and.
+ */
+ASTCENC_SIMD_INLINE vint4 operator&(vint4 a, vint4 b)
+{
+ return vint4(vandq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise xor.
+ */
+ASTCENC_SIMD_INLINE vint4 operator^(vint4 a, vint4 b)
+{
+ return vint4(veorq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector equality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator==(vint4 a, vint4 b)
+{
+ return vmask4(vceqq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector inequality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator!=(vint4 a, vint4 b)
+{
+ return ~vmask4(vceqq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector less than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<(vint4 a, vint4 b)
+{
+ return vmask4(vcltq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector greater than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>(vint4 a, vint4 b)
+{
+ return vmask4(vcgtq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Logical shift left.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 lsl(vint4 a)
+{
+ return vint4(vshlq_s32(a.m, vdupq_n_s32(s)));
+}
+
+/**
+ * @brief Logical shift right.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 lsr(vint4 a)
+{
+ uint32x4_t ua = vreinterpretq_u32_s32(a.m);
+ ua = vshlq_u32(ua, vdupq_n_s32(-s));
+ return vint4(vreinterpretq_s32_u32(ua));
+}
+
+/**
+ * @brief Arithmetic shift right.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 asr(vint4 a)
+{
+ return vint4(vshlq_s32(a.m, vdupq_n_s32(-s)));
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ */
+ASTCENC_SIMD_INLINE vint4 min(vint4 a, vint4 b)
+{
+ return vint4(vminq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Return the max vector of two vectors.
+ */
+ASTCENC_SIMD_INLINE vint4 max(vint4 a, vint4 b)
+{
+ return vint4(vmaxq_s32(a.m, b.m));
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE vint4 hmin(vint4 a)
+{
+ return vint4(vminvq_s32(a.m));
+}
+
+/**
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE vint4 hmax(vint4 a)
+{
+ return vint4(vmaxvq_s32(a.m));
+}
+
+/**
+ * @brief Return the horizontal sum of a vector.
+ */
+ASTCENC_SIMD_INLINE int hadd_s(vint4 a)
+{
+ int32x2_t t = vadd_s32(vget_high_s32(a.m), vget_low_s32(a.m));
+ return vget_lane_s32(vpadd_s32(t, t), 0);
+}
+
+/**
+ * @brief Store a vector to a 16B aligned memory address.
+ */
+ASTCENC_SIMD_INLINE void storea(vint4 a, int* p)
+{
+ vst1q_s32(p, a.m);
+}
+
+/**
+ * @brief Store a vector to an unaligned memory address.
+ */
+ASTCENC_SIMD_INLINE void store(vint4 a, int* p)
+{
+ vst1q_s32(p, a.m);
+}
+
+/**
+ * @brief Store lowest N (vector width) bytes into an unaligned address.
+ */
+ASTCENC_SIMD_INLINE void store_nbytes(vint4 a, uint8_t* p)
+{
+ vst1q_lane_s32(reinterpret_cast<int32_t*>(p), a.m, 0);
+}
+
+/**
+ * @brief Gather N (vector width) indices from the array.
+ */
+ASTCENC_SIMD_INLINE vint4 gatheri(const int* base, vint4 indices)
+{
+ alignas(16) int idx[4];
+ storea(indices, idx);
+ alignas(16) int vals[4];
+ vals[0] = base[idx[0]];
+ vals[1] = base[idx[1]];
+ vals[2] = base[idx[2]];
+ vals[3] = base[idx[3]];
+ return vint4(vals);
+}
+
+/**
+ * @brief Pack low 8 bits of N (vector width) lanes into bottom of vector.
+ */
+ASTCENC_SIMD_INLINE vint4 pack_low_bytes(vint4 a)
+{
+ alignas(16) uint8_t shuf[16] {
+ 0, 4, 8, 12, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0
+ };
+ uint8x16_t idx = vld1q_u8(shuf);
+ int8x16_t av = vreinterpretq_s8_s32(a.m);
+ return vint4(vreinterpretq_s32_s8(vqtbl1q_s8(av, idx)));
+}
+
+/**
+ * @brief Return lanes from @c b if @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vint4 select(vint4 a, vint4 b, vmask4 cond)
+{
+ return vint4(vbslq_s32(cond.m, b.m, a.m));
+}
+
+// ============================================================================
+// vfloat4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by vector addition.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator+(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(vaddq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector subtraction.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator-(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(vsubq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator*(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(vmulq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector division.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator/(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(vdivq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector equality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator==(vfloat4 a, vfloat4 b)
+{
+ return vmask4(vceqq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector inequality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator!=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(vmvnq_u32(vceqq_f32(a.m, b.m)));
+}
+
+/**
+ * @brief Overload: vector by vector less than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<(vfloat4 a, vfloat4 b)
+{
+ return vmask4(vcltq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector greater than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>(vfloat4 a, vfloat4 b)
+{
+ return vmask4(vcgtq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector less than or equal.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(vcleq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector greater than or equal.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(vcgeq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 min(vfloat4 a, vfloat4 b)
+{
+ // Do not reorder - second operand will return if either is NaN
+ return vfloat4(vminnmq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Return the max vector of two vectors.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 max(vfloat4 a, vfloat4 b)
+{
+ // Do not reorder - second operand will return if either is NaN
+ return vfloat4(vmaxnmq_f32(a.m, b.m));
+}
+
+/**
+ * @brief Return the absolute value of the float vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 abs(vfloat4 a)
+{
+ float32x4_t zero = vdupq_n_f32(0.0f);
+ float32x4_t inv = vsubq_f32(zero, a.m);
+ return vfloat4(vmaxq_f32(a.m, inv));
+}
+
+/**
+ * @brief Return a float rounded to the nearest integer value.
+ */
+ASTCENC_SIMD_INLINE vfloat4 round(vfloat4 a)
+{
+ return vfloat4(vrndnq_f32(a.m));
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 hmin(vfloat4 a)
+{
+ return vfloat4(vminvq_f32(a.m));
+}
+
+/**
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 hmax(vfloat4 a)
+{
+ return vfloat4(vmaxvq_f32(a.m));
+}
+
+/**
+ * @brief Return the horizontal sum of a vector.
+ */
+ASTCENC_SIMD_INLINE float hadd_s(vfloat4 a)
+{
+ // Perform halving add to ensure invariance; we cannot use vaddqv as this
+ // does (0 + 1 + 2 + 3) which is not invariant with x86 (0 + 2) + (1 + 3).
+ float32x2_t t = vadd_f32(vget_high_f32(a.m), vget_low_f32(a.m));
+ return vget_lane_f32(vpadd_f32(t, t), 0);
+}
+
+/**
+ * @brief Return the sqrt of the lanes in the vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 sqrt(vfloat4 a)
+{
+ return vfloat4(vsqrtq_f32(a.m));
+}
+
+/**
+ * @brief Return lanes from @c b if @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vfloat4 select(vfloat4 a, vfloat4 b, vmask4 cond)
+{
+ return vfloat4(vbslq_f32(cond.m, b.m, a.m));
+}
+
+/**
+ * @brief Return lanes from @c b if MSB of @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vfloat4 select_msb(vfloat4 a, vfloat4 b, vmask4 cond)
+{
+ static const uint32x4_t msb = vdupq_n_u32(0x80000000u);
+ uint32x4_t mask = vcgeq_u32(cond.m, msb);
+ return vfloat4(vbslq_f32(mask, b.m, a.m));
+}
+
+/**
+ * @brief Load a vector of gathered results from an array;
+ */
+ASTCENC_SIMD_INLINE vfloat4 gatherf(const float* base, vint4 indices)
+{
+ alignas(16) int idx[4];
+ storea(indices, idx);
+ alignas(16) float vals[4];
+ vals[0] = base[idx[0]];
+ vals[1] = base[idx[1]];
+ vals[2] = base[idx[2]];
+ vals[3] = base[idx[3]];
+ return vfloat4(vals);
+}
+
+/**
+ * @brief Store a vector to an unaligned memory address.
+ */
+ASTCENC_SIMD_INLINE void store(vfloat4 a, float* p)
+{
+ vst1q_f32(p, a.m);
+}
+
+/**
+ * @brief Store a vector to a 16B aligned memory address.
+ */
+ASTCENC_SIMD_INLINE void storea(vfloat4 a, float* p)
+{
+ vst1q_f32(p, a.m);
+}
+
+/**
+ * @brief Return a integer value for a float vector, using truncation.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_int(vfloat4 a)
+{
+ return vint4(vcvtq_s32_f32(a.m));
+}
+
+/**
+ * @brief Return a integer value for a float vector, using round-to-nearest.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_int_rtn(vfloat4 a)
+{
+ a = round(a);
+ return vint4(vcvtq_s32_f32(a.m));
+}
+
+/**
+ * @brief Return a float value for an integer vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 int_to_float(vint4 a)
+{
+ return vfloat4(vcvtq_f32_s32(a.m));
+}
+
+/**
+ * @brief Return a float16 value for a float vector, using round-to-nearest.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_float16(vfloat4 a)
+{
+ // Generate float16 value
+ float16x4_t f16 = vcvt_f16_f32(a.m);
+
+ // Convert each 16-bit float pattern to a 32-bit pattern
+ uint16x4_t u16 = vreinterpret_u16_f16(f16);
+ uint32x4_t u32 = vmovl_u16(u16);
+ return vint4(vreinterpretq_s32_u32(u32));
+}
+
+/**
+ * @brief Return a float16 value for a float scalar, using round-to-nearest.
+ */
+static inline uint16_t float_to_float16(float a)
+{
+ vfloat4 av(a);
+ return static_cast<uint16_t>(float_to_float16(av).lane<0>());
+}
+
+/**
+ * @brief Return a float value for a float16 vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 float16_to_float(vint4 a)
+{
+ // Convert each 32-bit float pattern to a 16-bit pattern
+ uint32x4_t u32 = vreinterpretq_u32_s32(a.m);
+ uint16x4_t u16 = vmovn_u32(u32);
+ float16x4_t f16 = vreinterpret_f16_u16(u16);
+
+ // Generate float16 value
+ return vfloat4(vcvt_f32_f16(f16));
+}
+
+/**
+ * @brief Return a float value for a float16 scalar.
+ */
+ASTCENC_SIMD_INLINE float float16_to_float(uint16_t a)
+{
+ vint4 av(a);
+ return float16_to_float(av).lane<0>();
+}
+
+/**
+ * @brief Return a float value as an integer bit pattern (i.e. no conversion).
+ *
+ * It is a common trick to convert floats into integer bit patterns, perform
+ * some bit hackery based on knowledge they are IEEE 754 layout, and then
+ * convert them back again. This is the first half of that flip.
+ */
+ASTCENC_SIMD_INLINE vint4 float_as_int(vfloat4 a)
+{
+ return vint4(vreinterpretq_s32_f32(a.m));
+}
+
+/**
+ * @brief Return a integer value as a float bit pattern (i.e. no conversion).
+ *
+ * It is a common trick to convert floats into integer bit patterns, perform
+ * some bit hackery based on knowledge they are IEEE 754 layout, and then
+ * convert them back again. This is the second half of that flip.
+ */
+ASTCENC_SIMD_INLINE vfloat4 int_as_float(vint4 v)
+{
+ return vfloat4(vreinterpretq_f32_s32(v.m));
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4& t0p)
+{
+ t0p = t0;
+}
+
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint4& t0p, vint4& t1p)
+{
+ t0p = t0;
+ t1p = t1;
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(
+ vint4 t0, vint4 t1, vint4 t2, vint4 t3,
+ vint4& t0p, vint4& t1p, vint4& t2p, vint4& t3p)
+{
+ t0p = t0;
+ t1p = t1;
+ t2p = t2;
+ t3p = t3;
+}
+
+/**
+ * @brief Perform an 8-bit 16-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx)
+{
+ int8x16_t table {
+ vreinterpretq_s8_s32(t0.m)
+ };
+
+ // Set index byte above max index for unused bytes so table lookup returns zero
+ int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00));
+ uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
+
+ return vint4(vreinterpretq_s32_s8(vqtbl1q_s8(table, idx_bytes)));
+}
+
+/**
+ * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx)
+{
+ int8x16x2_t table {
+ vreinterpretq_s8_s32(t0.m),
+ vreinterpretq_s8_s32(t1.m)
+ };
+
+ // Set index byte above max index for unused bytes so table lookup returns zero
+ int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00));
+ uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
+
+ return vint4(vreinterpretq_s32_s8(vqtbl2q_s8(table, idx_bytes)));
+}
+
+/**
+ * @brief Perform an 8-bit 64-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx)
+{
+ int8x16x4_t table {
+ vreinterpretq_s8_s32(t0.m),
+ vreinterpretq_s8_s32(t1.m),
+ vreinterpretq_s8_s32(t2.m),
+ vreinterpretq_s8_s32(t3.m)
+ };
+
+ // Set index byte above max index for unused bytes so table lookup returns zero
+ int32x4_t idx_masked = vorrq_s32(idx.m, vdupq_n_s32(0xFFFFFF00));
+ uint8x16_t idx_bytes = vreinterpretq_u8_s32(idx_masked);
+
+ return vint4(vreinterpretq_s32_s8(vqtbl4q_s8(table, idx_bytes)));
+}
+
+/**
+ * @brief Return a vector of interleaved RGBA data.
+ *
+ * Input vectors have the value stored in the bottom 8 bits of each lane,
+ * with high bits set to zero.
+ *
+ * Output vector stores a single RGBA texel packed in each lane.
+ */
+ASTCENC_SIMD_INLINE vint4 interleave_rgba8(vint4 r, vint4 g, vint4 b, vint4 a)
+{
+ return r + lsl<8>(g) + lsl<16>(b) + lsl<24>(a);
+}
+
+/**
+ * @brief Store a vector, skipping masked lanes.
+ *
+ * All masked lanes must be at the end of vector, after all non-masked lanes.
+ */
+ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask)
+{
+ if (mask.lane<3>())
+ {
+ store(data, base);
+ }
+ else if (mask.lane<2>())
+ {
+ base[0] = data.lane<0>();
+ base[1] = data.lane<1>();
+ base[2] = data.lane<2>();
+ }
+ else if (mask.lane<1>())
+ {
+ base[0] = data.lane<0>();
+ base[1] = data.lane<1>();
+ }
+ else if (mask.lane<0>())
+ {
+ base[0] = data.lane<0>();
+ }
+}
+
+#define ASTCENC_USE_NATIVE_POPCOUNT 1
+
+/**
+ * @brief Population bit count.
+ *
+ * @param v The value to population count.
+ *
+ * @return The number of 1 bits.
+ */
+ASTCENC_SIMD_INLINE int popcount(uint64_t v)
+{
+ return static_cast<int>(vaddlv_u8(vcnt_u8(vcreate_u8(v))));
+}
+
+#endif // #ifndef ASTC_VECMATHLIB_NEON_4_H_INCLUDED
diff --git a/thirdparty/astcenc/astcenc_vecmathlib_none_4.h b/thirdparty/astcenc/astcenc_vecmathlib_none_4.h
new file mode 100644
index 0000000000..d9b52be3e4
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_vecmathlib_none_4.h
@@ -0,0 +1,1169 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2019-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief 4x32-bit vectors, implemented using plain C++.
+ *
+ * This module implements 4-wide 32-bit float, int, and mask vectors. This
+ * module provides a scalar fallback for VLA code, primarily useful for
+ * debugging VLA algorithms without the complexity of handling SIMD. Only the
+ * baseline level of functionality needed to support VLA is provided.
+ *
+ * Note that the vector conditional operators implemented by this module are
+ * designed to behave like SIMD conditional operators that generate lane masks.
+ * Rather than returning 0/1 booleans like normal C++ code they will return
+ * 0/-1 to give a full lane-width bitmask.
+ *
+ * Note that the documentation for this module still talks about "vectors" to
+ * help developers think about the implied VLA behavior when writing optimized
+ * paths.
+ */
+
+#ifndef ASTC_VECMATHLIB_NONE_4_H_INCLUDED
+#define ASTC_VECMATHLIB_NONE_4_H_INCLUDED
+
+#ifndef ASTCENC_SIMD_INLINE
+ #error "Include astcenc_vecmathlib.h, do not include directly"
+#endif
+
+#include <algorithm>
+#include <cstdio>
+#include <cstring>
+#include <cfenv>
+
+// ============================================================================
+// vfloat4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide floats.
+ */
+struct vfloat4
+{
+ /**
+ * @brief Construct from zero-initialized value.
+ */
+ ASTCENC_SIMD_INLINE vfloat4() = default;
+
+ /**
+ * @brief Construct from 4 values loaded from an unaligned address.
+ *
+ * Consider using loada() which is better with wider VLA vectors if data is
+ * aligned to vector length.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(const float* p)
+ {
+ m[0] = p[0];
+ m[1] = p[1];
+ m[2] = p[2];
+ m[3] = p[3];
+ }
+
+ /**
+ * @brief Construct from 4 scalar values replicated across all lanes.
+ *
+ * Consider using zero() for constexpr zeros.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(float a)
+ {
+ m[0] = a;
+ m[1] = a;
+ m[2] = a;
+ m[3] = a;
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(float a, float b, float c, float d)
+ {
+ m[0] = a;
+ m[1] = b;
+ m[2] = c;
+ m[3] = d;
+ }
+
+ /**
+ * @brief Get the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE float lane() const
+ {
+ return m[l];
+ }
+
+ /**
+ * @brief Set the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE void set_lane(float a)
+ {
+ m[l] = a;
+ }
+
+ /**
+ * @brief Factory that returns a vector of zeros.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 zero()
+ {
+ return vfloat4(0.0f);
+ }
+
+ /**
+ * @brief Factory that returns a replicated scalar loaded from memory.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 load1(const float* p)
+ {
+ return vfloat4(*p);
+ }
+
+ /**
+ * @brief Factory that returns a vector loaded from aligned memory.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 loada(const float* p)
+ {
+ return vfloat4(p);
+ }
+
+ /**
+ * @brief Factory that returns a vector containing the lane IDs.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 lane_id()
+ {
+ return vfloat4(0.0f, 1.0f, 2.0f, 3.0f);
+ }
+
+ /**
+ * @brief Return a swizzled float 2.
+ */
+ template <int l0, int l1> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ return vfloat4(lane<l0>(), lane<l1>(), 0.0f, 0.0f);
+ }
+
+ /**
+ * @brief Return a swizzled float 3.
+ */
+ template <int l0, int l1, int l2> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ return vfloat4(lane<l0>(), lane<l1>(), lane<l2>(), 0.0f);
+ }
+
+ /**
+ * @brief Return a swizzled float 4.
+ */
+ template <int l0, int l1, int l2, int l3> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ return vfloat4(lane<l0>(), lane<l1>(), lane<l2>(), lane<l3>());
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ float m[4];
+};
+
+// ============================================================================
+// vint4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide ints.
+ */
+struct vint4
+{
+ /**
+ * @brief Construct from zero-initialized value.
+ */
+ ASTCENC_SIMD_INLINE vint4() = default;
+
+ /**
+ * @brief Construct from 4 values loaded from an unaligned address.
+ *
+ * Consider using vint4::loada() which is better with wider VLA vectors
+ * if data is aligned.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(const int* p)
+ {
+ m[0] = p[0];
+ m[1] = p[1];
+ m[2] = p[2];
+ m[3] = p[3];
+ }
+
+ /**
+ * @brief Construct from 4 uint8_t loaded from an unaligned address.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(const uint8_t *p)
+ {
+ m[0] = p[0];
+ m[1] = p[1];
+ m[2] = p[2];
+ m[3] = p[3];
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(int a, int b, int c, int d)
+ {
+ m[0] = a;
+ m[1] = b;
+ m[2] = c;
+ m[3] = d;
+ }
+
+
+ /**
+ * @brief Construct from 4 scalar values replicated across all lanes.
+ *
+ * Consider using vint4::zero() for constexpr zeros.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(int a)
+ {
+ m[0] = a;
+ m[1] = a;
+ m[2] = a;
+ m[3] = a;
+ }
+
+ /**
+ * @brief Get the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE int lane() const
+ {
+ return m[l];
+ }
+
+ /**
+ * @brief Set the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE void set_lane(int a)
+ {
+ m[l] = a;
+ }
+
+ /**
+ * @brief Factory that returns a vector of zeros.
+ */
+ static ASTCENC_SIMD_INLINE vint4 zero()
+ {
+ return vint4(0);
+ }
+
+ /**
+ * @brief Factory that returns a replicated scalar loaded from memory.
+ */
+ static ASTCENC_SIMD_INLINE vint4 load1(const int* p)
+ {
+ return vint4(*p);
+ }
+
+ /**
+ * @brief Factory that returns a vector loaded from 16B aligned memory.
+ */
+ static ASTCENC_SIMD_INLINE vint4 loada(const int* p)
+ {
+ return vint4(p);
+ }
+
+ /**
+ * @brief Factory that returns a vector containing the lane IDs.
+ */
+ static ASTCENC_SIMD_INLINE vint4 lane_id()
+ {
+ return vint4(0, 1, 2, 3);
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ int m[4];
+};
+
+// ============================================================================
+// vmask4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide control plane masks.
+ */
+struct vmask4
+{
+ /**
+ * @brief Construct from an existing mask value.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(int* p)
+ {
+ m[0] = p[0];
+ m[1] = p[1];
+ m[2] = p[2];
+ m[3] = p[3];
+ }
+
+ /**
+ * @brief Construct from 1 scalar value.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(bool a)
+ {
+ m[0] = a == false ? 0 : -1;
+ m[1] = a == false ? 0 : -1;
+ m[2] = a == false ? 0 : -1;
+ m[3] = a == false ? 0 : -1;
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(bool a, bool b, bool c, bool d)
+ {
+ m[0] = a == false ? 0 : -1;
+ m[1] = b == false ? 0 : -1;
+ m[2] = c == false ? 0 : -1;
+ m[3] = d == false ? 0 : -1;
+ }
+
+
+ /**
+ * @brief The vector ...
+ */
+ int m[4];
+};
+
+// ============================================================================
+// vmask4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: mask union (or).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator|(vmask4 a, vmask4 b)
+{
+ return vmask4(a.m[0] | b.m[0],
+ a.m[1] | b.m[1],
+ a.m[2] | b.m[2],
+ a.m[3] | b.m[3]);
+}
+
+/**
+ * @brief Overload: mask intersect (and).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator&(vmask4 a, vmask4 b)
+{
+ return vmask4(a.m[0] & b.m[0],
+ a.m[1] & b.m[1],
+ a.m[2] & b.m[2],
+ a.m[3] & b.m[3]);
+}
+
+/**
+ * @brief Overload: mask difference (xor).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator^(vmask4 a, vmask4 b)
+{
+ return vmask4(a.m[0] ^ b.m[0],
+ a.m[1] ^ b.m[1],
+ a.m[2] ^ b.m[2],
+ a.m[3] ^ b.m[3]);
+}
+
+/**
+ * @brief Overload: mask invert (not).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator~(vmask4 a)
+{
+ return vmask4(~a.m[0],
+ ~a.m[1],
+ ~a.m[2],
+ ~a.m[3]);
+}
+
+/**
+ * @brief Return a 1-bit mask code indicating mask status.
+ *
+ * bit0 = lane 0
+ */
+ASTCENC_SIMD_INLINE unsigned int mask(vmask4 a)
+{
+ return ((a.m[0] >> 31) & 0x1) |
+ ((a.m[1] >> 30) & 0x2) |
+ ((a.m[2] >> 29) & 0x4) |
+ ((a.m[3] >> 28) & 0x8);
+}
+
+// ============================================================================
+// vint4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by vector addition.
+ */
+ASTCENC_SIMD_INLINE vint4 operator+(vint4 a, vint4 b)
+{
+ return vint4(a.m[0] + b.m[0],
+ a.m[1] + b.m[1],
+ a.m[2] + b.m[2],
+ a.m[3] + b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector subtraction.
+ */
+ASTCENC_SIMD_INLINE vint4 operator-(vint4 a, vint4 b)
+{
+ return vint4(a.m[0] - b.m[0],
+ a.m[1] - b.m[1],
+ a.m[2] - b.m[2],
+ a.m[3] - b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vint4 operator*(vint4 a, vint4 b)
+{
+ return vint4(a.m[0] * b.m[0],
+ a.m[1] * b.m[1],
+ a.m[2] * b.m[2],
+ a.m[3] * b.m[3]);
+}
+
+/**
+ * @brief Overload: vector bit invert.
+ */
+ASTCENC_SIMD_INLINE vint4 operator~(vint4 a)
+{
+ return vint4(~a.m[0],
+ ~a.m[1],
+ ~a.m[2],
+ ~a.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector bitwise or.
+ */
+ASTCENC_SIMD_INLINE vint4 operator|(vint4 a, vint4 b)
+{
+ return vint4(a.m[0] | b.m[0],
+ a.m[1] | b.m[1],
+ a.m[2] | b.m[2],
+ a.m[3] | b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector bitwise and.
+ */
+ASTCENC_SIMD_INLINE vint4 operator&(vint4 a, vint4 b)
+{
+ return vint4(a.m[0] & b.m[0],
+ a.m[1] & b.m[1],
+ a.m[2] & b.m[2],
+ a.m[3] & b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector bitwise xor.
+ */
+ASTCENC_SIMD_INLINE vint4 operator^(vint4 a, vint4 b)
+{
+ return vint4(a.m[0] ^ b.m[0],
+ a.m[1] ^ b.m[1],
+ a.m[2] ^ b.m[2],
+ a.m[3] ^ b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector equality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator==(vint4 a, vint4 b)
+{
+ return vmask4(a.m[0] == b.m[0],
+ a.m[1] == b.m[1],
+ a.m[2] == b.m[2],
+ a.m[3] == b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector inequality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator!=(vint4 a, vint4 b)
+{
+ return vmask4(a.m[0] != b.m[0],
+ a.m[1] != b.m[1],
+ a.m[2] != b.m[2],
+ a.m[3] != b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector less than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<(vint4 a, vint4 b)
+{
+ return vmask4(a.m[0] < b.m[0],
+ a.m[1] < b.m[1],
+ a.m[2] < b.m[2],
+ a.m[3] < b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector greater than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>(vint4 a, vint4 b)
+{
+ return vmask4(a.m[0] > b.m[0],
+ a.m[1] > b.m[1],
+ a.m[2] > b.m[2],
+ a.m[3] > b.m[3]);
+}
+
+/**
+ * @brief Logical shift left.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 lsl(vint4 a)
+{
+ return vint4(a.m[0] << s,
+ a.m[1] << s,
+ a.m[2] << s,
+ a.m[3] << s);
+}
+
+/**
+ * @brief Logical shift right.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 lsr(vint4 a)
+{
+ unsigned int as0 = static_cast<unsigned int>(a.m[0]) >> s;
+ unsigned int as1 = static_cast<unsigned int>(a.m[1]) >> s;
+ unsigned int as2 = static_cast<unsigned int>(a.m[2]) >> s;
+ unsigned int as3 = static_cast<unsigned int>(a.m[3]) >> s;
+
+ return vint4(static_cast<int>(as0),
+ static_cast<int>(as1),
+ static_cast<int>(as2),
+ static_cast<int>(as3));
+}
+
+/**
+ * @brief Arithmetic shift right.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 asr(vint4 a)
+{
+ return vint4(a.m[0] >> s,
+ a.m[1] >> s,
+ a.m[2] >> s,
+ a.m[3] >> s);
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ */
+ASTCENC_SIMD_INLINE vint4 min(vint4 a, vint4 b)
+{
+ return vint4(a.m[0] < b.m[0] ? a.m[0] : b.m[0],
+ a.m[1] < b.m[1] ? a.m[1] : b.m[1],
+ a.m[2] < b.m[2] ? a.m[2] : b.m[2],
+ a.m[3] < b.m[3] ? a.m[3] : b.m[3]);
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ */
+ASTCENC_SIMD_INLINE vint4 max(vint4 a, vint4 b)
+{
+ return vint4(a.m[0] > b.m[0] ? a.m[0] : b.m[0],
+ a.m[1] > b.m[1] ? a.m[1] : b.m[1],
+ a.m[2] > b.m[2] ? a.m[2] : b.m[2],
+ a.m[3] > b.m[3] ? a.m[3] : b.m[3]);
+}
+
+/**
+ * @brief Return the horizontal minimum of a single vector.
+ */
+ASTCENC_SIMD_INLINE vint4 hmin(vint4 a)
+{
+ int b = std::min(a.m[0], a.m[1]);
+ int c = std::min(a.m[2], a.m[3]);
+ return vint4(std::min(b, c));
+}
+
+/**
+ * @brief Return the horizontal maximum of a single vector.
+ */
+ASTCENC_SIMD_INLINE vint4 hmax(vint4 a)
+{
+ int b = std::max(a.m[0], a.m[1]);
+ int c = std::max(a.m[2], a.m[3]);
+ return vint4(std::max(b, c));
+}
+
+/**
+ * @brief Return the horizontal sum of vector lanes as a scalar.
+ */
+ASTCENC_SIMD_INLINE int hadd_s(vint4 a)
+{
+ return a.m[0] + a.m[1] + a.m[2] + a.m[3];
+}
+
+/**
+ * @brief Store a vector to an aligned memory address.
+ */
+ASTCENC_SIMD_INLINE void storea(vint4 a, int* p)
+{
+ p[0] = a.m[0];
+ p[1] = a.m[1];
+ p[2] = a.m[2];
+ p[3] = a.m[3];
+}
+
+/**
+ * @brief Store a vector to an unaligned memory address.
+ */
+ASTCENC_SIMD_INLINE void store(vint4 a, int* p)
+{
+ p[0] = a.m[0];
+ p[1] = a.m[1];
+ p[2] = a.m[2];
+ p[3] = a.m[3];
+}
+
+/**
+ * @brief Store lowest N (vector width) bytes into an unaligned address.
+ */
+ASTCENC_SIMD_INLINE void store_nbytes(vint4 a, uint8_t* p)
+{
+ int* pi = reinterpret_cast<int*>(p);
+ *pi = a.m[0];
+}
+
+/**
+ * @brief Gather N (vector width) indices from the array.
+ */
+ASTCENC_SIMD_INLINE vint4 gatheri(const int* base, vint4 indices)
+{
+ return vint4(base[indices.m[0]],
+ base[indices.m[1]],
+ base[indices.m[2]],
+ base[indices.m[3]]);
+}
+
+/**
+ * @brief Pack low 8 bits of N (vector width) lanes into bottom of vector.
+ */
+ASTCENC_SIMD_INLINE vint4 pack_low_bytes(vint4 a)
+{
+ int b0 = a.m[0] & 0xFF;
+ int b1 = a.m[1] & 0xFF;
+ int b2 = a.m[2] & 0xFF;
+ int b3 = a.m[3] & 0xFF;
+
+ int b = b0 | (b1 << 8) | (b2 << 16) | (b3 << 24);
+ return vint4(b, 0, 0, 0);
+}
+
+/**
+ * @brief Return lanes from @c b if MSB of @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vint4 select(vint4 a, vint4 b, vmask4 cond)
+{
+ return vint4((cond.m[0] & static_cast<int>(0x80000000)) ? b.m[0] : a.m[0],
+ (cond.m[1] & static_cast<int>(0x80000000)) ? b.m[1] : a.m[1],
+ (cond.m[2] & static_cast<int>(0x80000000)) ? b.m[2] : a.m[2],
+ (cond.m[3] & static_cast<int>(0x80000000)) ? b.m[3] : a.m[3]);
+}
+
+// ============================================================================
+// vfloat4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by vector addition.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator+(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(a.m[0] + b.m[0],
+ a.m[1] + b.m[1],
+ a.m[2] + b.m[2],
+ a.m[3] + b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector subtraction.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator-(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(a.m[0] - b.m[0],
+ a.m[1] - b.m[1],
+ a.m[2] - b.m[2],
+ a.m[3] - b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator*(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(a.m[0] * b.m[0],
+ a.m[1] * b.m[1],
+ a.m[2] * b.m[2],
+ a.m[3] * b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector division.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator/(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(a.m[0] / b.m[0],
+ a.m[1] / b.m[1],
+ a.m[2] / b.m[2],
+ a.m[3] / b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector equality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator==(vfloat4 a, vfloat4 b)
+{
+ return vmask4(a.m[0] == b.m[0],
+ a.m[1] == b.m[1],
+ a.m[2] == b.m[2],
+ a.m[3] == b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector inequality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator!=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(a.m[0] != b.m[0],
+ a.m[1] != b.m[1],
+ a.m[2] != b.m[2],
+ a.m[3] != b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector less than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<(vfloat4 a, vfloat4 b)
+{
+ return vmask4(a.m[0] < b.m[0],
+ a.m[1] < b.m[1],
+ a.m[2] < b.m[2],
+ a.m[3] < b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector greater than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>(vfloat4 a, vfloat4 b)
+{
+ return vmask4(a.m[0] > b.m[0],
+ a.m[1] > b.m[1],
+ a.m[2] > b.m[2],
+ a.m[3] > b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector less than or equal.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(a.m[0] <= b.m[0],
+ a.m[1] <= b.m[1],
+ a.m[2] <= b.m[2],
+ a.m[3] <= b.m[3]);
+}
+
+/**
+ * @brief Overload: vector by vector greater than or equal.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(a.m[0] >= b.m[0],
+ a.m[1] >= b.m[1],
+ a.m[2] >= b.m[2],
+ a.m[3] >= b.m[3]);
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 min(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(a.m[0] < b.m[0] ? a.m[0] : b.m[0],
+ a.m[1] < b.m[1] ? a.m[1] : b.m[1],
+ a.m[2] < b.m[2] ? a.m[2] : b.m[2],
+ a.m[3] < b.m[3] ? a.m[3] : b.m[3]);
+}
+
+/**
+ * @brief Return the max vector of two vectors.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 max(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(a.m[0] > b.m[0] ? a.m[0] : b.m[0],
+ a.m[1] > b.m[1] ? a.m[1] : b.m[1],
+ a.m[2] > b.m[2] ? a.m[2] : b.m[2],
+ a.m[3] > b.m[3] ? a.m[3] : b.m[3]);
+}
+
+/**
+ * @brief Return the absolute value of the float vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 abs(vfloat4 a)
+{
+ return vfloat4(std::abs(a.m[0]),
+ std::abs(a.m[1]),
+ std::abs(a.m[2]),
+ std::abs(a.m[3]));
+}
+
+/**
+ * @brief Return a float rounded to the nearest integer value.
+ */
+ASTCENC_SIMD_INLINE vfloat4 round(vfloat4 a)
+{
+ assert(std::fegetround() == FE_TONEAREST);
+ return vfloat4(std::nearbyint(a.m[0]),
+ std::nearbyint(a.m[1]),
+ std::nearbyint(a.m[2]),
+ std::nearbyint(a.m[3]));
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 hmin(vfloat4 a)
+{
+ float tmp1 = std::min(a.m[0], a.m[1]);
+ float tmp2 = std::min(a.m[2], a.m[3]);
+ return vfloat4(std::min(tmp1, tmp2));
+}
+
+/**
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 hmax(vfloat4 a)
+{
+ float tmp1 = std::max(a.m[0], a.m[1]);
+ float tmp2 = std::max(a.m[2], a.m[3]);
+ return vfloat4(std::max(tmp1, tmp2));
+}
+
+/**
+ * @brief Return the horizontal sum of a vector.
+ */
+ASTCENC_SIMD_INLINE float hadd_s(vfloat4 a)
+{
+ // Use halving add, gives invariance with SIMD versions
+ return (a.m[0] + a.m[2]) + (a.m[1] + a.m[3]);
+}
+
+/**
+ * @brief Return the sqrt of the lanes in the vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 sqrt(vfloat4 a)
+{
+ return vfloat4(std::sqrt(a.m[0]),
+ std::sqrt(a.m[1]),
+ std::sqrt(a.m[2]),
+ std::sqrt(a.m[3]));
+}
+
+/**
+ * @brief Return lanes from @c b if @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vfloat4 select(vfloat4 a, vfloat4 b, vmask4 cond)
+{
+ return vfloat4((cond.m[0] & static_cast<int>(0x80000000)) ? b.m[0] : a.m[0],
+ (cond.m[1] & static_cast<int>(0x80000000)) ? b.m[1] : a.m[1],
+ (cond.m[2] & static_cast<int>(0x80000000)) ? b.m[2] : a.m[2],
+ (cond.m[3] & static_cast<int>(0x80000000)) ? b.m[3] : a.m[3]);
+}
+
+/**
+ * @brief Return lanes from @c b if MSB of @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vfloat4 select_msb(vfloat4 a, vfloat4 b, vmask4 cond)
+{
+ return vfloat4((cond.m[0] & static_cast<int>(0x80000000)) ? b.m[0] : a.m[0],
+ (cond.m[1] & static_cast<int>(0x80000000)) ? b.m[1] : a.m[1],
+ (cond.m[2] & static_cast<int>(0x80000000)) ? b.m[2] : a.m[2],
+ (cond.m[3] & static_cast<int>(0x80000000)) ? b.m[3] : a.m[3]);
+}
+
+/**
+ * @brief Load a vector of gathered results from an array;
+ */
+ASTCENC_SIMD_INLINE vfloat4 gatherf(const float* base, vint4 indices)
+{
+ return vfloat4(base[indices.m[0]],
+ base[indices.m[1]],
+ base[indices.m[2]],
+ base[indices.m[3]]);
+}
+
+/**
+ * @brief Store a vector to an unaligned memory address.
+ */
+ASTCENC_SIMD_INLINE void store(vfloat4 a, float* ptr)
+{
+ ptr[0] = a.m[0];
+ ptr[1] = a.m[1];
+ ptr[2] = a.m[2];
+ ptr[3] = a.m[3];
+}
+
+/**
+ * @brief Store a vector to an aligned memory address.
+ */
+ASTCENC_SIMD_INLINE void storea(vfloat4 a, float* ptr)
+{
+ ptr[0] = a.m[0];
+ ptr[1] = a.m[1];
+ ptr[2] = a.m[2];
+ ptr[3] = a.m[3];
+}
+
+/**
+ * @brief Return a integer value for a float vector, using truncation.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_int(vfloat4 a)
+{
+ return vint4(static_cast<int>(a.m[0]),
+ static_cast<int>(a.m[1]),
+ static_cast<int>(a.m[2]),
+ static_cast<int>(a.m[3]));
+}
+
+/**f
+ * @brief Return a integer value for a float vector, using round-to-nearest.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_int_rtn(vfloat4 a)
+{
+ return vint4(static_cast<int>(a.m[0] + 0.5f),
+ static_cast<int>(a.m[1] + 0.5f),
+ static_cast<int>(a.m[2] + 0.5f),
+ static_cast<int>(a.m[3] + 0.5f));
+}
+
+/**
+ * @brief Return a float value for a integer vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 int_to_float(vint4 a)
+{
+ return vfloat4(static_cast<float>(a.m[0]),
+ static_cast<float>(a.m[1]),
+ static_cast<float>(a.m[2]),
+ static_cast<float>(a.m[3]));
+}
+
+/**
+ * @brief Return a float16 value for a float vector, using round-to-nearest.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_float16(vfloat4 a)
+{
+ return vint4(
+ float_to_sf16(a.lane<0>()),
+ float_to_sf16(a.lane<1>()),
+ float_to_sf16(a.lane<2>()),
+ float_to_sf16(a.lane<3>()));
+}
+
+/**
+ * @brief Return a float16 value for a float scalar, using round-to-nearest.
+ */
+static inline uint16_t float_to_float16(float a)
+{
+ return float_to_sf16(a);
+}
+
+/**
+ * @brief Return a float value for a float16 vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 float16_to_float(vint4 a)
+{
+ return vfloat4(
+ sf16_to_float(static_cast<uint16_t>(a.lane<0>())),
+ sf16_to_float(static_cast<uint16_t>(a.lane<1>())),
+ sf16_to_float(static_cast<uint16_t>(a.lane<2>())),
+ sf16_to_float(static_cast<uint16_t>(a.lane<3>())));
+}
+
+/**
+ * @brief Return a float value for a float16 scalar.
+ */
+ASTCENC_SIMD_INLINE float float16_to_float(uint16_t a)
+{
+ return sf16_to_float(a);
+}
+
+/**
+ * @brief Return a float value as an integer bit pattern (i.e. no conversion).
+ *
+ * It is a common trick to convert floats into integer bit patterns, perform
+ * some bit hackery based on knowledge they are IEEE 754 layout, and then
+ * convert them back again. This is the first half of that flip.
+ */
+ASTCENC_SIMD_INLINE vint4 float_as_int(vfloat4 a)
+{
+ vint4 r;
+ memcpy(r.m, a.m, 4 * 4);
+ return r;
+}
+
+/**
+ * @brief Return a integer value as a float bit pattern (i.e. no conversion).
+ *
+ * It is a common trick to convert floats into integer bit patterns, perform
+ * some bit hackery based on knowledge they are IEEE 754 layout, and then
+ * convert them back again. This is the second half of that flip.
+ */
+ASTCENC_SIMD_INLINE vfloat4 int_as_float(vint4 a)
+{
+ vfloat4 r;
+ memcpy(r.m, a.m, 4 * 4);
+ return r;
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4& t0p)
+{
+ t0p = t0;
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint4& t0p, vint4& t1p)
+{
+ t0p = t0;
+ t1p = t1;
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(
+ vint4 t0, vint4 t1, vint4 t2, vint4 t3,
+ vint4& t0p, vint4& t1p, vint4& t2p, vint4& t3p)
+{
+ t0p = t0;
+ t1p = t1;
+ t2p = t2;
+ t3p = t3;
+}
+
+/**
+ * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx)
+{
+ uint8_t table[16];
+ storea(t0, reinterpret_cast<int*>(table + 0));
+
+ return vint4(table[idx.lane<0>()],
+ table[idx.lane<1>()],
+ table[idx.lane<2>()],
+ table[idx.lane<3>()]);
+}
+
+
+/**
+ * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx)
+{
+ uint8_t table[32];
+ storea(t0, reinterpret_cast<int*>(table + 0));
+ storea(t1, reinterpret_cast<int*>(table + 16));
+
+ return vint4(table[idx.lane<0>()],
+ table[idx.lane<1>()],
+ table[idx.lane<2>()],
+ table[idx.lane<3>()]);
+}
+
+/**
+ * @brief Perform an 8-bit 64-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx)
+{
+ uint8_t table[64];
+ storea(t0, reinterpret_cast<int*>(table + 0));
+ storea(t1, reinterpret_cast<int*>(table + 16));
+ storea(t2, reinterpret_cast<int*>(table + 32));
+ storea(t3, reinterpret_cast<int*>(table + 48));
+
+ return vint4(table[idx.lane<0>()],
+ table[idx.lane<1>()],
+ table[idx.lane<2>()],
+ table[idx.lane<3>()]);
+}
+
+/**
+ * @brief Return a vector of interleaved RGBA data.
+ *
+ * Input vectors have the value stored in the bottom 8 bits of each lane,
+ * with high bits set to zero.
+ *
+ * Output vector stores a single RGBA texel packed in each lane.
+ */
+ASTCENC_SIMD_INLINE vint4 interleave_rgba8(vint4 r, vint4 g, vint4 b, vint4 a)
+{
+ return r + lsl<8>(g) + lsl<16>(b) + lsl<24>(a);
+}
+
+/**
+ * @brief Store a vector, skipping masked lanes.
+ *
+ * All masked lanes must be at the end of vector, after all non-masked lanes.
+ */
+ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask)
+{
+ if (mask.m[3])
+ {
+ store(data, base);
+ }
+ else if (mask.m[2])
+ {
+ base[0] = data.lane<0>();
+ base[1] = data.lane<1>();
+ base[2] = data.lane<2>();
+ }
+ else if (mask.m[1])
+ {
+ base[0] = data.lane<0>();
+ base[1] = data.lane<1>();
+ }
+ else if (mask.m[0])
+ {
+ base[0] = data.lane<0>();
+ }
+}
+
+#endif // #ifndef ASTC_VECMATHLIB_NONE_4_H_INCLUDED
diff --git a/thirdparty/astcenc/astcenc_vecmathlib_sse_4.h b/thirdparty/astcenc/astcenc_vecmathlib_sse_4.h
new file mode 100644
index 0000000000..26dcc4a891
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_vecmathlib_sse_4.h
@@ -0,0 +1,1283 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2019-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief 4x32-bit vectors, implemented using SSE.
+ *
+ * This module implements 4-wide 32-bit float, int, and mask vectors for x86
+ * SSE. The implementation requires at least SSE2, but higher levels of SSE can
+ * be selected at compile time to improve performance.
+ *
+ * There is a baseline level of functionality provided by all vector widths and
+ * implementations. This is implemented using identical function signatures,
+ * modulo data type, so we can use them as substitutable implementations in VLA
+ * code.
+ *
+ * The 4-wide vectors are also used as a fixed-width type, and significantly
+ * extend the functionality above that available to VLA code.
+ */
+
+#ifndef ASTC_VECMATHLIB_SSE_4_H_INCLUDED
+#define ASTC_VECMATHLIB_SSE_4_H_INCLUDED
+
+#ifndef ASTCENC_SIMD_INLINE
+ #error "Include astcenc_vecmathlib.h, do not include directly"
+#endif
+
+#include <cstdio>
+
+// ============================================================================
+// vfloat4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide floats.
+ */
+struct vfloat4
+{
+ /**
+ * @brief Construct from zero-initialized value.
+ */
+ ASTCENC_SIMD_INLINE vfloat4() = default;
+
+ /**
+ * @brief Construct from 4 values loaded from an unaligned address.
+ *
+ * Consider using loada() which is better with vectors if data is aligned
+ * to vector length.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(const float *p)
+ {
+ m = _mm_loadu_ps(p);
+ }
+
+ /**
+ * @brief Construct from 1 scalar value replicated across all lanes.
+ *
+ * Consider using zero() for constexpr zeros.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(float a)
+ {
+ m = _mm_set1_ps(a);
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(float a, float b, float c, float d)
+ {
+ m = _mm_set_ps(d, c, b, a);
+ }
+
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vfloat4(__m128 a)
+ {
+ m = a;
+ }
+
+ /**
+ * @brief Get the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE float lane() const
+ {
+ return _mm_cvtss_f32(_mm_shuffle_ps(m, m, l));
+ }
+
+ /**
+ * @brief Set the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE void set_lane(float a)
+ {
+#if ASTCENC_SSE >= 41
+ __m128 v = _mm_set1_ps(a);
+ m = _mm_insert_ps(m, v, l << 6 | l << 4);
+#else
+ alignas(16) float idx[4];
+ _mm_store_ps(idx, m);
+ idx[l] = a;
+ m = _mm_load_ps(idx);
+#endif
+ }
+
+ /**
+ * @brief Factory that returns a vector of zeros.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 zero()
+ {
+ return vfloat4(_mm_setzero_ps());
+ }
+
+ /**
+ * @brief Factory that returns a replicated scalar loaded from memory.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 load1(const float* p)
+ {
+ return vfloat4(_mm_load_ps1(p));
+ }
+
+ /**
+ * @brief Factory that returns a vector loaded from 16B aligned memory.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 loada(const float* p)
+ {
+ return vfloat4(_mm_load_ps(p));
+ }
+
+ /**
+ * @brief Factory that returns a vector containing the lane IDs.
+ */
+ static ASTCENC_SIMD_INLINE vfloat4 lane_id()
+ {
+ return vfloat4(_mm_set_ps(3, 2, 1, 0));
+ }
+
+ /**
+ * @brief Return a swizzled float 2.
+ */
+ template <int l0, int l1> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ vfloat4 result(_mm_shuffle_ps(m, m, l0 | l1 << 2));
+ result.set_lane<2>(0.0f);
+ result.set_lane<3>(0.0f);
+ return result;
+ }
+
+ /**
+ * @brief Return a swizzled float 3.
+ */
+ template <int l0, int l1, int l2> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ vfloat4 result(_mm_shuffle_ps(m, m, l0 | l1 << 2 | l2 << 4));
+ result.set_lane<3>(0.0f);
+ return result;
+ }
+
+ /**
+ * @brief Return a swizzled float 4.
+ */
+ template <int l0, int l1, int l2, int l3> ASTCENC_SIMD_INLINE vfloat4 swz() const
+ {
+ return vfloat4(_mm_shuffle_ps(m, m, l0 | l1 << 2 | l2 << 4 | l3 << 6));
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ __m128 m;
+};
+
+// ============================================================================
+// vint4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide ints.
+ */
+struct vint4
+{
+ /**
+ * @brief Construct from zero-initialized value.
+ */
+ ASTCENC_SIMD_INLINE vint4() = default;
+
+ /**
+ * @brief Construct from 4 values loaded from an unaligned address.
+ *
+ * Consider using loada() which is better with vectors if data is aligned
+ * to vector length.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(const int *p)
+ {
+ m = _mm_loadu_si128(reinterpret_cast<const __m128i*>(p));
+ }
+
+ /**
+ * @brief Construct from 4 uint8_t loaded from an unaligned address.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(const uint8_t *p)
+ {
+ // _mm_loadu_si32 would be nicer syntax, but missing on older GCC
+ __m128i t = _mm_cvtsi32_si128(*reinterpret_cast<const int*>(p));
+
+#if ASTCENC_SSE >= 41
+ m = _mm_cvtepu8_epi32(t);
+#else
+ t = _mm_unpacklo_epi8(t, _mm_setzero_si128());
+ m = _mm_unpacklo_epi16(t, _mm_setzero_si128());
+#endif
+ }
+
+ /**
+ * @brief Construct from 1 scalar value replicated across all lanes.
+ *
+ * Consider using vfloat4::zero() for constexpr zeros.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(int a)
+ {
+ m = _mm_set1_epi32(a);
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(int a, int b, int c, int d)
+ {
+ m = _mm_set_epi32(d, c, b, a);
+ }
+
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vint4(__m128i a)
+ {
+ m = a;
+ }
+
+ /**
+ * @brief Get the scalar from a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE int lane() const
+ {
+ return _mm_cvtsi128_si32(_mm_shuffle_epi32(m, l));
+ }
+
+ /**
+ * @brief Set the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE void set_lane(int a)
+ {
+#if ASTCENC_SSE >= 41
+ m = _mm_insert_epi32(m, a, l);
+#else
+ alignas(16) int idx[4];
+ _mm_store_si128(reinterpret_cast<__m128i*>(idx), m);
+ idx[l] = a;
+ m = _mm_load_si128(reinterpret_cast<const __m128i*>(idx));
+#endif
+ }
+
+ /**
+ * @brief Factory that returns a vector of zeros.
+ */
+ static ASTCENC_SIMD_INLINE vint4 zero()
+ {
+ return vint4(_mm_setzero_si128());
+ }
+
+ /**
+ * @brief Factory that returns a replicated scalar loaded from memory.
+ */
+ static ASTCENC_SIMD_INLINE vint4 load1(const int* p)
+ {
+ return vint4(*p);
+ }
+
+ /**
+ * @brief Factory that returns a vector loaded from 16B aligned memory.
+ */
+ static ASTCENC_SIMD_INLINE vint4 loada(const int* p)
+ {
+ return vint4(_mm_load_si128(reinterpret_cast<const __m128i*>(p)));
+ }
+
+ /**
+ * @brief Factory that returns a vector containing the lane IDs.
+ */
+ static ASTCENC_SIMD_INLINE vint4 lane_id()
+ {
+ return vint4(_mm_set_epi32(3, 2, 1, 0));
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ __m128i m;
+};
+
+// ============================================================================
+// vmask4 data type
+// ============================================================================
+
+/**
+ * @brief Data type for 4-wide control plane masks.
+ */
+struct vmask4
+{
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(__m128 a)
+ {
+ m = a;
+ }
+
+ /**
+ * @brief Construct from an existing SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(__m128i a)
+ {
+ m = _mm_castsi128_ps(a);
+ }
+
+ /**
+ * @brief Construct from 1 scalar value.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(bool a)
+ {
+ vint4 mask(a == false ? 0 : -1);
+ m = _mm_castsi128_ps(mask.m);
+ }
+
+ /**
+ * @brief Construct from 4 scalar values.
+ *
+ * The value of @c a is stored to lane 0 (LSB) in the SIMD register.
+ */
+ ASTCENC_SIMD_INLINE explicit vmask4(bool a, bool b, bool c, bool d)
+ {
+ vint4 mask(a == false ? 0 : -1,
+ b == false ? 0 : -1,
+ c == false ? 0 : -1,
+ d == false ? 0 : -1);
+
+ m = _mm_castsi128_ps(mask.m);
+ }
+
+ /**
+ * @brief Get the scalar value of a single lane.
+ */
+ template <int l> ASTCENC_SIMD_INLINE float lane() const
+ {
+ return _mm_cvtss_f32(_mm_shuffle_ps(m, m, l));
+ }
+
+ /**
+ * @brief The vector ...
+ */
+ __m128 m;
+};
+
+// ============================================================================
+// vmask4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: mask union (or).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator|(vmask4 a, vmask4 b)
+{
+ return vmask4(_mm_or_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask intersect (and).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator&(vmask4 a, vmask4 b)
+{
+ return vmask4(_mm_and_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask difference (xor).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator^(vmask4 a, vmask4 b)
+{
+ return vmask4(_mm_xor_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: mask invert (not).
+ */
+ASTCENC_SIMD_INLINE vmask4 operator~(vmask4 a)
+{
+ return vmask4(_mm_xor_si128(_mm_castps_si128(a.m), _mm_set1_epi32(-1)));
+}
+
+/**
+ * @brief Return a 4-bit mask code indicating mask status.
+ *
+ * bit0 = lane 0
+ */
+ASTCENC_SIMD_INLINE unsigned int mask(vmask4 a)
+{
+ return static_cast<unsigned int>(_mm_movemask_ps(a.m));
+}
+
+// ============================================================================
+// vint4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by vector addition.
+ */
+ASTCENC_SIMD_INLINE vint4 operator+(vint4 a, vint4 b)
+{
+ return vint4(_mm_add_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector subtraction.
+ */
+ASTCENC_SIMD_INLINE vint4 operator-(vint4 a, vint4 b)
+{
+ return vint4(_mm_sub_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vint4 operator*(vint4 a, vint4 b)
+{
+#if ASTCENC_SSE >= 41
+ return vint4(_mm_mullo_epi32 (a.m, b.m));
+#else
+ __m128i t1 = _mm_mul_epu32(a.m, b.m);
+ __m128i t2 = _mm_mul_epu32(
+ _mm_srli_si128(a.m, 4),
+ _mm_srli_si128(b.m, 4));
+ __m128i r = _mm_unpacklo_epi32(
+ _mm_shuffle_epi32(t1, _MM_SHUFFLE (0, 0, 2, 0)),
+ _mm_shuffle_epi32(t2, _MM_SHUFFLE (0, 0, 2, 0)));
+ return vint4(r);
+#endif
+}
+
+/**
+ * @brief Overload: vector bit invert.
+ */
+ASTCENC_SIMD_INLINE vint4 operator~(vint4 a)
+{
+ return vint4(_mm_xor_si128(a.m, _mm_set1_epi32(-1)));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise or.
+ */
+ASTCENC_SIMD_INLINE vint4 operator|(vint4 a, vint4 b)
+{
+ return vint4(_mm_or_si128(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise and.
+ */
+ASTCENC_SIMD_INLINE vint4 operator&(vint4 a, vint4 b)
+{
+ return vint4(_mm_and_si128(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector bitwise xor.
+ */
+ASTCENC_SIMD_INLINE vint4 operator^(vint4 a, vint4 b)
+{
+ return vint4(_mm_xor_si128(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector equality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator==(vint4 a, vint4 b)
+{
+ return vmask4(_mm_cmpeq_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector inequality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator!=(vint4 a, vint4 b)
+{
+ return ~vmask4(_mm_cmpeq_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector less than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<(vint4 a, vint4 b)
+{
+ return vmask4(_mm_cmplt_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector greater than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>(vint4 a, vint4 b)
+{
+ return vmask4(_mm_cmpgt_epi32(a.m, b.m));
+}
+
+/**
+ * @brief Logical shift left.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 lsl(vint4 a)
+{
+ return vint4(_mm_slli_epi32(a.m, s));
+}
+
+/**
+ * @brief Logical shift right.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 lsr(vint4 a)
+{
+ return vint4(_mm_srli_epi32(a.m, s));
+}
+
+/**
+ * @brief Arithmetic shift right.
+ */
+template <int s> ASTCENC_SIMD_INLINE vint4 asr(vint4 a)
+{
+ return vint4(_mm_srai_epi32(a.m, s));
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ */
+ASTCENC_SIMD_INLINE vint4 min(vint4 a, vint4 b)
+{
+#if ASTCENC_SSE >= 41
+ return vint4(_mm_min_epi32(a.m, b.m));
+#else
+ vmask4 d = a < b;
+ __m128i ap = _mm_and_si128(_mm_castps_si128(d.m), a.m);
+ __m128i bp = _mm_andnot_si128(_mm_castps_si128(d.m), b.m);
+ return vint4(_mm_or_si128(ap,bp));
+#endif
+}
+
+/**
+ * @brief Return the max vector of two vectors.
+ */
+ASTCENC_SIMD_INLINE vint4 max(vint4 a, vint4 b)
+{
+#if ASTCENC_SSE >= 41
+ return vint4(_mm_max_epi32(a.m, b.m));
+#else
+ vmask4 d = a > b;
+ __m128i ap = _mm_and_si128(_mm_castps_si128(d.m), a.m);
+ __m128i bp = _mm_andnot_si128(_mm_castps_si128(d.m), b.m);
+ return vint4(_mm_or_si128(ap,bp));
+#endif
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE vint4 hmin(vint4 a)
+{
+ a = min(a, vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 3, 2))));
+ a = min(a, vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 0, 1))));
+ return vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 0, 0)));
+}
+
+/*
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE vint4 hmax(vint4 a)
+{
+ a = max(a, vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 3, 2))));
+ a = max(a, vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 0, 1))));
+ return vint4(_mm_shuffle_epi32(a.m, _MM_SHUFFLE(0, 0, 0, 0)));
+}
+
+/**
+ * @brief Return the horizontal sum of a vector as a scalar.
+ */
+ASTCENC_SIMD_INLINE int hadd_s(vint4 a)
+{
+ // Add top and bottom halves, lane 1/0
+ __m128i fold = _mm_castps_si128(_mm_movehl_ps(_mm_castsi128_ps(a.m),
+ _mm_castsi128_ps(a.m)));
+ __m128i t = _mm_add_epi32(a.m, fold);
+
+ // Add top and bottom halves, lane 0 (_mm_hadd_ps exists but slow)
+ t = _mm_add_epi32(t, _mm_shuffle_epi32(t, 0x55));
+
+ return _mm_cvtsi128_si32(t);
+}
+
+/**
+ * @brief Store a vector to a 16B aligned memory address.
+ */
+ASTCENC_SIMD_INLINE void storea(vint4 a, int* p)
+{
+ _mm_store_si128(reinterpret_cast<__m128i*>(p), a.m);
+}
+
+/**
+ * @brief Store a vector to an unaligned memory address.
+ */
+ASTCENC_SIMD_INLINE void store(vint4 a, int* p)
+{
+ // Cast due to missing intrinsics
+ _mm_storeu_ps(reinterpret_cast<float*>(p), _mm_castsi128_ps(a.m));
+}
+
+/**
+ * @brief Store lowest N (vector width) bytes into an unaligned address.
+ */
+ASTCENC_SIMD_INLINE void store_nbytes(vint4 a, uint8_t* p)
+{
+ // Cast due to missing intrinsics
+ _mm_store_ss(reinterpret_cast<float*>(p), _mm_castsi128_ps(a.m));
+}
+
+/**
+ * @brief Gather N (vector width) indices from the array.
+ */
+ASTCENC_SIMD_INLINE vint4 gatheri(const int* base, vint4 indices)
+{
+#if ASTCENC_AVX >= 2
+ return vint4(_mm_i32gather_epi32(base, indices.m, 4));
+#else
+ alignas(16) int idx[4];
+ storea(indices, idx);
+ return vint4(base[idx[0]], base[idx[1]], base[idx[2]], base[idx[3]]);
+#endif
+}
+
+/**
+ * @brief Pack low 8 bits of N (vector width) lanes into bottom of vector.
+ */
+ASTCENC_SIMD_INLINE vint4 pack_low_bytes(vint4 a)
+{
+#if ASTCENC_SSE >= 41
+ __m128i shuf = _mm_set_epi8(0,0,0,0, 0,0,0,0, 0,0,0,0, 12,8,4,0);
+ return vint4(_mm_shuffle_epi8(a.m, shuf));
+#else
+ __m128i va = _mm_unpacklo_epi8(a.m, _mm_shuffle_epi32(a.m, _MM_SHUFFLE(1,1,1,1)));
+ __m128i vb = _mm_unpackhi_epi8(a.m, _mm_shuffle_epi32(a.m, _MM_SHUFFLE(3,3,3,3)));
+ return vint4(_mm_unpacklo_epi16(va, vb));
+#endif
+}
+
+/**
+ * @brief Return lanes from @c b if @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vint4 select(vint4 a, vint4 b, vmask4 cond)
+{
+ __m128i condi = _mm_castps_si128(cond.m);
+
+#if ASTCENC_SSE >= 41
+ return vint4(_mm_blendv_epi8(a.m, b.m, condi));
+#else
+ return vint4(_mm_or_si128(_mm_and_si128(condi, b.m), _mm_andnot_si128(condi, a.m)));
+#endif
+}
+
+// ============================================================================
+// vfloat4 operators and functions
+// ============================================================================
+
+/**
+ * @brief Overload: vector by vector addition.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator+(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(_mm_add_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector subtraction.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator-(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(_mm_sub_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector multiplication.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator*(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(_mm_mul_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector division.
+ */
+ASTCENC_SIMD_INLINE vfloat4 operator/(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(_mm_div_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector equality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator==(vfloat4 a, vfloat4 b)
+{
+ return vmask4(_mm_cmpeq_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector inequality.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator!=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(_mm_cmpneq_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector less than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<(vfloat4 a, vfloat4 b)
+{
+ return vmask4(_mm_cmplt_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector greater than.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>(vfloat4 a, vfloat4 b)
+{
+ return vmask4(_mm_cmpgt_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector less than or equal.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator<=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(_mm_cmple_ps(a.m, b.m));
+}
+
+/**
+ * @brief Overload: vector by vector greater than or equal.
+ */
+ASTCENC_SIMD_INLINE vmask4 operator>=(vfloat4 a, vfloat4 b)
+{
+ return vmask4(_mm_cmpge_ps(a.m, b.m));
+}
+
+/**
+ * @brief Return the min vector of two vectors.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 min(vfloat4 a, vfloat4 b)
+{
+ // Do not reorder - second operand will return if either is NaN
+ return vfloat4(_mm_min_ps(a.m, b.m));
+}
+
+/**
+ * @brief Return the max vector of two vectors.
+ *
+ * If either lane value is NaN, @c b will be returned for that lane.
+ */
+ASTCENC_SIMD_INLINE vfloat4 max(vfloat4 a, vfloat4 b)
+{
+ // Do not reorder - second operand will return if either is NaN
+ return vfloat4(_mm_max_ps(a.m, b.m));
+}
+
+/**
+ * @brief Return the absolute value of the float vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 abs(vfloat4 a)
+{
+ return vfloat4(_mm_max_ps(_mm_sub_ps(_mm_setzero_ps(), a.m), a.m));
+}
+
+/**
+ * @brief Return a float rounded to the nearest integer value.
+ */
+ASTCENC_SIMD_INLINE vfloat4 round(vfloat4 a)
+{
+#if ASTCENC_SSE >= 41
+ constexpr int flags = _MM_FROUND_TO_NEAREST_INT | _MM_FROUND_NO_EXC;
+ return vfloat4(_mm_round_ps(a.m, flags));
+#else
+ __m128 v = a.m;
+ __m128 neg_zero = _mm_castsi128_ps(_mm_set1_epi32(static_cast<int>(0x80000000)));
+ __m128 no_fraction = _mm_set1_ps(8388608.0f);
+ __m128 abs_mask = _mm_castsi128_ps(_mm_set1_epi32(0x7FFFFFFF));
+ __m128 sign = _mm_and_ps(v, neg_zero);
+ __m128 s_magic = _mm_or_ps(no_fraction, sign);
+ __m128 r1 = _mm_add_ps(v, s_magic);
+ r1 = _mm_sub_ps(r1, s_magic);
+ __m128 r2 = _mm_and_ps(v, abs_mask);
+ __m128 mask = _mm_cmple_ps(r2, no_fraction);
+ r2 = _mm_andnot_ps(mask, v);
+ r1 = _mm_and_ps(r1, mask);
+ return vfloat4(_mm_xor_ps(r1, r2));
+#endif
+}
+
+/**
+ * @brief Return the horizontal minimum of a vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 hmin(vfloat4 a)
+{
+ a = min(a, vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 3, 2))));
+ a = min(a, vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 0, 1))));
+ return vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 0, 0)));
+}
+
+/**
+ * @brief Return the horizontal maximum of a vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 hmax(vfloat4 a)
+{
+ a = max(a, vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 3, 2))));
+ a = max(a, vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 0, 1))));
+ return vfloat4(_mm_shuffle_ps(a.m, a.m, _MM_SHUFFLE(0, 0, 0, 0)));
+}
+
+/**
+ * @brief Return the horizontal sum of a vector as a scalar.
+ */
+ASTCENC_SIMD_INLINE float hadd_s(vfloat4 a)
+{
+ // Add top and bottom halves, lane 1/0
+ __m128 t = _mm_add_ps(a.m, _mm_movehl_ps(a.m, a.m));
+
+ // Add top and bottom halves, lane 0 (_mm_hadd_ps exists but slow)
+ t = _mm_add_ss(t, _mm_shuffle_ps(t, t, 0x55));
+
+ return _mm_cvtss_f32(t);
+}
+
+/**
+ * @brief Return the sqrt of the lanes in the vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 sqrt(vfloat4 a)
+{
+ return vfloat4(_mm_sqrt_ps(a.m));
+}
+
+/**
+ * @brief Return lanes from @c b if @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vfloat4 select(vfloat4 a, vfloat4 b, vmask4 cond)
+{
+#if ASTCENC_SSE >= 41
+ return vfloat4(_mm_blendv_ps(a.m, b.m, cond.m));
+#else
+ return vfloat4(_mm_or_ps(_mm_and_ps(cond.m, b.m), _mm_andnot_ps(cond.m, a.m)));
+#endif
+}
+
+/**
+ * @brief Return lanes from @c b if MSB of @c cond is set, else @c a.
+ */
+ASTCENC_SIMD_INLINE vfloat4 select_msb(vfloat4 a, vfloat4 b, vmask4 cond)
+{
+#if ASTCENC_SSE >= 41
+ return vfloat4(_mm_blendv_ps(a.m, b.m, cond.m));
+#else
+ __m128 d = _mm_castsi128_ps(_mm_srai_epi32(_mm_castps_si128(cond.m), 31));
+ return vfloat4(_mm_or_ps(_mm_and_ps(d, b.m), _mm_andnot_ps(d, a.m)));
+#endif
+}
+
+/**
+ * @brief Load a vector of gathered results from an array;
+ */
+ASTCENC_SIMD_INLINE vfloat4 gatherf(const float* base, vint4 indices)
+{
+#if ASTCENC_AVX >= 2
+ return vfloat4(_mm_i32gather_ps(base, indices.m, 4));
+#else
+ alignas(16) int idx[4];
+ storea(indices, idx);
+ return vfloat4(base[idx[0]], base[idx[1]], base[idx[2]], base[idx[3]]);
+#endif
+}
+
+/**
+ * @brief Store a vector to an unaligned memory address.
+ */
+ASTCENC_SIMD_INLINE void store(vfloat4 a, float* p)
+{
+ _mm_storeu_ps(p, a.m);
+}
+
+/**
+ * @brief Store a vector to a 16B aligned memory address.
+ */
+ASTCENC_SIMD_INLINE void storea(vfloat4 a, float* p)
+{
+ _mm_store_ps(p, a.m);
+}
+
+/**
+ * @brief Return a integer value for a float vector, using truncation.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_int(vfloat4 a)
+{
+ return vint4(_mm_cvttps_epi32(a.m));
+}
+
+/**
+ * @brief Return a integer value for a float vector, using round-to-nearest.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_int_rtn(vfloat4 a)
+{
+ a = round(a);
+ return vint4(_mm_cvttps_epi32(a.m));
+}
+
+/**
+ * @brief Return a float value for an integer vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 int_to_float(vint4 a)
+{
+ return vfloat4(_mm_cvtepi32_ps(a.m));
+}
+
+/**
+ * @brief Return a float16 value for a float vector, using round-to-nearest.
+ */
+ASTCENC_SIMD_INLINE vint4 float_to_float16(vfloat4 a)
+{
+#if ASTCENC_F16C >= 1
+ __m128i packedf16 = _mm_cvtps_ph(a.m, 0);
+ __m128i f16 = _mm_cvtepu16_epi32(packedf16);
+ return vint4(f16);
+#else
+ return vint4(
+ float_to_sf16(a.lane<0>()),
+ float_to_sf16(a.lane<1>()),
+ float_to_sf16(a.lane<2>()),
+ float_to_sf16(a.lane<3>()));
+#endif
+}
+
+/**
+ * @brief Return a float16 value for a float scalar, using round-to-nearest.
+ */
+static inline uint16_t float_to_float16(float a)
+{
+#if ASTCENC_F16C >= 1
+ __m128i f16 = _mm_cvtps_ph(_mm_set1_ps(a), 0);
+ return static_cast<uint16_t>(_mm_cvtsi128_si32(f16));
+#else
+ return float_to_sf16(a);
+#endif
+}
+
+/**
+ * @brief Return a float value for a float16 vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 float16_to_float(vint4 a)
+{
+#if ASTCENC_F16C >= 1
+ __m128i packed = _mm_packs_epi32(a.m, a.m);
+ __m128 f32 = _mm_cvtph_ps(packed);
+ return vfloat4(f32);
+#else
+ return vfloat4(
+ sf16_to_float(static_cast<uint16_t>(a.lane<0>())),
+ sf16_to_float(static_cast<uint16_t>(a.lane<1>())),
+ sf16_to_float(static_cast<uint16_t>(a.lane<2>())),
+ sf16_to_float(static_cast<uint16_t>(a.lane<3>())));
+#endif
+}
+
+/**
+ * @brief Return a float value for a float16 scalar.
+ */
+ASTCENC_SIMD_INLINE float float16_to_float(uint16_t a)
+{
+#if ASTCENC_F16C >= 1
+ __m128i packed = _mm_set1_epi16(static_cast<short>(a));
+ __m128 f32 = _mm_cvtph_ps(packed);
+ return _mm_cvtss_f32(f32);
+#else
+ return sf16_to_float(a);
+#endif
+}
+
+/**
+ * @brief Return a float value as an integer bit pattern (i.e. no conversion).
+ *
+ * It is a common trick to convert floats into integer bit patterns, perform
+ * some bit hackery based on knowledge they are IEEE 754 layout, and then
+ * convert them back again. This is the first half of that flip.
+ */
+ASTCENC_SIMD_INLINE vint4 float_as_int(vfloat4 a)
+{
+ return vint4(_mm_castps_si128(a.m));
+}
+
+/**
+ * @brief Return a integer value as a float bit pattern (i.e. no conversion).
+ *
+ * It is a common trick to convert floats into integer bit patterns, perform
+ * some bit hackery based on knowledge they are IEEE 754 layout, and then
+ * convert them back again. This is the second half of that flip.
+ */
+ASTCENC_SIMD_INLINE vfloat4 int_as_float(vint4 v)
+{
+ return vfloat4(_mm_castsi128_ps(v.m));
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4& t0p)
+{
+ t0p = t0;
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint4& t0p, vint4& t1p)
+{
+#if ASTCENC_SSE >= 41
+ t0p = t0;
+ t1p = t0 ^ t1;
+#else
+ t0p = t0;
+ t1p = t1;
+#endif
+}
+
+/**
+ * @brief Prepare a vtable lookup table for use with the native SIMD size.
+ */
+ASTCENC_SIMD_INLINE void vtable_prepare(
+ vint4 t0, vint4 t1, vint4 t2, vint4 t3,
+ vint4& t0p, vint4& t1p, vint4& t2p, vint4& t3p)
+{
+#if ASTCENC_SSE >= 41
+ t0p = t0;
+ t1p = t0 ^ t1;
+ t2p = t1 ^ t2;
+ t3p = t2 ^ t3;
+#else
+ t0p = t0;
+ t1p = t1;
+ t2p = t2;
+ t3p = t3;
+#endif
+}
+
+/**
+ * @brief Perform an 8-bit 16-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx)
+{
+#if ASTCENC_SSE >= 41
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+ __m128i result = _mm_shuffle_epi8(t0.m, idxx);
+ return vint4(result);
+#else
+ alignas(ASTCENC_VECALIGN) uint8_t table[16];
+ storea(t0, reinterpret_cast<int*>(table + 0));
+
+ return vint4(table[idx.lane<0>()],
+ table[idx.lane<1>()],
+ table[idx.lane<2>()],
+ table[idx.lane<3>()]);
+#endif
+}
+
+/**
+ * @brief Perform an 8-bit 32-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx)
+{
+#if ASTCENC_SSE >= 41
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+ __m128i result = _mm_shuffle_epi8(t0.m, idxx);
+ idxx = _mm_sub_epi8(idxx, _mm_set1_epi8(16));
+
+ __m128i result2 = _mm_shuffle_epi8(t1.m, idxx);
+ result = _mm_xor_si128(result, result2);
+
+ return vint4(result);
+#else
+ alignas(ASTCENC_VECALIGN) uint8_t table[32];
+ storea(t0, reinterpret_cast<int*>(table + 0));
+ storea(t1, reinterpret_cast<int*>(table + 16));
+
+ return vint4(table[idx.lane<0>()],
+ table[idx.lane<1>()],
+ table[idx.lane<2>()],
+ table[idx.lane<3>()]);
+#endif
+}
+
+/**
+ * @brief Perform an 8-bit 64-entry table lookup, with 32-bit indexes.
+ */
+ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx)
+{
+#if ASTCENC_SSE >= 41
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+ __m128i result = _mm_shuffle_epi8(t0.m, idxx);
+ idxx = _mm_sub_epi8(idxx, _mm_set1_epi8(16));
+
+ __m128i result2 = _mm_shuffle_epi8(t1.m, idxx);
+ result = _mm_xor_si128(result, result2);
+ idxx = _mm_sub_epi8(idxx, _mm_set1_epi8(16));
+
+ result2 = _mm_shuffle_epi8(t2.m, idxx);
+ result = _mm_xor_si128(result, result2);
+ idxx = _mm_sub_epi8(idxx, _mm_set1_epi8(16));
+
+ result2 = _mm_shuffle_epi8(t3.m, idxx);
+ result = _mm_xor_si128(result, result2);
+
+ return vint4(result);
+#else
+ alignas(ASTCENC_VECALIGN) uint8_t table[64];
+ storea(t0, reinterpret_cast<int*>(table + 0));
+ storea(t1, reinterpret_cast<int*>(table + 16));
+ storea(t2, reinterpret_cast<int*>(table + 32));
+ storea(t3, reinterpret_cast<int*>(table + 48));
+
+ return vint4(table[idx.lane<0>()],
+ table[idx.lane<1>()],
+ table[idx.lane<2>()],
+ table[idx.lane<3>()]);
+#endif
+}
+
+/**
+ * @brief Return a vector of interleaved RGBA data.
+ *
+ * Input vectors have the value stored in the bottom 8 bits of each lane,
+ * with high bits set to zero.
+ *
+ * Output vector stores a single RGBA texel packed in each lane.
+ */
+ASTCENC_SIMD_INLINE vint4 interleave_rgba8(vint4 r, vint4 g, vint4 b, vint4 a)
+{
+// Workaround an XCode compiler internal fault; note is slower than slli_epi32
+// so we should revert this when we get the opportunity
+#if defined(__APPLE__)
+ __m128i value = r.m;
+ value = _mm_add_epi32(value, _mm_bslli_si128(g.m, 1));
+ value = _mm_add_epi32(value, _mm_bslli_si128(b.m, 2));
+ value = _mm_add_epi32(value, _mm_bslli_si128(a.m, 3));
+ return vint4(value);
+#else
+ __m128i value = r.m;
+ value = _mm_add_epi32(value, _mm_slli_epi32(g.m, 8));
+ value = _mm_add_epi32(value, _mm_slli_epi32(b.m, 16));
+ value = _mm_add_epi32(value, _mm_slli_epi32(a.m, 24));
+ return vint4(value);
+#endif
+}
+
+/**
+ * @brief Store a vector, skipping masked lanes.
+ *
+ * All masked lanes must be at the end of vector, after all non-masked lanes.
+ */
+ASTCENC_SIMD_INLINE void store_lanes_masked(int* base, vint4 data, vmask4 mask)
+{
+#if ASTCENC_AVX >= 2
+ _mm_maskstore_epi32(base, _mm_castps_si128(mask.m), data.m);
+#else
+ // Note - we cannot use _mm_maskmoveu_si128 as the underlying hardware doesn't guarantee
+ // fault suppression on masked lanes so we can get page faults at the end of an image.
+ if (mask.lane<3>() != 0.0f)
+ {
+ store(data, base);
+ }
+ else if (mask.lane<2>() != 0.0f)
+ {
+ base[0] = data.lane<0>();
+ base[1] = data.lane<1>();
+ base[2] = data.lane<2>();
+ }
+ else if (mask.lane<1>() != 0.0f)
+ {
+ base[0] = data.lane<0>();
+ base[1] = data.lane<1>();
+ }
+ else if (mask.lane<0>() != 0.0f)
+ {
+ base[0] = data.lane<0>();
+ }
+#endif
+}
+
+#if defined(ASTCENC_NO_INVARIANCE) && (ASTCENC_SSE >= 41)
+
+#define ASTCENC_USE_NATIVE_DOT_PRODUCT 1
+
+/**
+ * @brief Return the dot product for the full 4 lanes, returning scalar.
+ */
+ASTCENC_SIMD_INLINE float dot_s(vfloat4 a, vfloat4 b)
+{
+ return _mm_cvtss_f32(_mm_dp_ps(a.m, b.m, 0xFF));
+}
+
+/**
+ * @brief Return the dot product for the full 4 lanes, returning vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 dot(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(_mm_dp_ps(a.m, b.m, 0xFF));
+}
+
+/**
+ * @brief Return the dot product for the bottom 3 lanes, returning scalar.
+ */
+ASTCENC_SIMD_INLINE float dot3_s(vfloat4 a, vfloat4 b)
+{
+ return _mm_cvtss_f32(_mm_dp_ps(a.m, b.m, 0x77));
+}
+
+/**
+ * @brief Return the dot product for the bottom 3 lanes, returning vector.
+ */
+ASTCENC_SIMD_INLINE vfloat4 dot3(vfloat4 a, vfloat4 b)
+{
+ return vfloat4(_mm_dp_ps(a.m, b.m, 0x77));
+}
+
+#endif // #if defined(ASTCENC_NO_INVARIANCE) && (ASTCENC_SSE >= 41)
+
+#if ASTCENC_POPCNT >= 1
+
+#define ASTCENC_USE_NATIVE_POPCOUNT 1
+
+/**
+ * @brief Population bit count.
+ *
+ * @param v The value to population count.
+ *
+ * @return The number of 1 bits.
+ */
+ASTCENC_SIMD_INLINE int popcount(uint64_t v)
+{
+ return static_cast<int>(_mm_popcnt_u64(v));
+}
+
+#endif // ASTCENC_POPCNT >= 1
+
+#endif // #ifndef ASTC_VECMATHLIB_SSE_4_H_INCLUDED
diff --git a/thirdparty/astcenc/astcenc_weight_align.cpp b/thirdparty/astcenc/astcenc_weight_align.cpp
new file mode 100644
index 0000000000..e40a318cf5
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_weight_align.cpp
@@ -0,0 +1,479 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2022 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+#if !defined(ASTCENC_DECOMPRESS_ONLY)
+
+/**
+ * @brief Functions for angular-sum algorithm for weight alignment.
+ *
+ * This algorithm works as follows:
+ * - we compute a complex number P as (cos s*i, sin s*i) for each weight,
+ * where i is the input value and s is a scaling factor based on the spacing between the weights.
+ * - we then add together complex numbers for all the weights.
+ * - we then compute the length and angle of the resulting sum.
+ *
+ * This should produce the following results:
+ * - perfect alignment results in a vector whose length is equal to the sum of lengths of all inputs
+ * - even distribution results in a vector of length 0.
+ * - all samples identical results in perfect alignment for every scaling.
+ *
+ * For each scaling factor within a given set, we compute an alignment factor from 0 to 1. This
+ * should then result in some scalings standing out as having particularly good alignment factors;
+ * we can use this to produce a set of candidate scale/shift values for various quantization levels;
+ * we should then actually try them and see what happens.
+ */
+
+#include "astcenc_internal.h"
+#include "astcenc_vecmathlib.h"
+
+#include <stdio.h>
+#include <cassert>
+#include <cstring>
+
+static constexpr unsigned int ANGULAR_STEPS { 32 };
+
+static_assert((ANGULAR_STEPS % ASTCENC_SIMD_WIDTH) == 0,
+ "ANGULAR_STEPS must be multiple of ASTCENC_SIMD_WIDTH");
+
+static_assert(ANGULAR_STEPS >= 32,
+ "ANGULAR_STEPS must be at least max(steps_for_quant_level)");
+
+// Store a reduced sin/cos table for 64 possible weight values; this causes
+// slight quality loss compared to using sin() and cos() directly. Must be 2^N.
+static constexpr unsigned int SINCOS_STEPS { 64 };
+
+static const uint8_t steps_for_quant_level[12] {
+ 2, 3, 4, 5, 6, 8, 10, 12, 16, 20, 24, 32
+};
+
+alignas(ASTCENC_VECALIGN) static float sin_table[SINCOS_STEPS][ANGULAR_STEPS];
+alignas(ASTCENC_VECALIGN) static float cos_table[SINCOS_STEPS][ANGULAR_STEPS];
+
+#if defined(ASTCENC_DIAGNOSTICS)
+ static bool print_once { true };
+#endif
+
+/* See header for documentation. */
+void prepare_angular_tables()
+{
+ for (unsigned int i = 0; i < ANGULAR_STEPS; i++)
+ {
+ float angle_step = static_cast<float>(i + 1);
+
+ for (unsigned int j = 0; j < SINCOS_STEPS; j++)
+ {
+ sin_table[j][i] = static_cast<float>(sinf((2.0f * astc::PI / (SINCOS_STEPS - 1.0f)) * angle_step * static_cast<float>(j)));
+ cos_table[j][i] = static_cast<float>(cosf((2.0f * astc::PI / (SINCOS_STEPS - 1.0f)) * angle_step * static_cast<float>(j)));
+ }
+ }
+}
+
+/**
+ * @brief Compute the angular alignment factors and offsets.
+ *
+ * @param weight_count The number of (decimated) weights.
+ * @param dec_weight_ideal_value The ideal decimated unquantized weight values.
+ * @param max_angular_steps The maximum number of steps to be tested.
+ * @param[out] offsets The output angular offsets array.
+ */
+static void compute_angular_offsets(
+ unsigned int weight_count,
+ const float* dec_weight_ideal_value,
+ unsigned int max_angular_steps,
+ float* offsets
+) {
+ promise(weight_count > 0);
+ promise(max_angular_steps > 0);
+
+ alignas(ASTCENC_VECALIGN) int isamplev[BLOCK_MAX_WEIGHTS];
+
+ // Precompute isample; arrays are always allocated 64 elements long
+ for (unsigned int i = 0; i < weight_count; i += ASTCENC_SIMD_WIDTH)
+ {
+ // Add 2^23 and interpreting bits extracts round-to-nearest int
+ vfloat sample = loada(dec_weight_ideal_value + i) * (SINCOS_STEPS - 1.0f) + vfloat(12582912.0f);
+ vint isample = float_as_int(sample) & vint((SINCOS_STEPS - 1));
+ storea(isample, isamplev + i);
+ }
+
+ // Arrays are multiple of SIMD width (ANGULAR_STEPS), safe to overshoot max
+ vfloat mult = vfloat(1.0f / (2.0f * astc::PI));
+
+ for (unsigned int i = 0; i < max_angular_steps; i += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat anglesum_x = vfloat::zero();
+ vfloat anglesum_y = vfloat::zero();
+
+ for (unsigned int j = 0; j < weight_count; j++)
+ {
+ int isample = isamplev[j];
+ anglesum_x += loada(cos_table[isample] + i);
+ anglesum_y += loada(sin_table[isample] + i);
+ }
+
+ vfloat angle = atan2(anglesum_y, anglesum_x);
+ vfloat ofs = angle * mult;
+ storea(ofs, offsets + i);
+ }
+}
+
+/**
+ * @brief For a given step size compute the lowest and highest weight.
+ *
+ * Compute the lowest and highest weight that results from quantizing using the given stepsize and
+ * offset, and then compute the resulting error. The cut errors indicate the error that results from
+ * forcing samples that should have had one weight value one step up or down.
+ *
+ * @param weight_count The number of (decimated) weights.
+ * @param dec_weight_ideal_value The ideal decimated unquantized weight values.
+ * @param max_angular_steps The maximum number of steps to be tested.
+ * @param max_quant_steps The maximum quantization level to be tested.
+ * @param offsets The angular offsets array.
+ * @param[out] lowest_weight Per angular step, the lowest weight.
+ * @param[out] weight_span Per angular step, the span between lowest and highest weight.
+ * @param[out] error Per angular step, the error.
+ * @param[out] cut_low_weight_error Per angular step, the low weight cut error.
+ * @param[out] cut_high_weight_error Per angular step, the high weight cut error.
+ */
+static void compute_lowest_and_highest_weight(
+ unsigned int weight_count,
+ const float* dec_weight_ideal_value,
+ unsigned int max_angular_steps,
+ unsigned int max_quant_steps,
+ const float* offsets,
+ float* lowest_weight,
+ int* weight_span,
+ float* error,
+ float* cut_low_weight_error,
+ float* cut_high_weight_error
+) {
+ promise(weight_count > 0);
+ promise(max_angular_steps > 0);
+
+ vfloat rcp_stepsize = vfloat::lane_id() + vfloat(1.0f);
+
+ // Arrays are ANGULAR_STEPS long, so always safe to run full vectors
+ for (unsigned int sp = 0; sp < max_angular_steps; sp += ASTCENC_SIMD_WIDTH)
+ {
+ vfloat minidx(128.0f);
+ vfloat maxidx(-128.0f);
+ vfloat errval = vfloat::zero();
+ vfloat cut_low_weight_err = vfloat::zero();
+ vfloat cut_high_weight_err = vfloat::zero();
+ vfloat offset = loada(offsets + sp);
+
+ for (unsigned int j = 0; j < weight_count; j++)
+ {
+ vfloat sval = load1(dec_weight_ideal_value + j) * rcp_stepsize - offset;
+ vfloat svalrte = round(sval);
+ vfloat diff = sval - svalrte;
+ errval += diff * diff;
+
+ // Reset tracker on min hit
+ vmask mask = svalrte < minidx;
+ minidx = select(minidx, svalrte, mask);
+ cut_low_weight_err = select(cut_low_weight_err, vfloat::zero(), mask);
+
+ // Accumulate on min hit
+ mask = svalrte == minidx;
+ vfloat accum = cut_low_weight_err + vfloat(1.0f) - vfloat(2.0f) * diff;
+ cut_low_weight_err = select(cut_low_weight_err, accum, mask);
+
+ // Reset tracker on max hit
+ mask = svalrte > maxidx;
+ maxidx = select(maxidx, svalrte, mask);
+ cut_high_weight_err = select(cut_high_weight_err, vfloat::zero(), mask);
+
+ // Accumulate on max hit
+ mask = svalrte == maxidx;
+ accum = cut_high_weight_err + vfloat(1.0f) + vfloat(2.0f) * diff;
+ cut_high_weight_err = select(cut_high_weight_err, accum, mask);
+ }
+
+ // Write out min weight and weight span; clamp span to a usable range
+ vint span = float_to_int(maxidx - minidx + vfloat(1));
+ span = min(span, vint(max_quant_steps + 3));
+ span = max(span, vint(2));
+ storea(minidx, lowest_weight + sp);
+ storea(span, weight_span + sp);
+
+ // The cut_(lowest/highest)_weight_error indicate the error that results from forcing
+ // samples that should have had the weight value one step (up/down).
+ vfloat ssize = 1.0f / rcp_stepsize;
+ vfloat errscale = ssize * ssize;
+ storea(errval * errscale, error + sp);
+ storea(cut_low_weight_err * errscale, cut_low_weight_error + sp);
+ storea(cut_high_weight_err * errscale, cut_high_weight_error + sp);
+
+ rcp_stepsize = rcp_stepsize + vfloat(ASTCENC_SIMD_WIDTH);
+ }
+}
+
+/**
+ * @brief The main function for the angular algorithm.
+ *
+ * @param weight_count The number of (decimated) weights.
+ * @param dec_weight_ideal_value The ideal decimated unquantized weight values.
+ * @param max_quant_level The maximum quantization level to be tested.
+ * @param[out] low_value Per angular step, the lowest weight value.
+ * @param[out] high_value Per angular step, the highest weight value.
+ */
+static void compute_angular_endpoints_for_quant_levels(
+ unsigned int weight_count,
+ const float* dec_weight_ideal_value,
+ unsigned int max_quant_level,
+ float low_value[TUNE_MAX_ANGULAR_QUANT + 1],
+ float high_value[TUNE_MAX_ANGULAR_QUANT + 1]
+) {
+ unsigned int max_quant_steps = steps_for_quant_level[max_quant_level];
+ unsigned int max_angular_steps = steps_for_quant_level[max_quant_level];
+
+ alignas(ASTCENC_VECALIGN) float angular_offsets[ANGULAR_STEPS];
+
+ compute_angular_offsets(weight_count, dec_weight_ideal_value,
+ max_angular_steps, angular_offsets);
+
+ alignas(ASTCENC_VECALIGN) float lowest_weight[ANGULAR_STEPS];
+ alignas(ASTCENC_VECALIGN) int32_t weight_span[ANGULAR_STEPS];
+ alignas(ASTCENC_VECALIGN) float error[ANGULAR_STEPS];
+ alignas(ASTCENC_VECALIGN) float cut_low_weight_error[ANGULAR_STEPS];
+ alignas(ASTCENC_VECALIGN) float cut_high_weight_error[ANGULAR_STEPS];
+
+ compute_lowest_and_highest_weight(weight_count, dec_weight_ideal_value,
+ max_angular_steps, max_quant_steps,
+ angular_offsets, lowest_weight, weight_span, error,
+ cut_low_weight_error, cut_high_weight_error);
+
+ // For each quantization level, find the best error terms. Use packed vectors so data-dependent
+ // branches can become selects. This involves some integer to float casts, but the values are
+ // small enough so they never round the wrong way.
+ vfloat4 best_results[36];
+
+ // Initialize the array to some safe defaults
+ promise(max_quant_steps > 0);
+ for (unsigned int i = 0; i < (max_quant_steps + 4); i++)
+ {
+ // Lane<0> = Best error
+ // Lane<1> = Best scale; -1 indicates no solution found
+ // Lane<2> = Cut low weight
+ best_results[i] = vfloat4(ERROR_CALC_DEFAULT, -1.0f, 0.0f, 0.0f);
+ }
+
+ promise(max_angular_steps > 0);
+ for (unsigned int i = 0; i < max_angular_steps; i++)
+ {
+ float i_flt = static_cast<float>(i);
+
+ int idx_span = weight_span[i];
+
+ float error_cut_low = error[i] + cut_low_weight_error[i];
+ float error_cut_high = error[i] + cut_high_weight_error[i];
+ float error_cut_low_high = error[i] + cut_low_weight_error[i] + cut_high_weight_error[i];
+
+ // Check best error against record N
+ vfloat4 best_result = best_results[idx_span];
+ vfloat4 new_result = vfloat4(error[i], i_flt, 0.0f, 0.0f);
+ vmask4 mask = vfloat4(best_result.lane<0>()) > vfloat4(error[i]);
+ best_results[idx_span] = select(best_result, new_result, mask);
+
+ // Check best error against record N-1 with either cut low or cut high
+ best_result = best_results[idx_span - 1];
+
+ new_result = vfloat4(error_cut_low, i_flt, 1.0f, 0.0f);
+ mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_low);
+ best_result = select(best_result, new_result, mask);
+
+ new_result = vfloat4(error_cut_high, i_flt, 0.0f, 0.0f);
+ mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_high);
+ best_results[idx_span - 1] = select(best_result, new_result, mask);
+
+ // Check best error against record N-2 with both cut low and high
+ best_result = best_results[idx_span - 2];
+ new_result = vfloat4(error_cut_low_high, i_flt, 1.0f, 0.0f);
+ mask = vfloat4(best_result.lane<0>()) > vfloat4(error_cut_low_high);
+ best_results[idx_span - 2] = select(best_result, new_result, mask);
+ }
+
+ for (unsigned int i = 0; i <= max_quant_level; i++)
+ {
+ unsigned int q = steps_for_quant_level[i];
+ int bsi = static_cast<int>(best_results[q].lane<1>());
+
+ // Did we find anything?
+#if defined(ASTCENC_DIAGNOSTICS)
+ if ((bsi < 0) && print_once)
+ {
+ print_once = false;
+ printf("INFO: Unable to find full encoding within search error limit.\n\n");
+ }
+#endif
+
+ bsi = astc::max(0, bsi);
+
+ float lwi = lowest_weight[bsi] + best_results[q].lane<2>();
+ float hwi = lwi + static_cast<float>(q) - 1.0f;
+
+ float stepsize = 1.0f / (1.0f + static_cast<float>(bsi));
+ low_value[i] = (angular_offsets[bsi] + lwi) * stepsize;
+ high_value[i] = (angular_offsets[bsi] + hwi) * stepsize;
+ }
+}
+
+/* See header for documentation. */
+void compute_angular_endpoints_1plane(
+ bool only_always,
+ const block_size_descriptor& bsd,
+ const float* dec_weight_ideal_value,
+ unsigned int max_weight_quant,
+ compression_working_buffers& tmpbuf
+) {
+ float (&low_value)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value1;
+ float (&high_value)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value1;
+
+ float (&low_values)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values1;
+ float (&high_values)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values1;
+
+ unsigned int max_decimation_modes = only_always ? bsd.decimation_mode_count_always
+ : bsd.decimation_mode_count_selected;
+ promise(max_decimation_modes > 0);
+ for (unsigned int i = 0; i < max_decimation_modes; i++)
+ {
+ const decimation_mode& dm = bsd.decimation_modes[i];
+ if (!dm.is_ref_1_plane(static_cast<quant_method>(max_weight_quant)))
+ {
+ continue;
+ }
+
+ unsigned int weight_count = bsd.get_decimation_info(i).weight_count;
+
+ unsigned int max_precision = dm.maxprec_1plane;
+ if (max_precision > TUNE_MAX_ANGULAR_QUANT)
+ {
+ max_precision = TUNE_MAX_ANGULAR_QUANT;
+ }
+
+ if (max_precision > max_weight_quant)
+ {
+ max_precision = max_weight_quant;
+ }
+
+ compute_angular_endpoints_for_quant_levels(
+ weight_count,
+ dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS,
+ max_precision, low_values[i], high_values[i]);
+ }
+
+ unsigned int max_block_modes = only_always ? bsd.block_mode_count_1plane_always
+ : bsd.block_mode_count_1plane_selected;
+ promise(max_block_modes > 0);
+ for (unsigned int i = 0; i < max_block_modes; i++)
+ {
+ const block_mode& bm = bsd.block_modes[i];
+ assert(!bm.is_dual_plane);
+
+ unsigned int quant_mode = bm.quant_mode;
+ unsigned int decim_mode = bm.decimation_mode;
+
+ if (quant_mode <= TUNE_MAX_ANGULAR_QUANT)
+ {
+ low_value[i] = low_values[decim_mode][quant_mode];
+ high_value[i] = high_values[decim_mode][quant_mode];
+ }
+ else
+ {
+ low_value[i] = 0.0f;
+ high_value[i] = 1.0f;
+ }
+ }
+}
+
+/* See header for documentation. */
+void compute_angular_endpoints_2planes(
+ const block_size_descriptor& bsd,
+ const float* dec_weight_ideal_value,
+ unsigned int max_weight_quant,
+ compression_working_buffers& tmpbuf
+) {
+ float (&low_value1)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value1;
+ float (&high_value1)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value1;
+ float (&low_value2)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_low_value2;
+ float (&high_value2)[WEIGHTS_MAX_BLOCK_MODES] = tmpbuf.weight_high_value2;
+
+ float (&low_values1)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values1;
+ float (&high_values1)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values1;
+ float (&low_values2)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_low_values2;
+ float (&high_values2)[WEIGHTS_MAX_DECIMATION_MODES][TUNE_MAX_ANGULAR_QUANT + 1] = tmpbuf.weight_high_values2;
+
+ promise(bsd.decimation_mode_count_selected > 0);
+ for (unsigned int i = 0; i < bsd.decimation_mode_count_selected; i++)
+ {
+ const decimation_mode& dm = bsd.decimation_modes[i];
+ if (!dm.is_ref_2_plane(static_cast<quant_method>(max_weight_quant)))
+ {
+ continue;
+ }
+
+ unsigned int weight_count = bsd.get_decimation_info(i).weight_count;
+
+ unsigned int max_precision = dm.maxprec_2planes;
+ if (max_precision > TUNE_MAX_ANGULAR_QUANT)
+ {
+ max_precision = TUNE_MAX_ANGULAR_QUANT;
+ }
+
+ if (max_precision > max_weight_quant)
+ {
+ max_precision = max_weight_quant;
+ }
+
+ compute_angular_endpoints_for_quant_levels(
+ weight_count,
+ dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS,
+ max_precision, low_values1[i], high_values1[i]);
+
+ compute_angular_endpoints_for_quant_levels(
+ weight_count,
+ dec_weight_ideal_value + i * BLOCK_MAX_WEIGHTS + WEIGHTS_PLANE2_OFFSET,
+ max_precision, low_values2[i], high_values2[i]);
+ }
+
+ unsigned int start = bsd.block_mode_count_1plane_selected;
+ unsigned int end = bsd.block_mode_count_1plane_2plane_selected;
+ for (unsigned int i = start; i < end; i++)
+ {
+ const block_mode& bm = bsd.block_modes[i];
+ unsigned int quant_mode = bm.quant_mode;
+ unsigned int decim_mode = bm.decimation_mode;
+
+ if (quant_mode <= TUNE_MAX_ANGULAR_QUANT)
+ {
+ low_value1[i] = low_values1[decim_mode][quant_mode];
+ high_value1[i] = high_values1[decim_mode][quant_mode];
+ low_value2[i] = low_values2[decim_mode][quant_mode];
+ high_value2[i] = high_values2[decim_mode][quant_mode];
+ }
+ else
+ {
+ low_value1[i] = 0.0f;
+ high_value1[i] = 1.0f;
+ low_value2[i] = 0.0f;
+ high_value2[i] = 1.0f;
+ }
+ }
+}
+
+#endif
diff --git a/thirdparty/astcenc/astcenc_weight_quant_xfer_tables.cpp b/thirdparty/astcenc/astcenc_weight_quant_xfer_tables.cpp
new file mode 100644
index 0000000000..8fdf73adc2
--- /dev/null
+++ b/thirdparty/astcenc/astcenc_weight_quant_xfer_tables.cpp
@@ -0,0 +1,147 @@
+// SPDX-License-Identifier: Apache-2.0
+// ----------------------------------------------------------------------------
+// Copyright 2011-2021 Arm Limited
+//
+// 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.
+// ----------------------------------------------------------------------------
+
+/**
+ * @brief Data tables for quantization transfer.
+ */
+
+#include "astcenc_internal.h"
+
+#define _ 0 // Using _ to indicate an entry that will not be used.
+
+const quant_and_transfer_table quant_and_xfer_tables[12] {
+ // QUANT2, range 0..1
+ {
+ {0, 64},
+ {0, 1},
+ {0, 64},
+ {0x4000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,
+ _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,
+ 0x4000}
+ },
+ // QUANT_3, range 0..2
+ {
+ {0, 32, 64},
+ {0, 1, 2},
+ {0, 32, 64},
+ {0x2000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,
+ _,_,0x4000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,
+ _,_,_,_,0x4020}
+ },
+ // QUANT_4, range 0..3
+ {
+ {0, 21, 43, 64},
+ {0, 1, 2, 3},
+ {0, 21, 43, 64},
+ {0x1500,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x2b00,_,_,_,_,
+ _,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x4015,_,_,_,_,_,_,_,_,_,_,_,_,
+ _,_,_,_,_,_,_,_,0x402b}
+ },
+ //QUANT_5, range 0..4
+ {
+ {0, 16, 32, 48, 64},
+ {0, 1, 2, 3, 4},
+ {0, 16, 32, 48, 64},
+ {0x1000,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x2000,_,_,_,_,_,_,_,_,_,
+ _,_,_,_,_,_,0x3010,_,_,_,_,_,_,_,_,_,_,_,_,_,_,_,0x4020,_,_,_,
+ _,_,_,_,_,_,_,_,_,_,_,_,0x4030}
+ },
+ // QUANT_6, range 0..5
+ {
+ {0, 12, 25, 39, 52, 64},
+ {0, 2, 4, 5, 3, 1},
+ {0, 64, 12, 52, 25, 39},
+ {0x0c00,_,_,_,_,_,_,_,_,_,_,_,0x1900,_,_,_,_,_,_,_,_,_,_,_,_,
+ 0x270c,_,_,_,_,_,_,_,_,_,_,_,_,_,0x3419,_,_,_,_,_,_,_,_,_,_,
+ _,_,0x4027,_,_,_,_,_,_,_,_,_,_,_,0x4034}
+ },
+ // QUANT_8, range 0..7
+ {
+ {0, 9, 18, 27, 37, 46, 55, 64},
+ {0, 1, 2, 3, 4, 5, 6, 7},
+ {0, 9, 18, 27, 37, 46, 55, 64},
+ {0x0900,_,_,_,_,_,_,_,_,0x1200,_,_,_,_,_,_,_,_,0x1b09,_,_,
+ _,_,_,_,_,_,0x2512,_,_,_,_,_,_,_,_,_,0x2e1b,_,_,_,_,_,_,_,_,
+ 0x3725,_,_,_,_,_,_,_,_,0x402e,_,_,_,_,_,_,_,_,0x4037}
+ },
+ // QUANT_10, range 0..9
+ {
+ {0, 7, 14, 21, 28, 36, 43, 50, 57, 64},
+ {0, 2, 4, 6, 8, 9, 7, 5, 3, 1},
+ {0, 64, 7, 57, 14, 50, 21, 43, 28, 36},
+ {0x0700,_,_,_,_,_,_,0x0e00,_,_,_,_,_,_,0x1507,_,_,_,_,_,_,
+ 0x1c0e,_,_,_,_,_,_,0x2415,_,_,_,_,_,_,_,0x2b1c,_,_,_,_,_,
+ _,0x3224,_,_,_,_,_,_,0x392b,_,_,_,_,_,_,0x4032,_,_,_,_,_,
+ _,0x4039}
+ },
+ // QUANT_12, range 0..11
+ {
+ {0, 5, 11, 17, 23, 28, 36, 41, 47, 53, 59, 64},
+ {0, 4, 8, 2, 6, 10, 11, 7, 3, 9, 5, 1},
+ {0, 64, 17, 47, 5, 59, 23, 41, 11, 53, 28, 36},
+ {0x0500,_,_,_,_,0x0b00,_,_,_,_,_,0x1105,_,_,_,_,_,
+ 0x170b,_,_,_,_,_,0x1c11,_,_,_,_,0x2417,_,_,_,_,_,_,_,
+ 0x291c,_,_,_,_,0x2f24,_,_,_,_,_,0x3529,_,_,_,_,_,
+ 0x3b2f,_,_,_,_,_,0x4035,_,_,_,_,0x403b}
+ },
+ // QUANT_16, range 0..15
+ {
+ {0, 4, 8, 12, 17, 21, 25, 29, 35, 39, 43, 47, 52, 56, 60, 64},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15},
+ {0, 4, 8, 12, 17, 21, 25, 29, 35, 39, 43, 47, 52, 56, 60, 64},
+ {0x0400,_,_,_,0x0800,_,_,_,0x0c04,_,_,_,0x1108,_,_,_,_,
+ 0x150c,_,_,_,0x1911,_,_,_,0x1d15,_,_,_,0x2319,_,_,_,_,
+ _,0x271d,_,_,_,0x2b23,_,_,_,0x2f27,_,_,_,0x342b,_,_,_,
+ _,0x382f,_,_,_,0x3c34,_,_,_,0x4038,_,_,_,0x403c}
+ },
+ // QUANT_20, range 0..19
+ {
+ {0, 3, 6, 9, 13, 16, 19, 23, 26, 29, 35, 38, 41, 45, 48, 51, 55, 58, 61, 64},
+ {0, 4, 8, 12, 16, 2, 6, 10, 14, 18, 19, 15, 11, 7, 3, 17, 13, 9, 5, 1},
+ {0, 64, 16, 48, 3, 61, 19, 45, 6, 58, 23, 41, 9, 55, 26, 38, 13, 51, 29, 35},
+ {0x0300,_,_,0x0600,_,_,0x0903,_,_,0x0d06,_,_,_,
+ 0x1009,_,_,0x130d,_,_,0x1710,_,_,_,0x1a13,_,_,
+ 0x1d17,_,_,0x231a,_,_,_,_,_,0x261d,_,_,0x2923,_,_,
+ 0x2d26,_,_,_,0x3029,_,_,0x332d,_,_,0x3730,_,_,_,
+ 0x3a33,_,_,0x3d37,_,_,0x403a,_,_,0x403d}
+ },
+ // QUANT_24, range 0..23
+ {
+ {0, 2, 5, 8, 11, 13, 16, 19, 22, 24, 27, 30, 34, 37, 40, 42, 45, 48, 51, 53, 56, 59, 62, 64},
+ {0, 8, 16, 2, 10, 18, 4, 12, 20, 6, 14, 22, 23, 15, 7, 21, 13, 5, 19, 11, 3, 17, 9, 1},
+ {0, 64, 8, 56, 16, 48, 24, 40, 2, 62, 11, 53, 19, 45, 27, 37, 5, 59, 13, 51, 22, 42, 30, 34},
+ {0x0200,_,0x0500,_,_,0x0802,_,_,0x0b05,_,_,0x0d08,
+ _,0x100b,_,_,0x130d,_,_,0x1610,_,_,0x1813,_,
+ 0x1b16,_,_,0x1e18,_,_,0x221b,_,_,_,0x251e,_,_,
+ 0x2822,_,_,0x2a25,_,0x2d28,_,_,0x302a,_,_,0x332d,
+ _,_,0x3530,_,0x3833,_,_,0x3b35,_,_,0x3e38,_,_,
+ 0x403b,_,0x403e}
+ },
+ // QUANT_32, range 0..31
+ {
+ {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64},
+ {0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31},
+ {0, 2, 4, 6, 8, 10, 12, 14, 16, 18, 20, 22, 24, 26, 28, 30, 34, 36, 38, 40, 42, 44, 46, 48, 50, 52, 54, 56, 58, 60, 62, 64},
+ {0x0200,_,0x0400,_,0x0602,_,0x0804,_,0x0a06,_,
+ 0x0c08,_,0x0e0a,_,0x100c,_,0x120e,_,0x1410,_,
+ 0x1612,_,0x1814,_,0x1a16,_,0x1c18,_,0x1e1a,_,
+ 0x221c,_,_,_,0x241e,_,0x2622,_,0x2824,_,0x2a26,_,
+ 0x2c28,_,0x2e2a,_,0x302c,_,0x322e,_,0x3430,_,
+ 0x3632,_,0x3834,_,0x3a36,_,0x3c38,_,0x3e3a,_,
+ 0x403c,_,0x403e}
+ }
+};
diff --git a/thirdparty/astcenc/patches/fix-build-no-ssse3.patch b/thirdparty/astcenc/patches/fix-build-no-ssse3.patch
new file mode 100644
index 0000000000..9da4f3e1f3
--- /dev/null
+++ b/thirdparty/astcenc/patches/fix-build-no-ssse3.patch
@@ -0,0 +1,81 @@
+From 02c22d3df501dc284ba732fa82a6c408c57b3237 Mon Sep 17 00:00:00 2001
+From: =?UTF-8?q?R=C3=A9mi=20Verschelde?= <rverschelde@gmail.com>
+Date: Thu, 19 Jan 2023 23:30:13 +0100
+Subject: [PATCH] mathlib: Remove incomplete support for SSE3 which assumed
+ SSSE3
+
+`_mm_shuffle_epi8` requires SSSE3 so the check on `ASTCENC_SSE >= 30` is
+too lax and would fail if `__SSE3__` is supported, but not `__SSSE3__`.
+
+The only supported configurations are SSE2, SSE4.1, and AVX2, so as
+discussed in #393 we drop the SSE3 checks and require SSE4.1 instead.
+---
+ Source/astcenc_mathlib.h | 2 --
+ Source/astcenc_vecmathlib_sse_4.h | 10 +++++-----
+ 2 files changed, 5 insertions(+), 7 deletions(-)
+
+diff --git a/Source/astcenc_mathlib.h b/Source/astcenc_mathlib.h
+index 67e989e..0540c4f 100644
+--- a/Source/astcenc_mathlib.h
++++ b/Source/astcenc_mathlib.h
+@@ -48,8 +48,6 @@
+ #define ASTCENC_SSE 42
+ #elif defined(__SSE4_1__)
+ #define ASTCENC_SSE 41
+- #elif defined(__SSE3__)
+- #define ASTCENC_SSE 30
+ #elif defined(__SSE2__)
+ #define ASTCENC_SSE 20
+ #else
+diff --git a/Source/astcenc_vecmathlib_sse_4.h b/Source/astcenc_vecmathlib_sse_4.h
+index 76fe577..26dcc4a 100644
+--- a/Source/astcenc_vecmathlib_sse_4.h
++++ b/Source/astcenc_vecmathlib_sse_4.h
+@@ -1046,7 +1046,7 @@ ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4& t0p)
+ */
+ ASTCENC_SIMD_INLINE void vtable_prepare(vint4 t0, vint4 t1, vint4& t0p, vint4& t1p)
+ {
+-#if ASTCENC_SSE >= 30
++#if ASTCENC_SSE >= 41
+ t0p = t0;
+ t1p = t0 ^ t1;
+ #else
+@@ -1062,7 +1062,7 @@ ASTCENC_SIMD_INLINE void vtable_prepare(
+ vint4 t0, vint4 t1, vint4 t2, vint4 t3,
+ vint4& t0p, vint4& t1p, vint4& t2p, vint4& t3p)
+ {
+-#if ASTCENC_SSE >= 30
++#if ASTCENC_SSE >= 41
+ t0p = t0;
+ t1p = t0 ^ t1;
+ t2p = t1 ^ t2;
+@@ -1080,7 +1080,7 @@ ASTCENC_SIMD_INLINE void vtable_prepare(
+ */
+ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx)
+ {
+-#if ASTCENC_SSE >= 30
++#if ASTCENC_SSE >= 41
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+@@ -1102,7 +1102,7 @@ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 idx)
+ */
+ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx)
+ {
+-#if ASTCENC_SSE >= 30
++#if ASTCENC_SSE >= 41
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+@@ -1130,7 +1130,7 @@ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 idx)
+ */
+ ASTCENC_SIMD_INLINE vint4 vtable_8bt_32bi(vint4 t0, vint4 t1, vint4 t2, vint4 t3, vint4 idx)
+ {
+-#if ASTCENC_SSE >= 30
++#if ASTCENC_SSE >= 41
+ // Set index byte MSB to 1 for unused bytes so shuffle returns zero
+ __m128i idxx = _mm_or_si128(idx.m, _mm_set1_epi32(static_cast<int>(0xFFFFFF00)));
+
+--
+2.39.1
+