summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.editorconfig10
-rw-r--r--COPYRIGHT.txt5
-rw-r--r--SConstruct2
-rw-r--r--core/config/project_settings.cpp2
-rw-r--r--core/crypto/crypto_core.cpp2
-rw-r--r--core/crypto/hashing_context.cpp6
-rw-r--r--core/debugger/remote_debugger.cpp4
-rw-r--r--core/extension/gdextension.cpp23
-rw-r--r--core/extension/gdextension_interface.cpp168
-rw-r--r--core/extension/gdextension_interface.h92
-rw-r--r--core/input/input.cpp31
-rw-r--r--core/input/input.h1
-rw-r--r--core/io/compression.cpp2
-rw-r--r--core/io/file_access_memory.cpp16
-rw-r--r--core/io/file_access_zip.cpp4
-rw-r--r--core/io/image.cpp17
-rw-r--r--core/io/ip.cpp2
-rw-r--r--core/io/marshalls.cpp4
-rw-r--r--core/io/packed_data_container.cpp6
-rw-r--r--core/io/resource_loader.cpp2
-rw-r--r--core/io/resource_saver.cpp2
-rw-r--r--core/io/stream_peer_gzip.cpp4
-rw-r--r--core/io/xml_parser.cpp4
-rw-r--r--core/io/zip_io.cpp14
-rw-r--r--core/math/a_star_grid_2d.cpp76
-rw-r--r--core/math/a_star_grid_2d.h19
-rw-r--r--core/math/disjoint_set.h2
-rw-r--r--core/math/dynamic_bvh.h2
-rw-r--r--core/math/projection.cpp1
-rw-r--r--core/object/class_db.cpp65
-rw-r--r--core/object/class_db.h29
-rw-r--r--core/object/make_virtuals.py27
-rw-r--r--core/object/object.cpp29
-rw-r--r--core/object/object.h4
-rw-r--r--core/object/ref_counted.h2
-rw-r--r--core/object/script_language_extension.h4
-rw-r--r--core/object/undo_redo.cpp8
-rw-r--r--core/object/worker_thread_pool.cpp4
-rw-r--r--core/os/memory.cpp6
-rw-r--r--core/os/memory.h2
-rw-r--r--core/os/pool_allocator.cpp14
-rw-r--r--core/string/node_path.cpp8
-rw-r--r--core/string/print_string.cpp2
-rw-r--r--core/string/string_name.cpp4
-rw-r--r--core/templates/command_queue_mt.h2
-rw-r--r--core/templates/cowdata.h13
-rw-r--r--core/templates/list.h2
-rw-r--r--core/templates/paged_array.h6
-rw-r--r--core/templates/rid_owner.h6
-rw-r--r--core/typedefs.h2
-rw-r--r--core/variant/array.cpp2
-rw-r--r--core/variant/callable.cpp8
-rw-r--r--core/variant/container_type_validate.h2
-rw-r--r--core/variant/dictionary.cpp2
-rw-r--r--core/variant/method_ptrcall.h44
-rw-r--r--core/variant/typed_array.h3
-rw-r--r--core/variant/variant_call.cpp30
-rw-r--r--core/variant/variant_op.h4
-rw-r--r--core/variant/variant_setget.cpp6
-rw-r--r--core/variant/variant_utility.cpp87
-rw-r--r--doc/classes/@GlobalScope.xml24
-rw-r--r--doc/classes/AABB.xml2
-rw-r--r--doc/classes/AudioServer.xml10
-rw-r--r--doc/classes/CanvasTexture.xml1
-rw-r--r--doc/classes/CodeEdit.xml52
-rw-r--r--doc/classes/DisplayServer.xml12
-rw-r--r--doc/classes/EditorDebuggerPlugin.xml2
-rw-r--r--doc/classes/EditorInterface.xml7
-rw-r--r--doc/classes/EditorPlugin.xml6
-rw-r--r--doc/classes/EditorSettings.xml3
-rw-r--r--doc/classes/Image.xml9
-rw-r--r--doc/classes/ItemList.xml6
-rw-r--r--doc/classes/Joint2D.xml8
-rw-r--r--doc/classes/Joint3D.xml8
-rw-r--r--doc/classes/LightmapGI.xml3
-rw-r--r--doc/classes/Line2D.xml13
-rw-r--r--doc/classes/Node.xml13
-rw-r--r--doc/classes/PhysicsServer3DRenderingServerHandler.xml32
-rw-r--r--doc/classes/PopupMenu.xml10
-rw-r--r--doc/classes/ProjectSettings.xml21
-rw-r--r--doc/classes/RDShaderSPIRV.xml2
-rw-r--r--doc/classes/ScrollContainer.xml8
-rw-r--r--doc/classes/SurfaceTool.xml2
-rw-r--r--doc/classes/TileSetAtlasSource.xml15
-rw-r--r--doc/classes/Vector2i.xml6
-rw-r--r--doc/classes/Vector3i.xml6
-rw-r--r--doc/classes/Vector4i.xml6
-rw-r--r--doc/classes/XRInterface.xml3
-rw-r--r--drivers/SCsub1
-rw-r--r--drivers/coreaudio/audio_driver_coreaudio.cpp4
-rw-r--r--drivers/egl/SCsub6
-rw-r--r--drivers/egl/egl_manager.cpp404
-rw-r--r--drivers/egl/egl_manager.h118
-rw-r--r--drivers/gl_context/SCsub10
-rw-r--r--drivers/gles3/environment/gi.h7
-rw-r--r--drivers/gles3/rasterizer_canvas_gles3.cpp21
-rw-r--r--drivers/gles3/rasterizer_gles3.cpp146
-rw-r--r--drivers/gles3/rasterizer_gles3.h8
-rw-r--r--drivers/gles3/rasterizer_scene_gles3.cpp119
-rw-r--r--drivers/gles3/shader_gles3.cpp41
-rw-r--r--drivers/gles3/shader_gles3.h14
-rw-r--r--drivers/gles3/shaders/canvas.glsl6
-rw-r--r--drivers/gles3/storage/config.cpp42
-rw-r--r--drivers/gles3/storage/config.h10
-rw-r--r--drivers/gles3/storage/light_storage.cpp48
-rw-r--r--drivers/gles3/storage/light_storage.h27
-rw-r--r--drivers/gles3/storage/material_storage.cpp41
-rw-r--r--drivers/gles3/storage/mesh_storage.cpp90
-rw-r--r--drivers/gles3/storage/mesh_storage.h17
-rw-r--r--drivers/gles3/storage/particles_storage.cpp100
-rw-r--r--drivers/gles3/storage/particles_storage.h17
-rw-r--r--drivers/gles3/storage/render_scene_buffers_gles3.h7
-rw-r--r--drivers/gles3/storage/texture_storage.cpp347
-rw-r--r--drivers/gles3/storage/texture_storage.h16
-rw-r--r--drivers/gles3/storage/utilities.cpp24
-rw-r--r--drivers/gles3/storage/utilities.h7
-rw-r--r--drivers/pulseaudio/audio_driver_pulseaudio.cpp6
-rw-r--r--drivers/unix/file_access_unix.cpp20
-rw-r--r--drivers/unix/os_unix.cpp4
-rw-r--r--drivers/vulkan/rendering_device_vulkan.cpp147
-rw-r--r--drivers/vulkan/vulkan_context.cpp24
-rw-r--r--drivers/vulkan/vulkan_context.h2
-rw-r--r--drivers/windows/file_access_windows.cpp18
-rw-r--r--editor/animation_track_editor.cpp46
-rw-r--r--editor/connections_dialog.cpp48
-rw-r--r--editor/create_dialog.cpp13
-rw-r--r--editor/create_dialog.h2
-rw-r--r--editor/debugger/editor_debugger_node.cpp20
-rw-r--r--editor/debugger/editor_debugger_tree.cpp2
-rw-r--r--editor/debugger/editor_performance_profiler.cpp2
-rw-r--r--editor/editor_audio_buses.cpp51
-rw-r--r--editor/editor_audio_buses.h7
-rw-r--r--editor/editor_autoload_settings.cpp6
-rw-r--r--editor/editor_command_palette.cpp10
-rw-r--r--editor/editor_command_palette.h1
-rw-r--r--editor/editor_data.cpp4
-rw-r--r--editor/editor_inspector.cpp9
-rw-r--r--editor/editor_interface.cpp8
-rw-r--r--editor/editor_interface.h6
-rw-r--r--editor/editor_node.cpp39
-rw-r--r--editor/editor_node.h1
-rw-r--r--editor/editor_paths.cpp2
-rw-r--r--editor/editor_plugin_settings.cpp2
-rw-r--r--editor/editor_properties.cpp4
-rw-r--r--editor/editor_properties_array_dict.cpp2
-rw-r--r--editor/editor_settings.cpp5
-rw-r--r--editor/editor_settings_dialog.cpp6
-rw-r--r--editor/editor_themes.cpp110
-rw-r--r--editor/editor_themes.h16
-rw-r--r--editor/export/editor_export_platform.cpp20
-rw-r--r--editor/export/project_export.cpp8
-rw-r--r--editor/filesystem_dock.cpp112
-rw-r--r--editor/filesystem_dock.h8
-rw-r--r--editor/find_in_files.cpp4
-rw-r--r--editor/gui/editor_run_bar.cpp2
-rw-r--r--editor/gui/editor_spin_slider.cpp2
-rw-r--r--editor/gui/editor_toaster.cpp2
-rw-r--r--editor/gui/scene_tree_editor.cpp20
-rw-r--r--editor/icons/AABB.svg2
-rw-r--r--editor/icons/Array.svg2
-rw-r--r--editor/icons/Basis.svg2
-rw-r--r--editor/icons/CanvasTexture.svg1
-rw-r--r--editor/icons/CheckBox.svg2
-rw-r--r--editor/icons/CodeRegionFoldDownArrow.svg1
-rw-r--r--editor/icons/CodeRegionFoldedRightArrow.svg1
-rw-r--r--editor/icons/Color.svg2
-rw-r--r--editor/icons/CurveTexture.svg2
-rw-r--r--editor/icons/Dictionary.svg2
-rw-r--r--editor/icons/GizmoCPUParticles3D.svg2
-rw-r--r--editor/icons/GizmoDecal.svg1
-rw-r--r--editor/icons/GizmoFogVolume.svg1
-rw-r--r--editor/icons/GizmoLightmapProbe.svg1
-rw-r--r--editor/icons/GraphEdit.svg2
-rw-r--r--editor/icons/GraphElement.svg2
-rw-r--r--editor/icons/GraphNode.svg2
-rw-r--r--editor/icons/GuiToggleOnDisabledMirrored.svg (renamed from editor/icons/GuiToggleOnMirroredDisabled.svg)0
-rw-r--r--editor/icons/IOSDeviceWired.svg2
-rw-r--r--editor/icons/IOSDeviceWireless.svg2
-rw-r--r--editor/icons/IOSSimulator.svg2
-rw-r--r--editor/icons/KeyPosition.svg2
-rw-r--r--editor/icons/KeyRotation.svg2
-rw-r--r--editor/icons/KeyScale.svg2
-rw-r--r--editor/icons/MiniObject.svg2
-rw-r--r--editor/icons/Nil.svg2
-rw-r--r--editor/icons/NodePath.svg2
-rw-r--r--editor/icons/PackedByteArray.svg2
-rw-r--r--editor/icons/PackedColorArray.svg2
-rw-r--r--editor/icons/PackedFloat32Array.svg2
-rw-r--r--editor/icons/PackedFloat64Array.svg2
-rw-r--r--editor/icons/PackedInt32Array.svg2
-rw-r--r--editor/icons/PackedInt64Array.svg2
-rw-r--r--editor/icons/PackedStringArray.svg2
-rw-r--r--editor/icons/PackedVector2Array.svg2
-rw-r--r--editor/icons/PackedVector3Array.svg2
-rw-r--r--editor/icons/Paint.svg1
-rw-r--r--editor/icons/Plane.svg2
-rw-r--r--editor/icons/Projection.svg2
-rw-r--r--editor/icons/Quaternion.svg2
-rw-r--r--editor/icons/RID.svg2
-rw-r--r--editor/icons/Rect2.svg2
-rw-r--r--editor/icons/Rect2i.svg2
-rw-r--r--editor/icons/String.svg2
-rw-r--r--editor/icons/StringName.svg2
-rw-r--r--editor/icons/TorusMesh.svg2
-rw-r--r--editor/icons/Transform2D.svg2
-rw-r--r--editor/icons/Transform3D.svg2
-rw-r--r--editor/icons/Uv.svg2
-rw-r--r--editor/icons/Variant.svg2
-rw-r--r--editor/icons/Vector2.svg2
-rw-r--r--editor/icons/Vector2i.svg2
-rw-r--r--editor/icons/Vector3.svg2
-rw-r--r--editor/icons/Vector3i.svg2
-rw-r--r--editor/icons/Vector4.svg2
-rw-r--r--editor/icons/Vector4i.svg2
-rw-r--r--editor/icons/bool.svg2
-rw-r--r--editor/icons/float.svg2
-rw-r--r--editor/icons/uint.svg2
-rw-r--r--editor/import/collada.cpp2
-rw-r--r--editor/import/editor_import_collada.cpp6
-rw-r--r--editor/import/resource_importer_scene.cpp10
-rw-r--r--editor/import_dock.cpp2
-rw-r--r--editor/inspector_dock.cpp4
-rw-r--r--editor/localization_editor.cpp18
-rw-r--r--editor/plugins/abstract_polygon_2d_editor.cpp3
-rw-r--r--editor/plugins/animation_blend_space_1d_editor.cpp4
-rw-r--r--editor/plugins/animation_blend_space_2d_editor.cpp4
-rw-r--r--editor/plugins/animation_blend_tree_editor_plugin.cpp12
-rw-r--r--editor/plugins/animation_library_editor.cpp2
-rw-r--r--editor/plugins/animation_player_editor_plugin.cpp6
-rw-r--r--editor/plugins/animation_state_machine_editor.cpp8
-rw-r--r--editor/plugins/asset_library_editor_plugin.cpp2
-rw-r--r--editor/plugins/canvas_item_editor_plugin.cpp199
-rw-r--r--editor/plugins/canvas_item_editor_plugin.h11
-rw-r--r--editor/plugins/control_editor_plugin.cpp7
-rw-r--r--editor/plugins/cpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/curve_editor_plugin.cpp6
-rw-r--r--editor/plugins/editor_debugger_plugin.cpp12
-rw-r--r--editor/plugins/font_config_plugin.cpp2
-rw-r--r--editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp4
-rw-r--r--editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp233
-rw-r--r--editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp3
-rw-r--r--editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp79
-rw-r--r--editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h6
-rw-r--r--editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp4
-rw-r--r--editor/plugins/gizmos/decal_gizmo_plugin.cpp78
-rw-r--r--editor/plugins/gizmos/decal_gizmo_plugin.h6
-rw-r--r--editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp6
-rw-r--r--editor/plugins/gizmos/gizmo_3d_helper.cpp131
-rw-r--r--editor/plugins/gizmos/gizmo_3d_helper.h55
-rw-r--r--editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp67
-rw-r--r--editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp61
-rw-r--r--editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h6
-rw-r--r--editor/plugins/gizmos/light_3d_gizmo_plugin.cpp198
-rw-r--r--editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp10
-rw-r--r--editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp7
-rw-r--r--editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp6
-rw-r--r--editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp157
-rw-r--r--editor/plugins/gizmos/reflection_probe_gizmo_plugin.h6
-rw-r--r--editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp170
-rw-r--r--editor/plugins/gizmos/voxel_gi_gizmo_plugin.h6
-rw-r--r--editor/plugins/gpu_particles_2d_editor_plugin.cpp2
-rw-r--r--editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp7
-rw-r--r--editor/plugins/gradient_editor.cpp2
-rw-r--r--editor/plugins/gradient_texture_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/lightmap_gi_editor_plugin.cpp10
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.cpp11
-rw-r--r--editor/plugins/mesh_instance_3d_editor_plugin.h3
-rw-r--r--editor/plugins/mesh_library_editor_plugin.cpp5
-rw-r--r--editor/plugins/multimesh_editor_plugin.cpp3
-rw-r--r--editor/plugins/navigation_obstacle_3d_editor_plugin.cpp10
-rw-r--r--editor/plugins/node_3d_editor_gizmos.cpp53
-rw-r--r--editor/plugins/node_3d_editor_plugin.cpp94
-rw-r--r--editor/plugins/node_3d_editor_plugin.h10
-rw-r--r--editor/plugins/occluder_instance_3d_editor_plugin.cpp3
-rw-r--r--editor/plugins/path_2d_editor_plugin.cpp25
-rw-r--r--editor/plugins/path_2d_editor_plugin.h2
-rw-r--r--editor/plugins/path_3d_editor_plugin.cpp57
-rw-r--r--editor/plugins/path_3d_editor_plugin.h4
-rw-r--r--editor/plugins/physical_bone_3d_editor_plugin.cpp8
-rw-r--r--editor/plugins/polygon_2d_editor_plugin.cpp3
-rw-r--r--editor/plugins/polygon_3d_editor_plugin.cpp16
-rw-r--r--editor/plugins/resource_preloader_editor_plugin.cpp2
-rw-r--r--editor/plugins/script_editor_plugin.cpp6
-rw-r--r--editor/plugins/script_text_editor.cpp45
-rw-r--r--editor/plugins/script_text_editor.h2
-rw-r--r--editor/plugins/skeleton_2d_editor_plugin.cpp3
-rw-r--r--editor/plugins/skeleton_3d_editor_plugin.cpp22
-rw-r--r--editor/plugins/skeleton_ik_3d_editor_plugin.cpp3
-rw-r--r--editor/plugins/sprite_2d_editor_plugin.cpp4
-rw-r--r--editor/plugins/sprite_frames_editor_plugin.cpp7
-rw-r--r--editor/plugins/text_shader_editor.cpp6
-rw-r--r--editor/plugins/texture_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_plugin.cpp2
-rw-r--r--editor/plugins/theme_editor_preview.cpp2
-rw-r--r--editor/plugins/tiles/tile_data_editors.cpp53
-rw-r--r--editor/plugins/tiles/tile_map_editor.cpp246
-rw-r--r--editor/plugins/tiles/tile_map_editor.h21
-rw-r--r--editor/plugins/tiles/tile_set_atlas_source_editor.cpp16
-rw-r--r--editor/plugins/tiles/tile_set_editor.cpp4
-rw-r--r--editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp6
-rw-r--r--editor/plugins/tiles/tiles_editor_plugin.cpp11
-rw-r--r--editor/plugins/version_control_editor_plugin.cpp78
-rw-r--r--editor/plugins/visual_shader_editor_plugin.cpp92
-rw-r--r--editor/plugins/voxel_gi_editor_plugin.cpp9
-rw-r--r--editor/project_manager.cpp4
-rw-r--r--editor/rename_dialog.cpp8
-rw-r--r--editor/scene_tree_dock.cpp64
-rw-r--r--editor/window_wrapper.cpp4
-rw-r--r--main/main.cpp55
-rw-r--r--misc/extension_api_validation/4.1-stable.expected8
-rwxr-xr-xmisc/scripts/header_guards.sh2
-rw-r--r--misc/scripts/mypy.ini1
-rw-r--r--modules/csg/editor/csg_gizmos.cpp72
-rw-r--r--modules/csg/editor/csg_gizmos.h6
-rw-r--r--modules/csg/icons/CSGTorus3D.svg2
-rw-r--r--modules/gdscript/.editorconfig8
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml3
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp9
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp43
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h1
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp11
-rw-r--r--modules/gdscript/gdscript.cpp143
-rw-r--r--modules/gdscript/gdscript.h15
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp84
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp3
-rw-r--r--modules/gdscript/gdscript_compiler.cpp121
-rw-r--r--modules/gdscript/gdscript_compiler.h4
-rw-r--r--modules/gdscript/gdscript_editor.cpp12
-rw-r--r--modules/gdscript/gdscript_function.cpp36
-rw-r--r--modules/gdscript/gdscript_function.h188
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp74
-rw-r--r--modules/gdscript/gdscript_parser.cpp319
-rw-r--r--modules/gdscript/gdscript_parser.h14
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp280
-rw-r--r--modules/gdscript/gdscript_tokenizer.h2
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp6
-rw-r--r--modules/gdscript/gdscript_vm.cpp17
-rw-r--r--modules/gdscript/gdscript_warning.cpp16
-rw-r--r--modules/gdscript/gdscript_warning.h4
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp464
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.h78
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp10
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp8
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.h1
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp55
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h2
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp199
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h8
-rw-r--r--modules/gdscript/language_server/godot_lsp.h173
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/typed_array_init_with_unconvertable_in_literal.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.gd5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.gd17
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out11
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_dont_make_literal_typed_with_weak_type.gd22
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/typed_array_dont_make_literal_typed_with_weak_type.out7
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.gd21
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.out3
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_equal_to_inferred.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_equal_to_inferred.out5
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_supertype_of_inferred.gd4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_supertype_of_inferred.out5
-rw-r--r--modules/gdscript/tests/scripts/lsp/class.notest.gd132
-rw-r--r--modules/gdscript/tests/scripts/lsp/enums.notest.gd26
-rw-r--r--modules/gdscript/tests/scripts/lsp/indentation.notest.gd28
-rw-r--r--modules/gdscript/tests/scripts/lsp/lambdas.notest.gd91
-rw-r--r--modules/gdscript/tests/scripts/lsp/local_variables.notest.gd25
-rw-r--r--modules/gdscript/tests/scripts/lsp/properties.notest.gd65
-rw-r--r--modules/gdscript/tests/scripts/lsp/scopes.notest.gd106
-rw-r--r--modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd56
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/bad_r_string_1.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/bad_r_string_1.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/bad_r_string_2.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/bad_r_string_2.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/bad_r_string_3.gd3
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/bad_r_string_3.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/r_strings.gd22
-rw-r--r--modules/gdscript/tests/scripts/parser/features/r_strings.out22
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/member_info.gd72
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/member_info.out45
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/metatypes.gd36
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/metatypes.notest.gd1
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/metatypes.out13
-rw-r--r--modules/gdscript/tests/scripts/utils.notest.gd281
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp9
-rw-r--r--modules/gdscript/tests/test_lsp.h480
-rw-r--r--modules/gltf/doc_classes/GLTFDocument.xml11
-rw-r--r--modules/gltf/doc_classes/GLTFDocumentExtension.xml55
-rw-r--r--modules/gltf/extensions/gltf_document_extension.cpp34
-rw-r--r--modules/gltf/extensions/gltf_document_extension.h10
-rw-r--r--modules/gltf/extensions/gltf_document_extension_texture_webp.cpp39
-rw-r--r--modules/gltf/extensions/gltf_document_extension_texture_webp.h5
-rw-r--r--modules/gltf/gltf_document.cpp120
-rw-r--r--modules/gltf/gltf_document.h11
-rw-r--r--modules/gridmap/editor/grid_map_editor_plugin.cpp1
-rw-r--r--modules/gridmap/grid_map.cpp1
-rw-r--r--modules/lightmapper_rd/lightmapper_rd.cpp16
-rw-r--r--modules/lightmapper_rd/lm_compute.glsl2
-rw-r--r--modules/mono/csharp_script.cpp19
-rw-r--r--modules/mono/csharp_script.h1
-rw-r--r--modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs34
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs6
-rw-r--r--modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs49
-rw-r--r--modules/mono/editor/bindings_generator.cpp15
-rw-r--r--modules/mono/editor/hostfxr_resolver.cpp7
-rw-r--r--modules/mono/glue/GodotSharp/.editorconfig11
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs2
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs54
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs14
-rw-r--r--modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj3
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.cpp1
-rw-r--r--modules/mono/mono_gd/gd_mono_cache.h2
-rw-r--r--modules/multiplayer/editor/replication_editor.cpp2
-rw-r--r--modules/openxr/action_map/openxr_action_map.cpp1
-rw-r--r--modules/openxr/extensions/openxr_opengl_extension.h1
-rw-r--r--modules/openxr/openxr_api.cpp90
-rw-r--r--modules/openxr/openxr_api.h6
-rw-r--r--modules/openxr/openxr_interface.cpp21
-rw-r--r--modules/openxr/openxr_interface.h1
-rw-r--r--modules/regex/doc_classes/RegEx.xml2
-rw-r--r--modules/vorbis/audio_stream_ogg_vorbis.cpp4
-rw-r--r--modules/webrtc/register_types.cpp8
-rw-r--r--modules/webrtc/webrtc_data_channel.cpp2
-rw-r--r--modules/webrtc/webrtc_data_channel.h2
-rw-r--r--modules/zip/zip_packer.cpp6
-rw-r--r--modules/zip/zip_packer.h6
-rw-r--r--modules/zip/zip_reader.cpp6
-rw-r--r--modules/zip/zip_reader.h6
-rw-r--r--platform/android/android_input_handler.cpp4
-rw-r--r--platform/android/android_input_handler.h2
-rw-r--r--platform/android/dir_access_jandroid.cpp26
-rw-r--r--platform/android/display_server_android.cpp2
-rw-r--r--platform/android/export/export_plugin.cpp2
-rw-r--r--platform/android/file_access_filesystem_jandroid.cpp26
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/GodotLib.java2
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java29
-rw-r--r--platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java24
-rw-r--r--platform/android/java_godot_lib_jni.cpp4
-rw-r--r--platform/android/java_godot_lib_jni.h2
-rw-r--r--platform/android/platform_gl.h43
-rw-r--r--platform/android/tts_android.cpp16
-rw-r--r--platform/ios/display_server_ios.mm2
-rw-r--r--platform/ios/os_ios.mm2
-rw-r--r--platform/ios/platform_config.h2
-rw-r--r--platform/ios/platform_gl.h40
-rw-r--r--platform/linuxbsd/godot_linuxbsd.cpp2
-rw-r--r--platform/linuxbsd/platform_config.h2
-rw-r--r--platform/linuxbsd/platform_gl.h41
-rw-r--r--platform/linuxbsd/tts_linux.cpp10
-rw-r--r--platform/linuxbsd/x11/display_server_x11.cpp18
-rw-r--r--platform/linuxbsd/x11/gl_manager_x11.cpp9
-rw-r--r--platform/macos/SCsub1
-rw-r--r--platform/macos/detect.py27
-rw-r--r--platform/macos/display_server_macos.h5
-rw-r--r--platform/macos/display_server_macos.mm140
-rw-r--r--platform/macos/doc_classes/EditorExportPlatformMacOS.xml3
-rw-r--r--platform/macos/export/export_plugin.cpp23
-rw-r--r--platform/macos/gl_manager_macos_angle.h63
-rw-r--r--platform/macos/gl_manager_macos_angle.mm70
-rw-r--r--platform/macos/gl_manager_macos_legacy.h25
-rw-r--r--platform/macos/gl_manager_macos_legacy.mm73
-rw-r--r--platform/macos/godot_content_view.mm6
-rw-r--r--platform/macos/os_macos.mm2
-rw-r--r--platform/macos/platform_config.h1
-rw-r--r--platform/macos/platform_gl.h52
-rw-r--r--platform/web/detect.py16
-rw-r--r--platform/web/display_server_web.cpp2
-rw-r--r--platform/web/os_web.cpp2
-rw-r--r--platform/web/platform_config.h2
-rw-r--r--platform/web/platform_gl.h40
-rw-r--r--platform/windows/SCsub4
-rw-r--r--platform/windows/detect.py25
-rw-r--r--platform/windows/display_server_windows.cpp162
-rw-r--r--platform/windows/display_server_windows.h8
-rw-r--r--platform/windows/doc_classes/EditorExportPlatformWindows.xml3
-rw-r--r--platform/windows/export/export_plugin.cpp32
-rw-r--r--platform/windows/gl_manager_windows_angle.cpp70
-rw-r--r--platform/windows/gl_manager_windows_angle.h61
-rw-r--r--platform/windows/gl_manager_windows_native.cpp (renamed from platform/windows/gl_manager_windows.cpp)112
-rw-r--r--platform/windows/gl_manager_windows_native.h (renamed from platform/windows/gl_manager_windows.h)28
-rw-r--r--platform/windows/os_windows.cpp4
-rw-r--r--platform/windows/platform_config.h2
-rw-r--r--platform/windows/platform_gl.h53
-rw-r--r--platform/windows/tts_windows.cpp12
-rw-r--r--platform/windows/wgl_detect_version.cpp189
-rw-r--r--platform/windows/wgl_detect_version.h40
-rw-r--r--scene/2d/animated_sprite_2d.cpp2
-rw-r--r--scene/2d/audio_stream_player_2d.cpp17
-rw-r--r--scene/2d/audio_stream_player_2d.h4
-rw-r--r--scene/2d/gpu_particles_2d.cpp8
-rw-r--r--scene/2d/gpu_particles_2d.h2
-rw-r--r--scene/2d/joint_2d.cpp10
-rw-r--r--scene/2d/joint_2d.h2
-rw-r--r--scene/2d/line_2d.cpp63
-rw-r--r--scene/2d/line_2d.h4
-rw-r--r--scene/2d/line_builder.cpp344
-rw-r--r--scene/2d/line_builder.h2
-rw-r--r--scene/2d/navigation_agent_2d.cpp4
-rw-r--r--scene/2d/physical_bone_2d.cpp2
-rw-r--r--scene/2d/tile_map.cpp124
-rw-r--r--scene/2d/tile_map.h5
-rw-r--r--scene/3d/audio_stream_player_3d.cpp15
-rw-r--r--scene/3d/audio_stream_player_3d.h3
-rw-r--r--scene/3d/gpu_particles_3d.cpp8
-rw-r--r--scene/3d/gpu_particles_3d.h2
-rw-r--r--scene/3d/joint_3d.cpp24
-rw-r--r--scene/3d/joint_3d.h2
-rw-r--r--scene/3d/lightmap_gi.cpp5
-rw-r--r--scene/3d/lightmap_gi.h1
-rw-r--r--scene/3d/navigation_agent_3d.cpp4
-rw-r--r--scene/3d/soft_body_3d.cpp9
-rw-r--r--scene/3d/soft_body_3d.h4
-rw-r--r--scene/3d/sprite_3d.cpp2
-rw-r--r--scene/animation/animation_blend_tree.cpp2
-rw-r--r--scene/animation/animation_node_state_machine.cpp2
-rw-r--r--scene/audio/audio_stream_player.cpp15
-rw-r--r--scene/audio/audio_stream_player.h8
-rw-r--r--scene/gui/box_container.cpp13
-rw-r--r--scene/gui/box_container.h2
-rw-r--r--scene/gui/button.cpp77
-rw-r--r--scene/gui/button.h2
-rw-r--r--scene/gui/check_box.cpp33
-rw-r--r--scene/gui/check_box.h2
-rw-r--r--scene/gui/check_button.cpp34
-rw-r--r--scene/gui/check_button.h2
-rw-r--r--scene/gui/code_edit.cpp349
-rw-r--r--scene/gui/code_edit.h24
-rw-r--r--scene/gui/color_mode.cpp20
-rw-r--r--scene/gui/color_picker.cpp94
-rw-r--r--scene/gui/color_picker.h16
-rw-r--r--scene/gui/control.cpp22
-rw-r--r--scene/gui/control.h1
-rw-r--r--scene/gui/dialogs.cpp11
-rw-r--r--scene/gui/dialogs.h2
-rw-r--r--scene/gui/file_dialog.cpp44
-rw-r--r--scene/gui/file_dialog.h5
-rw-r--r--scene/gui/flow_container.cpp12
-rw-r--r--scene/gui/flow_container.h2
-rw-r--r--scene/gui/graph_edit.cpp150
-rw-r--r--scene/gui/graph_edit.h73
-rw-r--r--scene/gui/graph_edit_arranger.cpp2
-rw-r--r--scene/gui/graph_element.cpp7
-rw-r--r--scene/gui/graph_element.h4
-rw-r--r--scene/gui/graph_node.cpp62
-rw-r--r--scene/gui/graph_node.h18
-rw-r--r--scene/gui/grid_container.cpp16
-rw-r--r--scene/gui/grid_container.h4
-rw-r--r--scene/gui/item_list.cpp57
-rw-r--r--scene/gui/item_list.h5
-rw-r--r--scene/gui/label.cpp31
-rw-r--r--scene/gui/label.h2
-rw-r--r--scene/gui/line_edit.cpp56
-rw-r--r--scene/gui/line_edit.h6
-rw-r--r--scene/gui/link_button.cpp37
-rw-r--r--scene/gui/link_button.h2
-rw-r--r--scene/gui/margin_container.cpp33
-rw-r--r--scene/gui/margin_container.h5
-rw-r--r--scene/gui/menu_bar.cpp55
-rw-r--r--scene/gui/menu_bar.h1
-rw-r--r--scene/gui/option_button.cpp36
-rw-r--r--scene/gui/option_button.h3
-rw-r--r--scene/gui/panel.cpp11
-rw-r--r--scene/gui/panel.h3
-rw-r--r--scene/gui/panel_container.cpp12
-rw-r--r--scene/gui/panel_container.h2
-rw-r--r--scene/gui/popup.cpp27
-rw-r--r--scene/gui/popup.h5
-rw-r--r--scene/gui/popup_menu.cpp99
-rw-r--r--scene/gui/popup_menu.h3
-rw-r--r--scene/gui/progress_bar.cpp23
-rw-r--r--scene/gui/progress_bar.h2
-rw-r--r--scene/gui/rich_text_label.cpp104
-rw-r--r--scene/gui/rich_text_label.h4
-rw-r--r--scene/gui/scroll_bar.cpp33
-rw-r--r--scene/gui/scroll_bar.h2
-rw-r--r--scene/gui/scroll_container.cpp11
-rw-r--r--scene/gui/scroll_container.h5
-rw-r--r--scene/gui/separator.cpp14
-rw-r--r--scene/gui/separator.h3
-rw-r--r--scene/gui/slider.cpp29
-rw-r--r--scene/gui/slider.h1
-rw-r--r--scene/gui/spin_box.cpp10
-rw-r--r--scene/gui/spin_box.h2
-rw-r--r--scene/gui/split_container.cpp29
-rw-r--r--scene/gui/split_container.h6
-rw-r--r--scene/gui/tab_bar.cpp63
-rw-r--r--scene/gui/tab_bar.h2
-rw-r--r--scene/gui/tab_container.cpp88
-rw-r--r--scene/gui/tab_container.h1
-rw-r--r--scene/gui/text_edit.cpp135
-rw-r--r--scene/gui/text_edit.h14
-rw-r--r--scene/gui/tree.cpp143
-rw-r--r--scene/gui/tree.h3
-rw-r--r--scene/main/canvas_item.cpp2
-rw-r--r--scene/main/viewport.cpp41
-rw-r--r--scene/main/window.cpp42
-rw-r--r--scene/main/window.h27
-rw-r--r--scene/resources/animation.cpp2
-rw-r--r--scene/resources/curve.cpp4
-rw-r--r--scene/resources/importer_mesh.cpp19
-rw-r--r--scene/resources/surface_tool.cpp4
-rw-r--r--scene/resources/syntax_highlighter.cpp2
-rw-r--r--scene/resources/theme.h30
-rw-r--r--scene/resources/tile_set.cpp23
-rw-r--r--scene/resources/tile_set.h17
-rw-r--r--scene/theme/default_theme.cpp3
-rw-r--r--scene/theme/icons/folder_down_arrow.svg1
-rw-r--r--scene/theme/icons/folder_right_arrow.svg1
-rw-r--r--scene/theme/theme_db.cpp44
-rw-r--r--scene/theme/theme_db.h47
-rw-r--r--scene/theme/theme_owner.cpp2
-rw-r--r--servers/audio/effects/audio_stream_generator.cpp11
-rw-r--r--servers/audio_server.cpp11
-rw-r--r--servers/physics_3d/godot_soft_body_3d.cpp6
-rw-r--r--servers/physics_server_2d.cpp2
-rw-r--r--servers/physics_server_3d.cpp18
-rw-r--r--servers/physics_server_3d.h8
-rw-r--r--servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp1
-rw-r--r--servers/rendering/renderer_rd/shaders/canvas.glsl6
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl11
-rw-r--r--servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl11
-rw-r--r--servers/rendering/renderer_viewport.cpp4
-rw-r--r--servers/rendering/rendering_server_default.cpp2
-rw-r--r--servers/rendering/shader_types.cpp1
-rw-r--r--servers/xr/xr_interface.cpp2
-rw-r--r--servers/xr/xr_interface.h1
-rw-r--r--tests/core/io/test_resource.h4
-rw-r--r--tests/core/math/test_math_funcs.h2
-rw-r--r--tests/core/variant/test_variant_utility.h141
-rw-r--r--tests/scene/test_code_edit.h188
-rw-r--r--tests/scene/test_curve_3d.h8
-rw-r--r--tests/scene/test_text_edit.h9
-rw-r--r--tests/servers/rendering/test_shader_preprocessor.h2
-rw-r--r--tests/test_main.cpp1
-rw-r--r--thirdparty/README.md20
-rw-r--r--thirdparty/angle/LICENSE32
-rw-r--r--thirdparty/angle/include/EGL/egl.h342
-rw-r--r--thirdparty/angle/include/EGL/eglext.h1486
-rw-r--r--thirdparty/angle/include/EGL/eglext_angle.h428
-rw-r--r--thirdparty/angle/include/EGL/eglplatform.h175
-rw-r--r--thirdparty/angle/include/KHR/khrplatform.h290
-rw-r--r--thirdparty/glad/EGL/eglplatform.h169
-rw-r--r--thirdparty/glad/egl.c408
-rw-r--r--thirdparty/glad/gl.c749
-rw-r--r--thirdparty/glad/glad/egl.h562
-rw-r--r--thirdparty/glad/glad/gl.h697
-rw-r--r--thirdparty/glad/patches/patch_enable_both_gl_and_gles.diff62
-rw-r--r--thirdparty/libwebp/src/dec/vp8i_dec.h2
-rw-r--r--thirdparty/libwebp/src/dec/vp8l_dec.c46
-rw-r--r--thirdparty/libwebp/src/dec/vp8li_dec.h2
-rw-r--r--thirdparty/libwebp/src/demux/demux.c2
-rw-r--r--thirdparty/libwebp/src/enc/vp8i_enc.h2
-rw-r--r--thirdparty/libwebp/src/mux/muxi.h2
-rw-r--r--thirdparty/libwebp/src/utils/huffman_utils.c97
-rw-r--r--thirdparty/libwebp/src/utils/huffman_utils.h27
658 files changed, 17110 insertions, 5391 deletions
diff --git a/.editorconfig b/.editorconfig
index 4bb7553b16..92ee947a82 100644
--- a/.editorconfig
+++ b/.editorconfig
@@ -21,13 +21,3 @@ indent_size = 4
[*.{yml,yaml}]
indent_style = space
indent_size = 2
-
-# GDScript unit test files
-[*.gd]
-indent_style = tab
-indent_size = 4
-insert_final_newline = true
-trim_trailing_whitespace = true
-
-[*.out]
-insert_final_newline = true
diff --git a/COPYRIGHT.txt b/COPYRIGHT.txt
index 1c22a72bfb..500eb84d08 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/angle/
+Comment: ANGLE
+Copyright: 2018, The ANGLE Project Authors.
+License: BSD-3-clause
+
Files: ./thirdparty/astcenc/
Comment: Arm ASTC Encoder
Copyright: 2011-2023, Arm Limited
diff --git a/SConstruct b/SConstruct
index df750beae4..d01062db8d 100644
--- a/SConstruct
+++ b/SConstruct
@@ -579,6 +579,8 @@ if selected_platform in platform_list:
if env["debug_symbols"]:
env.Append(CCFLAGS=["/Zi", "/FS"])
env.Append(LINKFLAGS=["/DEBUG:FULL"])
+ else:
+ env.Append(LINKFLAGS=["/DEBUG:NONE"])
if env["optimize"] == "speed":
env.Append(CCFLAGS=["/O2"])
diff --git a/core/config/project_settings.cpp b/core/config/project_settings.cpp
index 9ffbac3553..5ba800ebfe 100644
--- a/core/config/project_settings.cpp
+++ b/core/config/project_settings.cpp
@@ -1398,6 +1398,8 @@ ProjectSettings::ProjectSettings() {
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_filter", PROPERTY_HINT_ENUM, "Nearest,Linear,Linear Mipmap,Nearest Mipmap"), 1);
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "rendering/textures/canvas_textures/default_texture_repeat", PROPERTY_HINT_ENUM, "Disable,Enable,Mirror"), 0);
+ GLOBAL_DEF("collada/use_ambient", false);
+
// These properties will not show up in the dialog. If you want to exclude whole groups, use add_hidden_prefix().
GLOBAL_DEF_INTERNAL("application/config/features", PackedStringArray());
GLOBAL_DEF_INTERNAL("internationalization/locale/translation_remaps", PackedStringArray());
diff --git a/core/crypto/crypto_core.cpp b/core/crypto/crypto_core.cpp
index 3ca2ec282f..17b34c08e2 100644
--- a/core/crypto/crypto_core.cpp
+++ b/core/crypto/crypto_core.cpp
@@ -73,7 +73,7 @@ Error CryptoCore::RandomGenerator::init() {
}
Error CryptoCore::RandomGenerator::get_random_bytes(uint8_t *r_buffer, size_t p_bytes) {
- ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
int ret = mbedtls_ctr_drbg_random((mbedtls_ctr_drbg_context *)ctx, r_buffer, p_bytes);
ERR_FAIL_COND_V_MSG(ret, FAILED, " failed\n ! mbedtls_ctr_drbg_seed returned an error" + itos(ret));
return OK;
diff --git a/core/crypto/hashing_context.cpp b/core/crypto/hashing_context.cpp
index 35f491cd0c..157a0c091b 100644
--- a/core/crypto/hashing_context.cpp
+++ b/core/crypto/hashing_context.cpp
@@ -35,7 +35,7 @@
Error HashingContext::start(HashType p_type) {
ERR_FAIL_COND_V(ctx != nullptr, ERR_ALREADY_IN_USE);
_create_ctx(p_type);
- ERR_FAIL_COND_V(ctx == nullptr, ERR_UNAVAILABLE);
+ ERR_FAIL_NULL_V(ctx, ERR_UNAVAILABLE);
switch (type) {
case HASH_MD5:
return ((CryptoCore::MD5Context *)ctx)->start();
@@ -48,7 +48,7 @@ Error HashingContext::start(HashType p_type) {
}
Error HashingContext::update(PackedByteArray p_chunk) {
- ERR_FAIL_COND_V(ctx == nullptr, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
size_t len = p_chunk.size();
ERR_FAIL_COND_V(len == 0, FAILED);
const uint8_t *r = p_chunk.ptr();
@@ -64,7 +64,7 @@ Error HashingContext::update(PackedByteArray p_chunk) {
}
PackedByteArray HashingContext::finish() {
- ERR_FAIL_COND_V(ctx == nullptr, PackedByteArray());
+ ERR_FAIL_NULL_V(ctx, PackedByteArray());
PackedByteArray out;
Error err = FAILED;
switch (type) {
diff --git a/core/debugger/remote_debugger.cpp b/core/debugger/remote_debugger.cpp
index b4d6fa4174..a817ea871d 100644
--- a/core/debugger/remote_debugger.cpp
+++ b/core/debugger/remote_debugger.cpp
@@ -415,7 +415,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
Array msg;
msg.push_back(p_can_continue);
msg.push_back(error_str);
- ERR_FAIL_COND(!script_lang);
+ ERR_FAIL_NULL(script_lang);
msg.push_back(script_lang->debug_get_stack_level_count() > 0);
msg.push_back(Thread::get_caller_id() == Thread::get_main_id() ? String(RTR("Main Thread")) : itos(Thread::get_caller_id()));
if (allow_focus_steal_fn) {
@@ -485,7 +485,7 @@ void RemoteDebugger::debug(bool p_can_continue, bool p_is_error_breakpoint) {
} else if (command == "get_stack_frame_vars") {
ERR_FAIL_COND(data.size() != 1);
- ERR_FAIL_COND(!script_lang);
+ ERR_FAIL_NULL(script_lang);
int lv = data[0];
List<String> members;
diff --git a/core/extension/gdextension.cpp b/core/extension/gdextension.cpp
index 9674acb894..bffa0e251f 100644
--- a/core/extension/gdextension.cpp
+++ b/core/extension/gdextension.cpp
@@ -286,12 +286,14 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
const GDExtensionClassCreationInfo2 class_info2 = {
p_extension_funcs->is_virtual, // GDExtensionBool is_virtual;
p_extension_funcs->is_abstract, // GDExtensionBool is_abstract;
+ true, // GDExtensionBool is_exposed;
p_extension_funcs->set_func, // GDExtensionClassSet set_func;
p_extension_funcs->get_func, // GDExtensionClassGet get_func;
p_extension_funcs->get_property_list_func, // GDExtensionClassGetPropertyList get_property_list_func;
p_extension_funcs->free_property_list_func, // GDExtensionClassFreePropertyList free_property_list_func;
p_extension_funcs->property_can_revert_func, // GDExtensionClassPropertyCanRevert property_can_revert_func;
p_extension_funcs->property_get_revert_func, // GDExtensionClassPropertyGetRevert property_get_revert_func;
+ nullptr, // GDExtensionClassValidateProperty validate_property_func;
nullptr, // GDExtensionClassNotification2 notification_func;
p_extension_funcs->to_string_func, // GDExtensionClassToString to_string_func;
p_extension_funcs->reference_func, // GDExtensionClassReference reference_func;
@@ -299,6 +301,8 @@ void GDExtension::_register_extension_class(GDExtensionClassLibraryPtr p_library
p_extension_funcs->create_instance_func, // GDExtensionClassCreateInstance create_instance_func; /* this one is mandatory */
p_extension_funcs->free_instance_func, // GDExtensionClassFreeInstance free_instance_func; /* this one is mandatory */
p_extension_funcs->get_virtual_func, // GDExtensionClassGetVirtual get_virtual_func;
+ nullptr, // GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
+ nullptr, // GDExtensionClassCallVirtualWithData call_virtual_func;
p_extension_funcs->get_rid_func, // GDExtensionClassGetRID get_rid;
p_extension_funcs->class_userdata, // void *class_userdata;
};
@@ -352,12 +356,14 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
extension->gdextension.editor_class = self->level_initialized == INITIALIZATION_LEVEL_EDITOR;
extension->gdextension.is_virtual = p_extension_funcs->is_virtual;
extension->gdextension.is_abstract = p_extension_funcs->is_abstract;
+ extension->gdextension.is_exposed = p_extension_funcs->is_exposed;
extension->gdextension.set = p_extension_funcs->set_func;
extension->gdextension.get = p_extension_funcs->get_func;
extension->gdextension.get_property_list = p_extension_funcs->get_property_list_func;
extension->gdextension.free_property_list = p_extension_funcs->free_property_list_func;
extension->gdextension.property_can_revert = p_extension_funcs->property_can_revert_func;
extension->gdextension.property_get_revert = p_extension_funcs->property_get_revert_func;
+ extension->gdextension.validate_property = p_extension_funcs->validate_property_func;
#ifndef DISABLE_DEPRECATED
if (p_deprecated_funcs) {
extension->gdextension.notification = p_deprecated_funcs->notification_func;
@@ -371,6 +377,8 @@ void GDExtension::_register_extension_class_internal(GDExtensionClassLibraryPtr
extension->gdextension.create_instance = p_extension_funcs->create_instance_func;
extension->gdextension.free_instance = p_extension_funcs->free_instance_func;
extension->gdextension.get_virtual = p_extension_funcs->get_virtual_func;
+ extension->gdextension.get_virtual_call_data = p_extension_funcs->get_virtual_call_data_func;
+ extension->gdextension.call_virtual_with_data = p_extension_funcs->call_virtual_with_data_func;
extension->gdextension.get_rid = p_extension_funcs->get_rid_func;
ClassDB::register_extension_class(&extension->gdextension);
@@ -487,7 +495,7 @@ void GDExtension::register_interface_function(StringName p_function_name, GDExte
GDExtensionInterfaceFunctionPtr GDExtension::get_interface_function(StringName p_function_name) {
GDExtensionInterfaceFunctionPtr *function = gdextension_interface_functions.getptr(p_function_name);
- ERR_FAIL_COND_V_MSG(function == nullptr, nullptr, "Attempt to get non-existent interface function: " + p_function_name);
+ ERR_FAIL_NULL_V_MSG(function, nullptr, "Attempt to get non-existent interface function: " + String(p_function_name) + ".");
return *function;
}
@@ -521,7 +529,7 @@ Error GDExtension::open_library(const String &p_path, const String &p_entry_symb
}
void GDExtension::close_library() {
- ERR_FAIL_COND(library == nullptr);
+ ERR_FAIL_NULL(library);
OS::get_singleton()->close_dynamic_library(library);
#if defined(TOOLS_ENABLED) && defined(WINDOWS_ENABLED)
@@ -539,12 +547,12 @@ bool GDExtension::is_library_open() const {
}
GDExtension::InitializationLevel GDExtension::get_minimum_library_initialization_level() const {
- ERR_FAIL_COND_V(library == nullptr, INITIALIZATION_LEVEL_CORE);
+ ERR_FAIL_NULL_V(library, INITIALIZATION_LEVEL_CORE);
return InitializationLevel(initialization.minimum_initialization_level);
}
void GDExtension::initialize_library(InitializationLevel p_level) {
- ERR_FAIL_COND(library == nullptr);
+ ERR_FAIL_NULL(library);
ERR_FAIL_COND_MSG(p_level <= int32_t(level_initialized), vformat("Level '%d' must be higher than the current level '%d'", p_level, level_initialized));
level_initialized = int32_t(p_level);
@@ -554,7 +562,7 @@ void GDExtension::initialize_library(InitializationLevel p_level) {
initialization.initialize(initialization.userdata, GDExtensionInitializationLevel(p_level));
}
void GDExtension::deinitialize_library(InitializationLevel p_level) {
- ERR_FAIL_COND(library == nullptr);
+ ERR_FAIL_NULL(library);
ERR_FAIL_COND(p_level > int32_t(level_initialized));
level_initialized = int32_t(p_level) - 1;
@@ -707,6 +715,11 @@ Ref<Resource> GDExtensionResourceLoader::load(const String &p_path, const String
// This is so relative path to dependencies are satisfied.
String copy_path = abs_path.get_base_dir().path_join("~" + abs_path.get_file());
+ // If there's a left-over copy (possibly from a crash) then delete it first.
+ if (FileAccess::exists(copy_path)) {
+ DirAccess::remove_absolute(copy_path);
+ }
+
Error copy_err = DirAccess::copy_absolute(abs_path, copy_path);
if (copy_err) {
if (r_error) {
diff --git a/core/extension/gdextension_interface.cpp b/core/extension/gdextension_interface.cpp
index 995d25cfb5..55f5b32c67 100644
--- a/core/extension/gdextension_interface.cpp
+++ b/core/extension/gdextension_interface.cpp
@@ -42,6 +42,152 @@
#include "core/variant/variant.h"
#include "core/version.h"
+class CallableCustomExtension : public CallableCustom {
+ void *userdata;
+ void *token;
+
+ ObjectID object;
+
+ GDExtensionCallableCustomCall call_func;
+ GDExtensionCallableCustomIsValid is_valid_func;
+ GDExtensionCallableCustomFree free_func;
+
+ GDExtensionCallableCustomEqual equal_func;
+ GDExtensionCallableCustomLessThan less_than_func;
+
+ GDExtensionCallableCustomToString to_string_func;
+
+ uint32_t _hash;
+
+ static bool default_compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const CallableCustomExtension *a = static_cast<const CallableCustomExtension *>(p_a);
+ const CallableCustomExtension *b = static_cast<const CallableCustomExtension *>(p_b);
+
+ if (a->call_func != b->call_func || a->userdata != b->userdata) {
+ return false;
+ }
+ return true;
+ }
+
+ static bool default_compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const CallableCustomExtension *a = static_cast<const CallableCustomExtension *>(p_a);
+ const CallableCustomExtension *b = static_cast<const CallableCustomExtension *>(p_b);
+
+ if (a->call_func != b->call_func) {
+ return a->call_func < b->call_func;
+ }
+ return a->userdata < b->userdata;
+ }
+
+ static bool custom_compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const CallableCustomExtension *a = static_cast<const CallableCustomExtension *>(p_a);
+ const CallableCustomExtension *b = static_cast<const CallableCustomExtension *>(p_b);
+
+ if (a->equal_func != b->equal_func) {
+ return false;
+ }
+ return a->equal_func(a->userdata, b->userdata);
+ }
+
+ static bool custom_compare_less(const CallableCustom *p_a, const CallableCustom *p_b) {
+ const CallableCustomExtension *a = static_cast<const CallableCustomExtension *>(p_a);
+ const CallableCustomExtension *b = static_cast<const CallableCustomExtension *>(p_b);
+
+ if (a->less_than_func != b->less_than_func) {
+ return default_compare_less(p_a, p_b);
+ }
+ return a->less_than_func(a->userdata, b->userdata);
+ }
+
+public:
+ uint32_t hash() const override {
+ return _hash;
+ }
+
+ String get_as_text() const override {
+ if (to_string_func != nullptr) {
+ String out;
+ GDExtensionBool is_valid = false;
+
+ to_string_func(userdata, &is_valid, (GDExtensionStringPtr)&out);
+
+ if (is_valid) {
+ return out;
+ }
+ }
+ return "<CallableCustom>";
+ }
+
+ CompareEqualFunc get_compare_equal_func() const override {
+ return (equal_func != nullptr) ? custom_compare_equal : default_compare_equal;
+ }
+
+ CompareLessFunc get_compare_less_func() const override {
+ return (less_than_func != nullptr) ? custom_compare_less : default_compare_less;
+ }
+
+ bool is_valid() const override {
+ if (is_valid_func != nullptr && !is_valid_func(userdata)) {
+ return false;
+ }
+ return call_func != nullptr;
+ }
+
+ StringName get_method() const override {
+ return StringName();
+ }
+
+ ObjectID get_object() const override {
+ return object;
+ }
+
+ void *get_userdata(void *p_token) const {
+ return (p_token == token) ? userdata : nullptr;
+ }
+
+ void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
+ GDExtensionCallError error;
+
+ call_func(userdata, (GDExtensionConstVariantPtr *)p_arguments, p_argcount, (GDExtensionVariantPtr)&r_return_value, &error);
+
+ r_call_error.error = (Callable::CallError::Error)error.error;
+ r_call_error.argument = error.argument;
+ r_call_error.expected = error.expected;
+ }
+
+ CallableCustomExtension(GDExtensionCallableCustomInfo *p_info) {
+ userdata = p_info->callable_userdata;
+ token = p_info->token;
+
+ if (p_info->object != nullptr) {
+ object = ((Object *)p_info->object)->get_instance_id();
+ }
+
+ call_func = p_info->call_func;
+ is_valid_func = p_info->is_valid_func;
+ free_func = p_info->free_func;
+
+ equal_func = p_info->equal_func;
+ less_than_func = p_info->less_than_func;
+
+ to_string_func = p_info->to_string_func;
+
+ // Pre-calculate the hash.
+ if (p_info->hash_func != nullptr) {
+ _hash = p_info->hash_func(userdata);
+ } else {
+ _hash = hash_murmur3_one_64((uint64_t)call_func);
+ _hash = hash_murmur3_one_64((uint64_t)userdata, _hash);
+ }
+ }
+
+ ~CallableCustomExtension() {
+ if (free_func != nullptr) {
+ free_func(userdata);
+ }
+ }
+};
+
// Core interface functions.
GDExtensionInterfaceFunctionPtr gdextension_get_proc_address(const char *p_name) {
return GDExtension::get_interface_function(p_name);
@@ -1098,7 +1244,7 @@ static GDExtensionScriptInstancePtr gdextension_placeholder_script_instance_crea
static void gdextension_placeholder_script_instance_update(GDExtensionScriptInstancePtr p_placeholder, GDExtensionConstTypePtr p_properties, GDExtensionConstTypePtr p_values) {
PlaceHolderScriptInstance *placeholder = dynamic_cast<PlaceHolderScriptInstance *>(reinterpret_cast<ScriptInstance *>(p_placeholder));
- ERR_FAIL_COND_MSG(!placeholder, "Unable to update placeholder, expected a PlaceHolderScriptInstance but received an invalid type.");
+ ERR_FAIL_NULL_MSG(placeholder, "Unable to update placeholder, expected a PlaceHolderScriptInstance but received an invalid type.");
const Array &properties = *reinterpret_cast<const Array *>(p_properties);
const Dictionary &values = *reinterpret_cast<const Dictionary *>(p_values);
@@ -1140,6 +1286,22 @@ static GDExtensionScriptInstancePtr gdextension_object_get_script_instance(GDExt
return script_instance_extension->instance;
}
+static void gdextension_callable_custom_create(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_custom_callable_info) {
+ memnew_placement(r_callable, Callable(memnew(CallableCustomExtension(p_custom_callable_info))));
+}
+
+static void *gdextension_callable_custom_get_userdata(GDExtensionTypePtr p_callable, void *p_token) {
+ const Callable &callable = *reinterpret_cast<const Callable *>(p_callable);
+ if (!callable.is_custom()) {
+ return nullptr;
+ }
+ const CallableCustomExtension *custom_callable = dynamic_cast<const CallableCustomExtension *>(callable.get_custom());
+ if (!custom_callable) {
+ return nullptr;
+ }
+ return custom_callable->get_userdata(p_token);
+}
+
static GDExtensionMethodBindPtr gdextension_classdb_get_method_bind(GDExtensionConstStringNamePtr p_classname, GDExtensionConstStringNamePtr p_methodname, GDExtensionInt p_hash) {
const StringName classname = *reinterpret_cast<const StringName *>(p_classname);
const StringName methodname = *reinterpret_cast<const StringName *>(p_methodname);
@@ -1160,7 +1322,7 @@ static GDExtensionMethodBindPtr gdextension_classdb_get_method_bind(GDExtensionC
ERR_PRINT("Method '" + classname + "." + methodname + "' has changed and no compatibility fallback has been provided. Please open an issue.");
return nullptr;
}
- ERR_FAIL_COND_V(!mb, nullptr);
+ ERR_FAIL_NULL_V(mb, nullptr);
if (mb->get_hash() != p_hash) {
ERR_PRINT("Hash mismatch for method '" + classname + "." + methodname + "'.");
return nullptr;
@@ -1325,6 +1487,8 @@ void gdextension_setup_interface() {
REGISTER_INTERFACE_FUNC(placeholder_script_instance_create);
REGISTER_INTERFACE_FUNC(placeholder_script_instance_update);
REGISTER_INTERFACE_FUNC(object_get_script_instance);
+ REGISTER_INTERFACE_FUNC(callable_custom_create);
+ REGISTER_INTERFACE_FUNC(callable_custom_get_userdata);
REGISTER_INTERFACE_FUNC(classdb_construct_object);
REGISTER_INTERFACE_FUNC(classdb_get_method_bind);
REGISTER_INTERFACE_FUNC(classdb_get_class_tag);
diff --git a/core/extension/gdextension_interface.h b/core/extension/gdextension_interface.h
index 4379e520b7..48cb28832a 100644
--- a/core/extension/gdextension_interface.h
+++ b/core/extension/gdextension_interface.h
@@ -258,15 +258,18 @@ typedef const GDExtensionPropertyInfo *(*GDExtensionClassGetPropertyList)(GDExte
typedef void (*GDExtensionClassFreePropertyList)(GDExtensionClassInstancePtr p_instance, const GDExtensionPropertyInfo *p_list);
typedef GDExtensionBool (*GDExtensionClassPropertyCanRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name);
typedef GDExtensionBool (*GDExtensionClassPropertyGetRevert)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, GDExtensionVariantPtr r_ret);
+typedef GDExtensionBool (*GDExtensionClassValidateProperty)(GDExtensionClassInstancePtr p_instance, GDExtensionPropertyInfo *p_property);
typedef void (*GDExtensionClassNotification)(GDExtensionClassInstancePtr p_instance, int32_t p_what); // Deprecated. Use GDExtensionClassNotification2 instead.
typedef void (*GDExtensionClassNotification2)(GDExtensionClassInstancePtr p_instance, int32_t p_what, GDExtensionBool p_reversed);
typedef void (*GDExtensionClassToString)(GDExtensionClassInstancePtr p_instance, GDExtensionBool *r_is_valid, GDExtensionStringPtr p_out);
typedef void (*GDExtensionClassReference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDExtensionClassUnreference)(GDExtensionClassInstancePtr p_instance);
typedef void (*GDExtensionClassCallVirtual)(GDExtensionClassInstancePtr p_instance, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
-typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance)(void *p_userdata);
-typedef void (*GDExtensionClassFreeInstance)(void *p_userdata, GDExtensionClassInstancePtr p_instance);
-typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_userdata, GDExtensionConstStringNamePtr p_name);
+typedef GDExtensionObjectPtr (*GDExtensionClassCreateInstance)(void *p_class_userdata);
+typedef void (*GDExtensionClassFreeInstance)(void *p_class_userdata, GDExtensionClassInstancePtr p_instance);
+typedef GDExtensionClassCallVirtual (*GDExtensionClassGetVirtual)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
+typedef void *(*GDExtensionClassGetVirtualCallData)(void *p_class_userdata, GDExtensionConstStringNamePtr p_name);
+typedef void (*GDExtensionClassCallVirtualWithData)(GDExtensionClassInstancePtr p_instance, GDExtensionConstStringNamePtr p_name, void *p_virtual_call_userdata, const GDExtensionConstTypePtr *p_args, GDExtensionTypePtr r_ret);
typedef struct {
GDExtensionBool is_virtual;
@@ -291,19 +294,31 @@ typedef struct {
typedef struct {
GDExtensionBool is_virtual;
GDExtensionBool is_abstract;
+ GDExtensionBool is_exposed;
GDExtensionClassSet set_func;
GDExtensionClassGet get_func;
GDExtensionClassGetPropertyList get_property_list_func;
GDExtensionClassFreePropertyList free_property_list_func;
GDExtensionClassPropertyCanRevert property_can_revert_func;
GDExtensionClassPropertyGetRevert property_get_revert_func;
+ GDExtensionClassValidateProperty validate_property_func;
GDExtensionClassNotification2 notification_func;
GDExtensionClassToString to_string_func;
GDExtensionClassReference reference_func;
GDExtensionClassUnreference unreference_func;
GDExtensionClassCreateInstance create_instance_func; // (Default) constructor; mandatory. If the class is not instantiable, consider making it virtual or abstract.
GDExtensionClassFreeInstance free_instance_func; // Destructor; mandatory.
- GDExtensionClassGetVirtual get_virtual_func; // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
+ // Queries a virtual function by name and returns a callback to invoke the requested virtual function.
+ GDExtensionClassGetVirtual get_virtual_func;
+ // Paired with `call_virtual_with_data_func`, this is an alternative to `get_virtual_func` for extensions that
+ // need or benefit from extra data when calling virtual functions.
+ // Returns user data that will be passed to `call_virtual_with_data_func`.
+ // Returning `NULL` from this function signals to Godot that the virtual function is not overridden.
+ // Data returned from this function should be managed by the extension and must be valid until the extension is deinitialized.
+ // You should supply either `get_virtual_func`, or `get_virtual_call_data_func` with `call_virtual_with_data_func`.
+ GDExtensionClassGetVirtualCallData get_virtual_call_data_func;
+ // Used to call virtual functions when `get_virtual_call_data_func` is not null.
+ GDExtensionClassCallVirtualWithData call_virtual_with_data_func;
GDExtensionClassGetRID get_rid_func;
void *class_userdata; // Per-class user data, later accessible in instance bindings.
} GDExtensionClassCreationInfo2;
@@ -364,6 +379,47 @@ typedef struct {
GDExtensionVariantPtr *default_arguments;
} GDExtensionClassMethodInfo;
+typedef void (*GDExtensionCallableCustomCall)(void *callable_userdata, const GDExtensionConstVariantPtr *p_args, GDExtensionInt p_argument_count, GDExtensionVariantPtr r_return, GDExtensionCallError *r_error);
+typedef GDExtensionBool (*GDExtensionCallableCustomIsValid)(void *callable_userdata);
+typedef void (*GDExtensionCallableCustomFree)(void *callable_userdata);
+
+typedef uint32_t (*GDExtensionCallableCustomHash)(void *callable_userdata);
+typedef GDExtensionBool (*GDExtensionCallableCustomEqual)(void *callable_userdata_a, void *callable_userdata_b);
+typedef GDExtensionBool (*GDExtensionCallableCustomLessThan)(void *callable_userdata_a, void *callable_userdata_b);
+
+typedef void (*GDExtensionCallableCustomToString)(void *callable_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out);
+
+typedef struct {
+ /* Only `call_func` and `token` are strictly required, however, `object` should be passed if its not a static method.
+ *
+ * `token` should point to an address that uniquely identifies the GDExtension (for example, the
+ * `GDExtensionClassLibraryPtr` passed to the entry symbol function.
+ *
+ * `hash_func`, `equal_func`, and `less_than_func` are optional. If not provided both `call_func` and
+ * `callable_userdata` together are used as the identity of the callable for hashing and comparison purposes.
+ *
+ * The hash returned by `hash_func` is cached, `hash_func` will not be called more than once per callable.
+ *
+ * `is_valid_func` is necessary if the validity of the callable can change before destruction.
+ *
+ * `free_func` is necessary if `callable_userdata` needs to be cleaned up when the callable is freed.
+ */
+ void *callable_userdata;
+ void *token;
+
+ GDExtensionObjectPtr object;
+
+ GDExtensionCallableCustomCall call_func;
+ GDExtensionCallableCustomIsValid is_valid_func;
+ GDExtensionCallableCustomFree free_func;
+
+ GDExtensionCallableCustomHash hash_func;
+ GDExtensionCallableCustomEqual equal_func;
+ GDExtensionCallableCustomLessThan less_than_func;
+
+ GDExtensionCallableCustomToString to_string_func;
+} GDExtensionCallableCustomInfo;
+
/* SCRIPT INSTANCE EXTENSION */
typedef void *GDExtensionScriptInstanceDataPtr; // Pointer to custom ScriptInstance native implementation.
@@ -2247,6 +2303,34 @@ typedef void (*GDExtensionInterfacePlaceHolderScriptInstanceUpdate)(GDExtensionS
*/
typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptInstance)(GDExtensionConstObjectPtr p_object, GDExtensionObjectPtr p_language);
+/* INTERFACE: Callable */
+
+/**
+ * @name callable_custom_create
+ * @since 4.2
+ *
+ * Creates a custom Callable object from a function pointer.
+ *
+ * Provided struct can be safely freed once the function returns.
+ *
+ * @param r_callable A pointer that will receive the new Callable.
+ * @param p_callable_custom_info The info required to construct a Callable.
+ */
+typedef void (*GDExtensionInterfaceCallableCustomCreate)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_callable_custom_info);
+
+/**
+ * @name callable_custom_get_userdata
+ * @since 4.2
+ *
+ * Retrieves the userdata pointer from a custom Callable.
+ *
+ * If the Callable is not a custom Callable or the token does not match the one provided to callable_custom_create() via GDExtensionCallableCustomInfo then NULL will be returned.
+ *
+ * @param p_callable A pointer to a Callable.
+ * @param p_token A pointer to an address that uniquely identifies the GDExtension.
+ */
+typedef void *(*GDExtensionInterfaceCallableCustomGetUserData)(GDExtensionConstTypePtr p_callable, void *p_token);
+
/* INTERFACE: ClassDB */
/**
diff --git a/core/input/input.cpp b/core/input/input.cpp
index e89c71d762..19ea8c7317 100644
--- a/core/input/input.cpp
+++ b/core/input/input.cpp
@@ -701,18 +701,39 @@ void Input::_parse_input_event_impl(const Ref<InputEvent> &p_event, bool p_is_em
if (!p_event->is_echo()) {
if (p_event->is_action_pressed(E.key)) {
- action.pressed++;
+ if (jm.is_valid()) {
+ // If axis is already pressed, don't increase the pressed counter.
+ if (!action.axis_pressed) {
+ action.pressed++;
+ action.axis_pressed = true;
+ }
+ } else {
+ action.pressed++;
+ }
+
is_pressed = true;
if (action.pressed == 1) {
action.pressed_physics_frame = Engine::get_singleton()->get_physics_frames();
action.pressed_process_frame = Engine::get_singleton()->get_process_frames();
}
} else {
- if (action.pressed == 1) {
- action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
- action.released_process_frame = Engine::get_singleton()->get_process_frames();
+ bool is_released = true;
+ if (jm.is_valid()) {
+ // Same as above. Don't release axis when not pressed.
+ if (action.axis_pressed) {
+ action.axis_pressed = false;
+ } else {
+ is_released = false;
+ }
+ }
+
+ if (is_released) {
+ if (action.pressed == 1) {
+ action.released_physics_frame = Engine::get_singleton()->get_physics_frames();
+ action.released_process_frame = Engine::get_singleton()->get_process_frames();
+ }
+ action.pressed = MAX(action.pressed - 1, 0);
}
- action.pressed = MAX(action.pressed - 1, 0);
}
action.exact = InputMap::get_singleton()->event_is_action(p_event, E.key, true);
}
diff --git a/core/input/input.h b/core/input/input.h
index 26466bdead..8ce5f64a6a 100644
--- a/core/input/input.h
+++ b/core/input/input.h
@@ -104,6 +104,7 @@ private:
uint64_t released_physics_frame = UINT64_MAX;
uint64_t released_process_frame = UINT64_MAX;
int pressed = 0;
+ bool axis_pressed = false;
bool exact = true;
float strength = 0.0f;
float raw_strength = 0.0f;
diff --git a/core/io/compression.cpp b/core/io/compression.cpp
index e36fb0afa4..4e4627c40b 100644
--- a/core/io/compression.cpp
+++ b/core/io/compression.cpp
@@ -215,7 +215,7 @@ int Compression::decompress_dynamic(Vector<uint8_t> *p_dst_vect, int p_max_dst_s
#ifdef BROTLI_ENABLED
BrotliDecoderResult ret;
BrotliDecoderState *state = BrotliDecoderCreateInstance(nullptr, nullptr, nullptr);
- ERR_FAIL_COND_V(state == nullptr, Z_DATA_ERROR);
+ ERR_FAIL_NULL_V(state, Z_DATA_ERROR);
// Setup the stream inputs.
const uint8_t *next_in = p_src;
diff --git a/core/io/file_access_memory.cpp b/core/io/file_access_memory.cpp
index 14ec0be092..0983920b94 100644
--- a/core/io/file_access_memory.cpp
+++ b/core/io/file_access_memory.cpp
@@ -79,7 +79,7 @@ Error FileAccessMemory::open_custom(const uint8_t *p_data, uint64_t p_len) {
}
Error FileAccessMemory::open_internal(const String &p_path, int p_mode_flags) {
- ERR_FAIL_COND_V(!files, ERR_FILE_NOT_FOUND);
+ ERR_FAIL_NULL_V(files, ERR_FILE_NOT_FOUND);
String name = fix_path(p_path);
//name = DirAccess::normalize_path(name);
@@ -99,22 +99,22 @@ bool FileAccessMemory::is_open() const {
}
void FileAccessMemory::seek(uint64_t p_position) {
- ERR_FAIL_COND(!data);
+ ERR_FAIL_NULL(data);
pos = p_position;
}
void FileAccessMemory::seek_end(int64_t p_position) {
- ERR_FAIL_COND(!data);
+ ERR_FAIL_NULL(data);
pos = length + p_position;
}
uint64_t FileAccessMemory::get_position() const {
- ERR_FAIL_COND_V(!data, 0);
+ ERR_FAIL_NULL_V(data, 0);
return pos;
}
uint64_t FileAccessMemory::get_length() const {
- ERR_FAIL_COND_V(!data, 0);
+ ERR_FAIL_NULL_V(data, 0);
return length;
}
@@ -134,7 +134,7 @@ uint8_t FileAccessMemory::get_8() const {
uint64_t FileAccessMemory::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(!data, -1);
+ ERR_FAIL_NULL_V(data, -1);
uint64_t left = length - pos;
uint64_t read = MIN(p_length, left);
@@ -154,11 +154,11 @@ Error FileAccessMemory::get_error() const {
}
void FileAccessMemory::flush() {
- ERR_FAIL_COND(!data);
+ ERR_FAIL_NULL(data);
}
void FileAccessMemory::store_8(uint8_t p_byte) {
- ERR_FAIL_COND(!data);
+ ERR_FAIL_NULL(data);
ERR_FAIL_COND(pos >= length);
data[pos++] = p_byte;
}
diff --git a/core/io/file_access_zip.cpp b/core/io/file_access_zip.cpp
index c7f1a73f97..d085c29728 100644
--- a/core/io/file_access_zip.cpp
+++ b/core/io/file_access_zip.cpp
@@ -239,7 +239,7 @@ Error FileAccessZip::open_internal(const String &p_path, int p_mode_flags) {
ERR_FAIL_COND_V(p_mode_flags & FileAccess::WRITE, FAILED);
ZipArchive *arch = ZipArchive::get_singleton();
- ERR_FAIL_COND_V(!arch, FAILED);
+ ERR_FAIL_NULL_V(arch, FAILED);
zfile = arch->get_file_handle(p_path);
ERR_FAIL_COND_V(!zfile, FAILED);
@@ -255,7 +255,7 @@ void FileAccessZip::_close() {
}
ZipArchive *arch = ZipArchive::get_singleton();
- ERR_FAIL_COND(!arch);
+ ERR_FAIL_NULL(arch);
arch->close_handle(zfile);
zfile = nullptr;
}
diff --git a/core/io/image.cpp b/core/io/image.cpp
index ce2f47371a..674af6b0a6 100644
--- a/core/io/image.cpp
+++ b/core/io/image.cpp
@@ -2356,7 +2356,7 @@ void Image::initialize_data(const char **p_xpm) {
}
Color *colorptr = colormap.getptr(pixelstr);
- ERR_FAIL_COND(!colorptr);
+ ERR_FAIL_NULL(colorptr);
uint8_t pixel[4];
for (uint32_t i = 0; i < pixel_size; i++) {
pixel[i] = CLAMP((*colorptr)[i] * 255, 0, 255);
@@ -2646,23 +2646,23 @@ Error Image::compress_from_channels(CompressMode p_mode, UsedChannels p_channels
switch (p_mode) {
case COMPRESS_S3TC: {
- ERR_FAIL_COND_V(!_image_compress_bc_func, ERR_UNAVAILABLE);
+ ERR_FAIL_NULL_V(_image_compress_bc_func, ERR_UNAVAILABLE);
_image_compress_bc_func(this, p_channels);
} break;
case COMPRESS_ETC: {
- ERR_FAIL_COND_V(!_image_compress_etc1_func, ERR_UNAVAILABLE);
+ ERR_FAIL_NULL_V(_image_compress_etc1_func, ERR_UNAVAILABLE);
_image_compress_etc1_func(this);
} break;
case COMPRESS_ETC2: {
- ERR_FAIL_COND_V(!_image_compress_etc2_func, ERR_UNAVAILABLE);
+ ERR_FAIL_NULL_V(_image_compress_etc2_func, ERR_UNAVAILABLE);
_image_compress_etc2_func(this, p_channels);
} break;
case COMPRESS_BPTC: {
- ERR_FAIL_COND_V(!_image_compress_bptc_func, ERR_UNAVAILABLE);
+ ERR_FAIL_NULL_V(_image_compress_bptc_func, ERR_UNAVAILABLE);
_image_compress_bptc_func(this, p_channels);
} break;
case COMPRESS_ASTC: {
- ERR_FAIL_COND_V(!_image_compress_astc_func, ERR_UNAVAILABLE);
+ ERR_FAIL_NULL_V(_image_compress_astc_func, ERR_UNAVAILABLE);
_image_compress_astc_func(this, p_astc_format);
} break;
case COMPRESS_MAX: {
@@ -3412,6 +3412,7 @@ void Image::_bind_methods() {
ClassDB::bind_method(D_METHOD("convert", "format"), &Image::convert);
+ ClassDB::bind_method(D_METHOD("get_mipmap_count"), &Image::get_mipmap_count);
ClassDB::bind_method(D_METHOD("get_mipmap_offset", "mipmap"), &Image::get_mipmap_offset);
ClassDB::bind_method(D_METHOD("resize_to_po2", "square", "interpolation"), &Image::resize_to_po2, DEFVAL(false), DEFVAL(INTERPOLATE_BILINEAR));
@@ -3655,7 +3656,7 @@ void Image::bump_map_to_normal_map(float bump_scale) {
const uint8_t *rp = data.ptr();
uint8_t *wp = result_image.ptrw();
- ERR_FAIL_COND(!rp);
+ ERR_FAIL_NULL(rp);
unsigned char *write_ptr = wp;
float *read_ptr = (float *)rp;
@@ -3916,7 +3917,7 @@ Error Image::_load_from_buffer(const Vector<uint8_t> &p_array, ImageMemLoadFunc
int buffer_size = p_array.size();
ERR_FAIL_COND_V(buffer_size == 0, ERR_INVALID_PARAMETER);
- ERR_FAIL_COND_V(!p_loader, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_loader, ERR_INVALID_PARAMETER);
const uint8_t *r = p_array.ptr();
diff --git a/core/io/ip.cpp b/core/io/ip.cpp
index 772f700916..254351897d 100644
--- a/core/io/ip.cpp
+++ b/core/io/ip.cpp
@@ -333,7 +333,7 @@ IP *(*IP::_create)() = nullptr;
IP *IP::create() {
ERR_FAIL_COND_V_MSG(singleton, nullptr, "IP singleton already exist.");
- ERR_FAIL_COND_V(!_create, nullptr);
+ ERR_FAIL_NULL_V(_create, nullptr);
return _create();
}
diff --git a/core/io/marshalls.cpp b/core/io/marshalls.cpp
index 6ca7b0f831..bfef9ebeaf 100644
--- a/core/io/marshalls.cpp
+++ b/core/io/marshalls.cpp
@@ -640,7 +640,7 @@ Error decode_variant(Variant &r_variant, const uint8_t *p_buffer, int p_len, int
} else {
Object *obj = ClassDB::instantiate(str);
- ERR_FAIL_COND_V(!obj, ERR_UNAVAILABLE);
+ ERR_FAIL_NULL_V(obj, ERR_UNAVAILABLE);
ERR_FAIL_COND_V(len < 4, ERR_INVALID_DATA);
int32_t count = decode_uint32(buf);
@@ -1576,7 +1576,7 @@ Error encode_variant(const Variant &p_variant, uint8_t *r_buffer, int &r_len, bo
buf += len;
}
Variant *v = d.getptr(E);
- ERR_FAIL_COND_V(!v, ERR_BUG);
+ ERR_FAIL_NULL_V(v, ERR_BUG);
err = encode_variant(*v, buf, len, p_full_objects, p_depth + 1);
ERR_FAIL_COND_V(err, err);
ERR_FAIL_COND_V(len % 4, ERR_BUG);
diff --git a/core/io/packed_data_container.cpp b/core/io/packed_data_container.cpp
index ce4edb18fe..11b0c69774 100644
--- a/core/io/packed_data_container.cpp
+++ b/core/io/packed_data_container.cpp
@@ -125,7 +125,7 @@ Variant PackedDataContainer::_get_at_ofs(uint32_t p_ofs, const uint8_t *p_buf, b
uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {
ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0);
const uint8_t *rd = data.ptr();
- ERR_FAIL_COND_V(!rd, 0);
+ ERR_FAIL_NULL_V(rd, 0);
const uint8_t *r = &rd[p_ofs];
uint32_t type = decode_uint32(r);
@@ -135,7 +135,7 @@ uint32_t PackedDataContainer::_type_at_ofs(uint32_t p_ofs) const {
int PackedDataContainer::_size(uint32_t p_ofs) const {
ERR_FAIL_COND_V(p_ofs + 4 > (uint32_t)data.size(), 0);
const uint8_t *rd = data.ptr();
- ERR_FAIL_COND_V(!rd, 0);
+ ERR_FAIL_NULL_V(rd, 0);
const uint8_t *r = &rd[p_ofs];
uint32_t type = decode_uint32(r);
@@ -156,7 +156,7 @@ Variant PackedDataContainer::_key_at_ofs(uint32_t p_ofs, const Variant &p_key, b
const uint8_t *rd = data.ptr();
if (!rd) {
err = true;
- ERR_FAIL_COND_V(!rd, Variant());
+ ERR_FAIL_NULL_V(rd, Variant());
}
const uint8_t *r = &rd[p_ofs];
uint32_t type = decode_uint32(r);
diff --git a/core/io/resource_loader.cpp b/core/io/resource_loader.cpp
index c1a38f0af8..f7915261af 100644
--- a/core/io/resource_loader.cpp
+++ b/core/io/resource_loader.cpp
@@ -1114,7 +1114,7 @@ bool ResourceLoader::add_custom_resource_format_loader(String script_path) {
Object *obj = ClassDB::instantiate(ibt);
- ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + ".");
+ ERR_FAIL_NULL_V_MSG(obj, false, "Cannot instance script as custom resource loader, expected 'ResourceFormatLoader' inheritance, got: " + String(ibt) + ".");
Ref<ResourceFormatLoader> crl = Object::cast_to<ResourceFormatLoader>(obj);
crl->set_script(s);
diff --git a/core/io/resource_saver.cpp b/core/io/resource_saver.cpp
index 6e377847a8..564a54b913 100644
--- a/core/io/resource_saver.cpp
+++ b/core/io/resource_saver.cpp
@@ -241,7 +241,7 @@ bool ResourceSaver::add_custom_resource_format_saver(String script_path) {
Object *obj = ClassDB::instantiate(ibt);
- ERR_FAIL_COND_V_MSG(obj == nullptr, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");
+ ERR_FAIL_NULL_V_MSG(obj, false, "Cannot instance script as custom resource saver, expected 'ResourceFormatSaver' inheritance, got: " + String(ibt) + ".");
Ref<ResourceFormatSaver> crl = Object::cast_to<ResourceFormatSaver>(obj);
crl->set_script(s);
diff --git a/core/io/stream_peer_gzip.cpp b/core/io/stream_peer_gzip.cpp
index 74216f3cff..4daa71a22a 100644
--- a/core/io/stream_peer_gzip.cpp
+++ b/core/io/stream_peer_gzip.cpp
@@ -102,7 +102,7 @@ Error StreamPeerGZIP::_start(bool p_compress, bool p_is_deflate, int buffer_size
}
Error StreamPeerGZIP::_process(uint8_t *p_dst, int p_dst_size, const uint8_t *p_src, int p_src_size, int &r_consumed, int &r_out, bool p_close) {
- ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
z_stream &strm = *(z_stream *)ctx;
strm.avail_in = p_src_size;
strm.avail_out = p_dst_size;
@@ -132,7 +132,7 @@ Error StreamPeerGZIP::put_data(const uint8_t *p_data, int p_bytes) {
}
Error StreamPeerGZIP::put_partial_data(const uint8_t *p_data, int p_bytes, int &r_sent) {
- ERR_FAIL_COND_V(!ctx, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(ctx, ERR_UNCONFIGURED);
ERR_FAIL_COND_V(p_bytes < 0, ERR_INVALID_PARAMETER);
// Ensure we have enough space in temporary buffer.
diff --git a/core/io/xml_parser.cpp b/core/io/xml_parser.cpp
index 958734addf..faf7d75172 100644
--- a/core/io/xml_parser.cpp
+++ b/core/io/xml_parser.cpp
@@ -336,7 +336,7 @@ uint64_t XMLParser::get_node_offset() const {
}
Error XMLParser::seek(uint64_t p_pos) {
- ERR_FAIL_COND_V(!data, ERR_FILE_EOF);
+ ERR_FAIL_NULL_V(data, ERR_FILE_EOF);
ERR_FAIL_COND_V(p_pos >= length, ERR_FILE_EOF);
P = data + p_pos;
@@ -474,7 +474,7 @@ Error XMLParser::open_buffer(const Vector<uint8_t> &p_buffer) {
Error XMLParser::_open_buffer(const uint8_t *p_buffer, size_t p_size) {
ERR_FAIL_COND_V(p_size == 0, ERR_INVALID_DATA);
- ERR_FAIL_COND_V(!p_buffer, ERR_INVALID_DATA);
+ ERR_FAIL_NULL_V(p_buffer, ERR_INVALID_DATA);
if (data_copy) {
memdelete_arr(data_copy);
diff --git a/core/io/zip_io.cpp b/core/io/zip_io.cpp
index a0e6bd62de..a89c6253f1 100644
--- a/core/io/zip_io.cpp
+++ b/core/io/zip_io.cpp
@@ -74,7 +74,7 @@ int godot_unzip_locate_file(unzFile p_zip_file, String p_filepath, bool p_case_s
void *zipio_open(voidpf opaque, const char *p_fname, int mode) {
Ref<FileAccess> *fa = reinterpret_cast<Ref<FileAccess> *>(opaque);
- ERR_FAIL_COND_V(fa == nullptr, nullptr);
+ ERR_FAIL_NULL_V(fa, nullptr);
String fname;
fname.parse_utf8(p_fname);
@@ -100,7 +100,7 @@ void *zipio_open(voidpf opaque, const char *p_fname, int mode) {
uLong zipio_read(voidpf opaque, voidpf stream, void *buf, uLong size) {
Ref<FileAccess> *fa = reinterpret_cast<Ref<FileAccess> *>(opaque);
- ERR_FAIL_COND_V(fa == nullptr, 0);
+ ERR_FAIL_NULL_V(fa, 0);
ERR_FAIL_COND_V(fa->is_null(), 0);
return (*fa)->get_buffer((uint8_t *)buf, size);
@@ -108,7 +108,7 @@ uLong zipio_read(voidpf opaque, voidpf stream, void *buf, uLong size) {
uLong zipio_write(voidpf opaque, voidpf stream, const void *buf, uLong size) {
Ref<FileAccess> *fa = reinterpret_cast<Ref<FileAccess> *>(opaque);
- ERR_FAIL_COND_V(fa == nullptr, 0);
+ ERR_FAIL_NULL_V(fa, 0);
ERR_FAIL_COND_V(fa->is_null(), 0);
(*fa)->store_buffer((uint8_t *)buf, size);
@@ -117,7 +117,7 @@ uLong zipio_write(voidpf opaque, voidpf stream, const void *buf, uLong size) {
long zipio_tell(voidpf opaque, voidpf stream) {
Ref<FileAccess> *fa = reinterpret_cast<Ref<FileAccess> *>(opaque);
- ERR_FAIL_COND_V(fa == nullptr, 0);
+ ERR_FAIL_NULL_V(fa, 0);
ERR_FAIL_COND_V(fa->is_null(), 0);
return (*fa)->get_position();
@@ -125,7 +125,7 @@ long zipio_tell(voidpf opaque, voidpf stream) {
long zipio_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
Ref<FileAccess> *fa = reinterpret_cast<Ref<FileAccess> *>(opaque);
- ERR_FAIL_COND_V(fa == nullptr, 0);
+ ERR_FAIL_NULL_V(fa, 0);
ERR_FAIL_COND_V(fa->is_null(), 0);
uint64_t pos = offset;
@@ -146,7 +146,7 @@ long zipio_seek(voidpf opaque, voidpf stream, uLong offset, int origin) {
int zipio_close(voidpf opaque, voidpf stream) {
Ref<FileAccess> *fa = reinterpret_cast<Ref<FileAccess> *>(opaque);
- ERR_FAIL_COND_V(fa == nullptr, 0);
+ ERR_FAIL_NULL_V(fa, 0);
ERR_FAIL_COND_V(fa->is_null(), 0);
fa->unref();
@@ -155,7 +155,7 @@ int zipio_close(voidpf opaque, voidpf stream) {
int zipio_testerror(voidpf opaque, voidpf stream) {
Ref<FileAccess> *fa = reinterpret_cast<Ref<FileAccess> *>(opaque);
- ERR_FAIL_COND_V(fa == nullptr, 1);
+ ERR_FAIL_NULL_V(fa, 1);
ERR_FAIL_COND_V(fa->is_null(), 0);
return (fa->is_valid() && (*fa)->get_error() != OK) ? 1 : 0;
diff --git a/core/math/a_star_grid_2d.cpp b/core/math/a_star_grid_2d.cpp
index 9ba4c2ff9a..9a3744fef8 100644
--- a/core/math/a_star_grid_2d.cpp
+++ b/core/math/a_star_grid_2d.cpp
@@ -32,8 +32,6 @@
#include "core/variant/typed_array.h"
-#define GET_POINT_UNCHECKED(m_id) points[m_id.y - region.position.y][m_id.x - region.position.x]
-
static real_t heuristic_euclidian(const Vector2i &p_from, const Vector2i &p_to) {
real_t dx = (real_t)ABS(p_to.x - p_from.x);
real_t dy = (real_t)ABS(p_to.y - p_from.y);
@@ -110,19 +108,22 @@ Size2 AStarGrid2D::get_cell_size() const {
void AStarGrid2D::update() {
points.clear();
- const int64_t end_x = region.position.x + region.size.width;
- const int64_t end_y = region.position.y + region.size.height;
- for (int64_t y = region.position.y; y < end_y; y++) {
+
+ const int32_t end_x = region.get_end().x;
+ const int32_t end_y = region.get_end().y;
+
+ for (int32_t y = region.position.y; y < end_y; y++) {
LocalVector<Point> line;
- for (int64_t x = region.position.x; x < end_x; x++) {
+ for (int32_t x = region.position.x; x < end_x; x++) {
line.push_back(Point(Vector2i(x, y), offset + Vector2(x, y) * cell_size));
}
points.push_back(line);
}
+
dirty = false;
}
-bool AStarGrid2D::is_in_bounds(int p_x, int p_y) const {
+bool AStarGrid2D::is_in_bounds(int32_t p_x, int32_t p_y) const {
return region.has_point(Vector2i(p_x, p_y));
}
@@ -172,40 +173,38 @@ AStarGrid2D::Heuristic AStarGrid2D::get_default_estimate_heuristic() const {
void AStarGrid2D::set_point_solid(const Vector2i &p_id, bool p_solid) {
ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set if point is disabled. Point %s out of bounds %s.", p_id, region));
- GET_POINT_UNCHECKED(p_id).solid = p_solid;
+ _get_point_unchecked(p_id)->solid = p_solid;
}
bool AStarGrid2D::is_point_solid(const Vector2i &p_id) const {
ERR_FAIL_COND_V_MSG(dirty, false, "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), false, vformat("Can't get if point is disabled. Point %s out of bounds %s.", p_id, region));
- return GET_POINT_UNCHECKED(p_id).solid;
+ return _get_point_unchecked(p_id)->solid;
}
void AStarGrid2D::set_point_weight_scale(const Vector2i &p_id, real_t p_weight_scale) {
ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_MSG(!is_in_boundsv(p_id), vformat("Can't set point's weight scale. Point %s out of bounds %s.", p_id, region));
ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't set point's weight scale less than 0.0: %f.", p_weight_scale));
- GET_POINT_UNCHECKED(p_id).weight_scale = p_weight_scale;
+ _get_point_unchecked(p_id)->weight_scale = p_weight_scale;
}
real_t AStarGrid2D::get_point_weight_scale(const Vector2i &p_id) const {
ERR_FAIL_COND_V_MSG(dirty, 0, "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), 0, vformat("Can't get point's weight scale. Point %s out of bounds %s.", p_id, region));
- return GET_POINT_UNCHECKED(p_id).weight_scale;
+ return _get_point_unchecked(p_id)->weight_scale;
}
void AStarGrid2D::fill_solid_region(const Rect2i &p_region, bool p_solid) {
ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
- Rect2i safe_region = p_region.intersection(region);
- int from_x = safe_region.get_position().x;
- int from_y = safe_region.get_position().y;
- int end_x = safe_region.get_end().x;
- int end_y = safe_region.get_end().y;
+ const Rect2i safe_region = p_region.intersection(region);
+ const int32_t end_x = safe_region.get_end().x;
+ const int32_t end_y = safe_region.get_end().y;
- for (int x = from_x; x < end_x; x++) {
- for (int y = from_y; y < end_y; y++) {
- GET_POINT_UNCHECKED(Vector2i(x, y)).solid = p_solid;
+ for (int32_t y = safe_region.position.y; y < end_y; y++) {
+ for (int32_t x = safe_region.position.x; x < end_x; x++) {
+ _get_point_unchecked(x, y)->solid = p_solid;
}
}
}
@@ -214,14 +213,13 @@ void AStarGrid2D::fill_weight_scale_region(const Rect2i &p_region, real_t p_weig
ERR_FAIL_COND_MSG(dirty, "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_MSG(p_weight_scale < 0.0, vformat("Can't set point's weight scale less than 0.0: %f.", p_weight_scale));
- Rect2i safe_region = p_region.intersection(region);
- int from_x = safe_region.get_position().x;
- int from_y = safe_region.get_position().y;
- int end_x = safe_region.get_end().x;
- int end_y = safe_region.get_end().y;
- for (int x = from_x; x < end_x; x++) {
- for (int y = from_y; y < end_y; y++) {
- GET_POINT_UNCHECKED(Vector2i(x, y)).weight_scale = p_weight_scale;
+ const Rect2i safe_region = p_region.intersection(region);
+ const int32_t end_x = safe_region.get_end().x;
+ const int32_t end_y = safe_region.get_end().y;
+
+ for (int32_t y = safe_region.position.y; y < end_y; y++) {
+ for (int32_t x = safe_region.position.x; x < end_x; x++) {
+ _get_point_unchecked(x, y)->weight_scale = p_weight_scale;
}
}
}
@@ -234,14 +232,14 @@ AStarGrid2D::Point *AStarGrid2D::_jump(Point *p_from, Point *p_to) {
return p_to;
}
- int64_t from_x = p_from->id.x;
- int64_t from_y = p_from->id.y;
+ int32_t from_x = p_from->id.x;
+ int32_t from_y = p_from->id.y;
- int64_t to_x = p_to->id.x;
- int64_t to_y = p_to->id.y;
+ int32_t to_x = p_to->id.x;
+ int32_t to_y = p_to->id.y;
- int64_t dx = to_x - from_x;
- int64_t dy = to_y - from_y;
+ int32_t dx = to_x - from_x;
+ int32_t dy = to_y - from_y;
if (diagonal_mode == DIAGONAL_MODE_ALWAYS || diagonal_mode == DIAGONAL_MODE_AT_LEAST_ONE_WALKABLE) {
if (dx != 0 && dy != 0) {
@@ -516,7 +514,7 @@ void AStarGrid2D::clear() {
Vector2 AStarGrid2D::get_point_position(const Vector2i &p_id) const {
ERR_FAIL_COND_V_MSG(dirty, Vector2(), "Grid is not initialized. Call the update method.");
ERR_FAIL_COND_V_MSG(!is_in_boundsv(p_id), Vector2(), vformat("Can't get point's position. Point %s out of bounds %s.", p_id, region));
- return GET_POINT_UNCHECKED(p_id).pos;
+ return _get_point_unchecked(p_id)->pos;
}
Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vector2i &p_to_id) {
@@ -542,7 +540,7 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
}
Point *p = end_point;
- int64_t pc = 1;
+ int32_t pc = 1;
while (p != begin_point) {
pc++;
p = p->prev_point;
@@ -555,7 +553,7 @@ Vector<Vector2> AStarGrid2D::get_point_path(const Vector2i &p_from_id, const Vec
Vector2 *w = path.ptrw();
p = end_point;
- int64_t idx = pc - 1;
+ int32_t idx = pc - 1;
while (p != begin_point) {
w[idx--] = p->pos;
p = p->prev_point;
@@ -590,7 +588,7 @@ TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const V
}
Point *p = end_point;
- int64_t pc = 1;
+ int32_t pc = 1;
while (p != begin_point) {
pc++;
p = p->prev_point;
@@ -601,7 +599,7 @@ TypedArray<Vector2i> AStarGrid2D::get_id_path(const Vector2i &p_from_id, const V
{
p = end_point;
- int64_t idx = pc - 1;
+ int32_t idx = pc - 1;
while (p != begin_point) {
path[idx--] = p->id;
p = p->prev_point;
@@ -671,5 +669,3 @@ void AStarGrid2D::_bind_methods() {
BIND_ENUM_CONSTANT(DIAGONAL_MODE_ONLY_IF_NO_OBSTACLES);
BIND_ENUM_CONSTANT(DIAGONAL_MODE_MAX);
}
-
-#undef GET_POINT_UNCHECKED
diff --git a/core/math/a_star_grid_2d.h b/core/math/a_star_grid_2d.h
index ecc9bb01f9..619551b754 100644
--- a/core/math/a_star_grid_2d.h
+++ b/core/math/a_star_grid_2d.h
@@ -105,24 +105,32 @@ private:
uint64_t pass = 1;
private: // Internal routines.
- _FORCE_INLINE_ bool _is_walkable(int64_t p_x, int64_t p_y) const {
+ _FORCE_INLINE_ bool _is_walkable(int32_t p_x, int32_t p_y) const {
if (region.has_point(Vector2i(p_x, p_y))) {
return !points[p_y - region.position.y][p_x - region.position.x].solid;
}
return false;
}
- _FORCE_INLINE_ Point *_get_point(int64_t p_x, int64_t p_y) {
+ _FORCE_INLINE_ Point *_get_point(int32_t p_x, int32_t p_y) {
if (region.has_point(Vector2i(p_x, p_y))) {
return &points[p_y - region.position.y][p_x - region.position.x];
}
return nullptr;
}
- _FORCE_INLINE_ Point *_get_point_unchecked(int64_t p_x, int64_t p_y) {
+ _FORCE_INLINE_ Point *_get_point_unchecked(int32_t p_x, int32_t p_y) {
return &points[p_y - region.position.y][p_x - region.position.x];
}
+ _FORCE_INLINE_ Point *_get_point_unchecked(const Vector2i &p_id) {
+ return &points[p_id.y - region.position.y][p_id.x - region.position.x];
+ }
+
+ _FORCE_INLINE_ const Point *_get_point_unchecked(const Vector2i &p_id) const {
+ return &points[p_id.y - region.position.y][p_id.x - region.position.x];
+ }
+
void _get_nbors(Point *p_point, LocalVector<Point *> &r_nbors);
Point *_jump(Point *p_from, Point *p_to);
bool _solve(Point *p_begin_point, Point *p_end_point);
@@ -151,10 +159,7 @@ public:
void update();
- int get_width() const;
- int get_height() const;
-
- bool is_in_bounds(int p_x, int p_y) const;
+ bool is_in_bounds(int32_t p_x, int32_t p_y) const;
bool is_in_boundsv(const Vector2i &p_id) const;
bool is_dirty() const;
diff --git a/core/math/disjoint_set.h b/core/math/disjoint_set.h
index 78ae77e72c..2ece991fea 100644
--- a/core/math/disjoint_set.h
+++ b/core/math/disjoint_set.h
@@ -134,7 +134,7 @@ void DisjointSet<T, H, C, AL>::get_representatives(Vector<T> &out_representative
template <typename T, class H, class C, class AL>
void DisjointSet<T, H, C, AL>::get_members(Vector<T> &out_members, T representative) {
typename MapT::Iterator rep_itr = elements.find(representative);
- ERR_FAIL_COND(rep_itr == nullptr);
+ ERR_FAIL_NULL(rep_itr);
Element *rep_element = rep_itr->value;
ERR_FAIL_COND(rep_element->parent != rep_element);
diff --git a/core/math/dynamic_bvh.h b/core/math/dynamic_bvh.h
index 21b5340aaa..dbc1cb31de 100644
--- a/core/math/dynamic_bvh.h
+++ b/core/math/dynamic_bvh.h
@@ -190,7 +190,7 @@ private:
_FORCE_INLINE_ bool is_internal() const { return (!is_leaf()); }
_FORCE_INLINE_ int get_index_in_parent() const {
- ERR_FAIL_COND_V(!parent, 0);
+ ERR_FAIL_NULL_V(parent, 0);
return (parent->children[1] == this) ? 1 : 0;
}
void get_max_depth(int depth, int &maxdepth) {
diff --git a/core/math/projection.cpp b/core/math/projection.cpp
index a304318e2e..9d5dc8b4d6 100644
--- a/core/math/projection.cpp
+++ b/core/math/projection.cpp
@@ -408,7 +408,6 @@ real_t Projection::get_z_far() const {
matrix[11] - matrix[10],
matrix[15] - matrix[14]);
- new_plane.normal = -new_plane.normal;
new_plane.normalize();
return new_plane.d;
diff --git a/core/object/class_db.cpp b/core/object/class_db.cpp
index dac8434264..6a6043e42d 100644
--- a/core/object/class_db.cpp
+++ b/core/object/class_db.cpp
@@ -144,7 +144,7 @@ StringName ClassDB::get_compatibility_remapped_class(const StringName &p_class)
StringName ClassDB::_get_parent_class(const StringName &p_class) {
ClassInfo *ti = classes.getptr(p_class);
- ERR_FAIL_COND_V_MSG(!ti, StringName(), "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_NULL_V_MSG(ti, StringName(), "Cannot get class '" + String(p_class) + "'.");
return ti->inherits;
}
@@ -159,7 +159,7 @@ ClassDB::APIType ClassDB::get_api_type(const StringName &p_class) {
ClassInfo *ti = classes.getptr(p_class);
- ERR_FAIL_COND_V_MSG(!ti, API_NONE, "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_NULL_V_MSG(ti, API_NONE, "Cannot get class '" + String(p_class) + "'.");
return ti->api;
}
@@ -180,7 +180,7 @@ uint32_t ClassDB::get_api_hash(APIType p_api) {
for (const StringName &E : class_list) {
ClassInfo *t = classes.getptr(E);
- ERR_FAIL_COND_V_MSG(!t, 0, "Cannot get class '" + String(E) + "'.");
+ ERR_FAIL_NULL_V_MSG(t, 0, "Cannot get class '" + String(E) + "'.");
if (t->api != p_api || !t->exposed) {
continue;
}
@@ -279,7 +279,7 @@ uint32_t ClassDB::get_api_hash(APIType p_api) {
for (const StringName &F : snames) {
PropertySetGet *psg = t->property_setget.getptr(F);
- ERR_FAIL_COND_V(!psg, 0);
+ ERR_FAIL_NULL_V(psg, 0);
hash = hash_murmur3_one_64(F.hash(), hash);
hash = hash_murmur3_one_64(psg->setter.hash(), hash);
@@ -337,9 +337,9 @@ Object *ClassDB::instantiate(const StringName &p_class) {
ti = classes.getptr(compat_classes[p_class]);
}
}
- ERR_FAIL_COND_V_MSG(!ti, nullptr, "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_NULL_V_MSG(ti, nullptr, "Cannot get class '" + String(p_class) + "'.");
ERR_FAIL_COND_V_MSG(ti->disabled, nullptr, "Class '" + String(p_class) + "' is disabled.");
- ERR_FAIL_COND_V_MSG(!ti->creation_func, nullptr, "Class '" + String(p_class) + "' or its base class cannot be instantiated.");
+ ERR_FAIL_NULL_V_MSG(ti->creation_func, nullptr, "Class '" + String(p_class) + "' or its base class cannot be instantiated.");
}
#ifdef TOOLS_ENABLED
if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
@@ -355,7 +355,7 @@ Object *ClassDB::instantiate(const StringName &p_class) {
}
void ClassDB::set_object_extension_instance(Object *p_object, const StringName &p_class, GDExtensionClassInstancePtr p_instance) {
- ERR_FAIL_COND(!p_object);
+ ERR_FAIL_NULL(p_object);
ClassInfo *ti;
{
OBJTYPE_RLOCK;
@@ -365,9 +365,9 @@ void ClassDB::set_object_extension_instance(Object *p_object, const StringName &
ti = classes.getptr(compat_classes[p_class]);
}
}
- ERR_FAIL_COND_MSG(!ti, "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_NULL_MSG(ti, "Cannot get class '" + String(p_class) + "'.");
ERR_FAIL_COND_MSG(ti->disabled, "Class '" + String(p_class) + "' is disabled.");
- ERR_FAIL_COND_MSG(!ti->gdextension, "Class '" + String(p_class) + "' has no native extension.");
+ ERR_FAIL_NULL_MSG(ti->gdextension, "Class '" + String(p_class) + "' has no native extension.");
}
p_object->_extension = ti->gdextension;
@@ -378,7 +378,7 @@ bool ClassDB::can_instantiate(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
- ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'.");
#ifdef TOOLS_ENABLED
if (ti->api == API_EDITOR && !Engine::get_singleton()->is_editor_hint()) {
return false;
@@ -622,7 +622,7 @@ void ClassDB::bind_integer_constant(const StringName &p_class, const StringName
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
if (type->constant_map.has(p_name)) {
ERR_FAIL();
@@ -791,7 +791,7 @@ void ClassDB::set_method_error_return_values(const StringName &p_class, const St
#ifdef DEBUG_METHODS_ENABLED
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
type->method_error_values[p_method] = p_values;
#endif
@@ -801,7 +801,7 @@ Vector<Error> ClassDB::get_method_error_return_values(const StringName &p_class,
#ifdef DEBUG_METHODS_ENABLED
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND_V(!type, Vector<Error>());
+ ERR_FAIL_NULL_V(type, Vector<Error>());
if (!type->method_error_values.has(p_method)) {
return Vector<Error>();
@@ -854,7 +854,7 @@ void ClassDB::add_signal(const StringName &p_class, const MethodInfo &p_signal)
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
StringName sname = p_signal.name;
@@ -873,7 +873,7 @@ void ClassDB::get_signal_list(const StringName &p_class, List<MethodInfo> *p_sig
OBJTYPE_RLOCK;
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
ClassInfo *check = type;
@@ -927,7 +927,7 @@ bool ClassDB::get_signal(const StringName &p_class, const StringName &p_signal,
void ClassDB::add_property_group(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
String prefix = p_prefix;
if (p_indent_depth > 0) {
@@ -940,7 +940,7 @@ void ClassDB::add_property_group(const StringName &p_class, const String &p_name
void ClassDB::add_property_subgroup(const StringName &p_class, const String &p_name, const String &p_prefix, int p_indent_depth) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
String prefix = p_prefix;
if (p_indent_depth > 0) {
@@ -957,7 +957,7 @@ void ClassDB::add_property_array_count(const StringName &p_class, const String &
void ClassDB::add_property_array(const StringName &p_class, const StringName &p_path, const String &p_array_element_prefix) {
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
type->property_list.push_back(PropertyInfo(Variant::NIL, p_path, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_EDITOR | PROPERTY_USAGE_ARRAY, p_array_element_prefix));
}
@@ -968,14 +968,14 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
ClassInfo *type = classes.getptr(p_class);
lock.read_unlock();
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
MethodBind *mb_set = nullptr;
if (p_setter) {
mb_set = get_method(p_class, p_setter);
#ifdef DEBUG_METHODS_ENABLED
- ERR_FAIL_COND_MSG(!mb_set, "Invalid setter '" + p_class + "::" + p_setter + "' for property '" + p_pinfo.name + "'.");
+ ERR_FAIL_NULL_MSG(mb_set, "Invalid setter '" + p_class + "::" + p_setter + "' for property '" + p_pinfo.name + "'.");
int exp_args = 1 + (p_index >= 0 ? 1 : 0);
ERR_FAIL_COND_MSG(mb_set->get_argument_count() != exp_args, "Invalid function for setter '" + p_class + "::" + p_setter + " for property '" + p_pinfo.name + "'.");
@@ -987,7 +987,7 @@ void ClassDB::add_property(const StringName &p_class, const PropertyInfo &p_pinf
mb_get = get_method(p_class, p_getter);
#ifdef DEBUG_METHODS_ENABLED
- ERR_FAIL_COND_MSG(!mb_get, "Invalid getter '" + p_class + "::" + p_getter + "' for property '" + p_pinfo.name + "'.");
+ ERR_FAIL_NULL_MSG(mb_get, "Invalid getter '" + p_class + "::" + p_getter + "' for property '" + p_pinfo.name + "'.");
int exp_args = 0 + (p_index >= 0 ? 1 : 0);
ERR_FAIL_COND_MSG(mb_get->get_argument_count() != exp_args, "Invalid function for getter '" + p_class + "::" + p_getter + "' for property: '" + p_pinfo.name + "'.");
@@ -1032,7 +1032,7 @@ void ClassDB::add_linked_property(const StringName &p_class, const String &p_pro
#ifdef TOOLS_ENABLED
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
- ERR_FAIL_COND(!type);
+ ERR_FAIL_NULL(type);
ERR_FAIL_COND(!type->property_map.has(p_property));
ERR_FAIL_COND(!type->property_map.has(p_linked_property));
@@ -1307,7 +1307,7 @@ void ClassDB::set_method_flags(const StringName &p_class, const StringName &p_me
OBJTYPE_WLOCK;
ClassInfo *type = classes.getptr(p_class);
ClassInfo *check = type;
- ERR_FAIL_COND(!check);
+ ERR_FAIL_NULL(check);
ERR_FAIL_COND(!check->method_map.has(p_method));
check->method_map[p_method]->set_hint_flags(p_flags);
}
@@ -1375,7 +1375,7 @@ MethodBind *ClassDB::_bind_vararg_method(MethodBind *p_bind, const StringName &p
ClassInfo *type = classes.getptr(instance_type);
if (!type) {
memdelete(bind);
- ERR_FAIL_COND_V(!type, nullptr);
+ ERR_FAIL_NULL_V(type, nullptr);
}
if (p_compatibility) {
@@ -1407,7 +1407,7 @@ MethodBind *ClassDB::bind_methodfi(uint32_t p_flags, MethodBind *p_bind, bool p_
#endif
OBJTYPE_WLOCK;
- ERR_FAIL_COND_V(!p_bind, nullptr);
+ ERR_FAIL_NULL_V(p_bind, nullptr);
p_bind->set_name(mdname);
String instance_type = p_bind->get_instance_class();
@@ -1533,7 +1533,7 @@ bool ClassDB::is_class_enabled(const StringName &p_class) {
}
}
- ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'.");
return !ti->disabled;
}
@@ -1541,7 +1541,7 @@ bool ClassDB::is_class_exposed(const StringName &p_class) {
OBJTYPE_RLOCK;
ClassInfo *ti = classes.getptr(p_class);
- ERR_FAIL_COND_V_MSG(!ti, false, "Cannot get class '" + String(p_class) + "'.");
+ ERR_FAIL_NULL_V_MSG(ti, false, "Cannot get class '" + String(p_class) + "'.");
return ti->exposed;
}
@@ -1675,14 +1675,21 @@ void ClassDB::register_extension_class(ObjectGDExtension *p_extension) {
c.inherits = parent->name;
c.class_ptr = parent->class_ptr;
c.inherits_ptr = parent;
- c.exposed = true;
+ c.exposed = p_extension->is_exposed;
+ if (c.exposed) {
+ // The parent classes should be exposed if it has an exposed child class.
+ while (parent && !parent->exposed) {
+ parent->exposed = true;
+ parent = classes.getptr(parent->name);
+ }
+ }
classes[p_extension->class_name] = c;
}
void ClassDB::unregister_extension_class(const StringName &p_class) {
ClassInfo *c = classes.getptr(p_class);
- ERR_FAIL_COND_MSG(!c, "Class " + p_class + "does not exist");
+ ERR_FAIL_NULL_MSG(c, "Class '" + String(p_class) + "' does not exist.");
for (KeyValue<StringName, MethodBind *> &F : c->method_map) {
memdelete(F.value);
}
diff --git a/core/object/class_db.h b/core/object/class_db.h
index 57469f03d2..b112cddf38 100644
--- a/core/object/class_db.h
+++ b/core/object/class_db.h
@@ -190,7 +190,7 @@ public:
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
- ERR_FAIL_COND(!t);
+ ERR_FAIL_NULL(t);
t->creation_func = &creator<T>;
t->exposed = true;
t->is_virtual = p_virtual;
@@ -205,13 +205,28 @@ public:
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
- ERR_FAIL_COND(!t);
+ ERR_FAIL_NULL(t);
t->exposed = true;
t->class_ptr = T::get_class_ptr_static();
t->api = current_api;
//nothing
}
+ template <class T>
+ static void register_internal_class() {
+ GLOBAL_LOCK_FUNCTION;
+ static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
+ T::initialize_class();
+ ClassInfo *t = classes.getptr(T::get_class_static());
+ ERR_FAIL_NULL(t);
+ t->creation_func = &creator<T>;
+ t->exposed = false;
+ t->is_virtual = false;
+ t->class_ptr = T::get_class_ptr_static();
+ t->api = current_api;
+ T::register_custom_data_to_otdb();
+ }
+
static void register_extension_class(ObjectGDExtension *p_extension);
static void unregister_extension_class(const StringName &p_class);
@@ -226,7 +241,7 @@ public:
static_assert(TypesAreSame<typename T::self_type, T>::value, "Class not declared properly, please use GDCLASS.");
T::initialize_class();
ClassInfo *t = classes.getptr(T::get_class_static());
- ERR_FAIL_COND(!t);
+ ERR_FAIL_NULL(t);
t->creation_func = &_create_ptr_func<T>;
t->exposed = true;
t->class_ptr = T::get_class_ptr_static();
@@ -332,7 +347,7 @@ public:
GLOBAL_LOCK_FUNCTION;
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
- ERR_FAIL_COND_V(!bind, nullptr);
+ ERR_FAIL_NULL_V(bind, nullptr);
if constexpr (std::is_same<typename member_function_traits<M>::return_type, Object *>::value) {
bind->set_return_type_is_raw_object_ptr(true);
@@ -345,7 +360,7 @@ public:
GLOBAL_LOCK_FUNCTION;
MethodBind *bind = create_vararg_method_bind(p_method, p_info, p_return_nil_is_variant);
- ERR_FAIL_COND_V(!bind, nullptr);
+ ERR_FAIL_NULL_V(bind, nullptr);
if constexpr (std::is_same<typename member_function_traits<M>::return_type, Object *>::value) {
bind->set_return_type_is_raw_object_ptr(true);
@@ -483,6 +498,10 @@ _FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
if (m_class::_class_is_enabled) { \
::ClassDB::register_abstract_class<m_class>(); \
}
+#define GDREGISTER_INTERNAL_CLASS(m_class) \
+ if (m_class::_class_is_enabled) { \
+ ::ClassDB::register_internal_class<m_class>(); \
+ }
#define GDREGISTER_NATIVE_STRUCT(m_class, m_code) ClassDB::register_native_struct(#m_class, m_code, sizeof(m_class))
diff --git a/core/object/make_virtuals.py b/core/object/make_virtuals.py
index 38682d6d92..c2e69dc8e2 100644
--- a/core/object/make_virtuals.py
+++ b/core/object/make_virtuals.py
@@ -2,7 +2,7 @@ proto = """
#define GDVIRTUAL$VER($RET m_name $ARG) \\
StringName _gdvirtual_##m_name##_sn = #m_name;\\
mutable bool _gdvirtual_##m_name##_initialized = false;\\
-mutable GDExtensionClassCallVirtual _gdvirtual_##m_name = nullptr;\\
+mutable void* _gdvirtual_##m_name = nullptr;\\
template<bool required>\\
_FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
ScriptInstance *_script_instance = ((Object*)(this))->get_script_instance();\\
@@ -16,15 +16,24 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_call($CALLARGS) $CONST { \\
} \\
}\\
if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
- /* TODO: C-style cast because GDExtensionStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
- _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDExtensionStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDExtensionClassCallVirtual) nullptr;\\
+ _gdvirtual_##m_name = nullptr;\\
+ if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\
+ _gdvirtual_##m_name = _get_extension()->get_virtual_call_data(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\
+ } else if (_get_extension()->get_virtual) {\\
+ _gdvirtual_##m_name = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\
+ }\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
$CALLPTRARGS\\
$CALLPTRRETDEF\\
- _gdvirtual_##m_name(_get_extension_instance(),$CALLPTRARGPASS,$CALLPTRRETPASS);\\
- $CALLPTRRET\\
+ if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\
+ _get_extension()->call_virtual_with_data(_get_extension_instance(), &_gdvirtual_##m_name##_sn, _gdvirtual_##m_name, $CALLPTRARGPASS,$CALLPTRRETPASS);\\
+ $CALLPTRRET\\
+ } else {\\
+ ((GDExtensionClassCallVirtual)_gdvirtual_##m_name)(_get_extension_instance(),$CALLPTRARGPASS,$CALLPTRRETPASS);\\
+ $CALLPTRRET\\
+ }\\
return true;\\
}\\
\\
@@ -41,8 +50,12 @@ _FORCE_INLINE_ bool _gdvirtual_##m_name##_overridden() const { \\
return _script_instance->has_method(_gdvirtual_##m_name##_sn);\\
}\\
if (unlikely(_get_extension() && !_gdvirtual_##m_name##_initialized)) {\\
- /* TODO: C-style cast because GDExtensionStringNamePtr's const qualifier is broken (see https://github.com/godotengine/godot/pull/67751) */\\
- _gdvirtual_##m_name = (_get_extension() && _get_extension()->get_virtual) ? _get_extension()->get_virtual(_get_extension()->class_userdata, (GDExtensionStringNamePtr)&_gdvirtual_##m_name##_sn) : (GDExtensionClassCallVirtual) nullptr;\\
+ _gdvirtual_##m_name = nullptr;\\
+ if (_get_extension()->get_virtual_call_data && _get_extension()->call_virtual_with_data) {\\
+ _gdvirtual_##m_name = _get_extension()->get_virtual_call_data(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\
+ } else if (_get_extension()->get_virtual) {\\
+ _gdvirtual_##m_name = (void *)_get_extension()->get_virtual(_get_extension()->class_userdata, &_gdvirtual_##m_name##_sn);\\
+ }\\
_gdvirtual_##m_name##_initialized = true;\\
}\\
if (_gdvirtual_##m_name) {\\
diff --git a/core/object/object.cpp b/core/object/object.cpp
index 0a0953f7dc..3fd7fe36e0 100644
--- a/core/object/object.cpp
+++ b/core/object/object.cpp
@@ -527,6 +527,27 @@ void Object::get_property_list(List<PropertyInfo> *p_list, bool p_reversed) cons
void Object::validate_property(PropertyInfo &p_property) const {
_validate_propertyv(p_property);
+ if (_extension && _extension->validate_property) {
+ // GDExtension uses a StringName rather than a String for property name.
+ StringName prop_name = p_property.name;
+ GDExtensionPropertyInfo gdext_prop = {
+ (GDExtensionVariantType)p_property.type,
+ &prop_name,
+ &p_property.class_name,
+ (uint32_t)p_property.hint,
+ &p_property.hint_string,
+ p_property.usage,
+ };
+ if (_extension->validate_property(_extension_instance, &gdext_prop)) {
+ p_property.type = (Variant::Type)gdext_prop.type;
+ p_property.name = *reinterpret_cast<StringName *>(gdext_prop.name);
+ p_property.class_name = *reinterpret_cast<StringName *>(gdext_prop.class_name);
+ p_property.hint = (PropertyHint)gdext_prop.hint;
+ p_property.hint_string = *reinterpret_cast<String *>(gdext_prop.hint_string);
+ p_property.usage = gdext_prop.usage;
+ };
+ }
+
if (script_instance) { // Call it last to allow user altering already validated properties.
script_instance->validate_property(p_property);
}
@@ -846,7 +867,7 @@ String Object::to_string() {
void Object::set_script_and_instance(const Variant &p_script, ScriptInstance *p_instance) {
//this function is not meant to be used in any of these ways
ERR_FAIL_COND(p_script.is_null());
- ERR_FAIL_COND(!p_instance);
+ ERR_FAIL_NULL(p_instance);
ERR_FAIL_COND(script_instance != nullptr || !script.is_null());
script = p_script;
@@ -1279,7 +1300,7 @@ Error Object::connect(const StringName &p_signal, const Callable &p_callable, ui
ERR_FAIL_COND_V_MSG(p_callable.is_null(), ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "': the provided callable is null.");
Object *target_object = p_callable.get_object();
- ERR_FAIL_COND_V_MSG(!target_object, ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null.");
+ ERR_FAIL_NULL_V_MSG(target_object, ERR_INVALID_PARAMETER, "Cannot connect to '" + p_signal + "' to callable '" + p_callable + "': the callable object is null.");
SignalData *s = signal_map.getptr(p_signal);
if (!s) {
@@ -1364,7 +1385,7 @@ bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
ERR_FAIL_COND_V_MSG(p_callable.is_null(), false, "Cannot disconnect from '" + p_signal + "': the provided callable is null.");
Object *target_object = p_callable.get_object();
- ERR_FAIL_COND_V_MSG(!target_object, false, "Cannot disconnect '" + p_signal + "' from callable '" + p_callable + "': the callable object is null.");
+ ERR_FAIL_NULL_V_MSG(target_object, false, "Cannot disconnect '" + p_signal + "' from callable '" + p_callable + "': the callable object is null.");
SignalData *s = signal_map.getptr(p_signal);
if (!s) {
@@ -1372,7 +1393,7 @@ bool Object::_disconnect(const StringName &p_signal, const Callable &p_callable,
(!script.is_null() && Ref<Script>(script)->has_script_signal(p_signal));
ERR_FAIL_COND_V_MSG(signal_is_valid, false, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'.");
}
- ERR_FAIL_COND_V_MSG(!s, false, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string()));
+ ERR_FAIL_NULL_V_MSG(s, false, vformat("Disconnecting nonexistent signal '%s' in %s.", p_signal, to_string()));
ERR_FAIL_COND_V_MSG(!s->slot_map.has(*p_callable.get_base_comparator()), false, "Attempt to disconnect a nonexistent connection from '" + to_string() + "'. Signal: '" + p_signal + "', callable: '" + p_callable + "'.");
diff --git a/core/object/object.h b/core/object/object.h
index 309cd34c4b..7da1c68edf 100644
--- a/core/object/object.h
+++ b/core/object/object.h
@@ -315,12 +315,14 @@ struct ObjectGDExtension {
bool editor_class = false;
bool is_virtual = false;
bool is_abstract = false;
+ bool is_exposed = true;
GDExtensionClassSet set;
GDExtensionClassGet get;
GDExtensionClassGetPropertyList get_property_list;
GDExtensionClassFreePropertyList free_property_list;
GDExtensionClassPropertyCanRevert property_can_revert;
GDExtensionClassPropertyGetRevert property_get_revert;
+ GDExtensionClassValidateProperty validate_property;
#ifndef DISABLE_DEPRECATED
GDExtensionClassNotification notification;
#endif // DISABLE_DEPRECATED
@@ -345,6 +347,8 @@ struct ObjectGDExtension {
GDExtensionClassCreateInstance create_instance;
GDExtensionClassFreeInstance free_instance;
GDExtensionClassGetVirtual get_virtual;
+ GDExtensionClassGetVirtualCallData get_virtual_call_data;
+ GDExtensionClassCallVirtualWithData call_virtual_with_data;
};
#define GDVIRTUAL_CALL(m_name, ...) _gdvirtual_##m_name##_call<false>(__VA_ARGS__)
diff --git a/core/object/ref_counted.h b/core/object/ref_counted.h
index 3386514706..228373d662 100644
--- a/core/object/ref_counted.h
+++ b/core/object/ref_counted.h
@@ -71,7 +71,7 @@ class Ref {
}
void ref_pointer(T *p_ref) {
- ERR_FAIL_COND(!p_ref);
+ ERR_FAIL_NULL(p_ref);
if (p_ref->init_ref()) {
reference = p_ref;
diff --git a/core/object/script_language_extension.h b/core/object/script_language_extension.h
index c7218d99a6..e06f005320 100644
--- a/core/object/script_language_extension.h
+++ b/core/object/script_language_extension.h
@@ -689,9 +689,11 @@ public:
}
virtual void validate_property(PropertyInfo &p_property) const override {
if (native_info->validate_property_func) {
+ // GDExtension uses a StringName rather than a String for property name.
+ StringName prop_name = p_property.name;
GDExtensionPropertyInfo gdext_prop = {
(GDExtensionVariantType)p_property.type,
- &p_property.name,
+ &prop_name,
&p_property.class_name,
(uint32_t)p_property.hint,
&p_property.hint_string,
diff --git a/core/object/undo_redo.cpp b/core/object/undo_redo.cpp
index f04961c760..b0f9501985 100644
--- a/core/object/undo_redo.cpp
+++ b/core/object/undo_redo.cpp
@@ -178,7 +178,7 @@ void UndoRedo::add_undo_method(const Callable &p_callable) {
}
void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, const Variant &p_value) {
- ERR_FAIL_COND(p_object == nullptr);
+ ERR_FAIL_NULL(p_object);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
@@ -194,7 +194,7 @@ void UndoRedo::add_do_property(Object *p_object, const StringName &p_property, c
}
void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property, const Variant &p_value) {
- ERR_FAIL_COND(p_object == nullptr);
+ ERR_FAIL_NULL(p_object);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
@@ -217,7 +217,7 @@ void UndoRedo::add_undo_property(Object *p_object, const StringName &p_property,
}
void UndoRedo::add_do_reference(Object *p_object) {
- ERR_FAIL_COND(p_object == nullptr);
+ ERR_FAIL_NULL(p_object);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
Operation do_op;
@@ -231,7 +231,7 @@ void UndoRedo::add_do_reference(Object *p_object) {
}
void UndoRedo::add_undo_reference(Object *p_object) {
- ERR_FAIL_COND(p_object == nullptr);
+ ERR_FAIL_NULL(p_object);
ERR_FAIL_COND(action_level <= 0);
ERR_FAIL_COND((current_action + 1) >= actions.size());
diff --git a/core/object/worker_thread_pool.cpp b/core/object/worker_thread_pool.cpp
index 5ec3e1a1a8..cfc3ac3bcf 100644
--- a/core/object/worker_thread_pool.cpp
+++ b/core/object/worker_thread_pool.cpp
@@ -34,8 +34,8 @@
#include "core/os/thread_safe.h"
void WorkerThreadPool::Task::free_template_userdata() {
- ERR_FAIL_COND(!template_userdata);
- ERR_FAIL_COND(native_func_userdata == nullptr);
+ ERR_FAIL_NULL(template_userdata);
+ ERR_FAIL_NULL(native_func_userdata);
BaseTemplateUserdata *btu = (BaseTemplateUserdata *)native_func_userdata;
memdelete(btu);
}
diff --git a/core/os/memory.cpp b/core/os/memory.cpp
index 0d15b8dcf5..5f6216a5f1 100644
--- a/core/os/memory.cpp
+++ b/core/os/memory.cpp
@@ -74,7 +74,7 @@ void *Memory::alloc_static(size_t p_bytes, bool p_pad_align) {
void *mem = malloc(p_bytes + (prepad ? PAD_ALIGN : 0));
- ERR_FAIL_COND_V(!mem, nullptr);
+ ERR_FAIL_NULL_V(mem, nullptr);
alloc_count.increment();
@@ -127,7 +127,7 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
*s = p_bytes;
mem = (uint8_t *)realloc(mem, p_bytes + PAD_ALIGN);
- ERR_FAIL_COND_V(!mem, nullptr);
+ ERR_FAIL_NULL_V(mem, nullptr);
s = (uint64_t *)mem;
@@ -145,7 +145,7 @@ void *Memory::realloc_static(void *p_memory, size_t p_bytes, bool p_pad_align) {
}
void Memory::free_static(void *p_ptr, bool p_pad_align) {
- ERR_FAIL_COND(p_ptr == nullptr);
+ ERR_FAIL_NULL(p_ptr);
uint8_t *mem = (uint8_t *)p_ptr;
diff --git a/core/os/memory.h b/core/os/memory.h
index 45019894b1..a0524b0ea2 100644
--- a/core/os/memory.h
+++ b/core/os/memory.h
@@ -144,7 +144,7 @@ T *memnew_arr_template(size_t p_elements) {
size_t len = sizeof(T) * p_elements;
uint64_t *mem = (uint64_t *)Memory::alloc_static(len, true);
T *failptr = nullptr; //get rid of a warning
- ERR_FAIL_COND_V(!mem, failptr);
+ ERR_FAIL_NULL_V(mem, failptr);
*(mem - 1) = p_elements;
if (!std::is_trivially_constructible<T>::value) {
diff --git a/core/os/pool_allocator.cpp b/core/os/pool_allocator.cpp
index c23196efdb..acbaed4ce8 100644
--- a/core/os/pool_allocator.cpp
+++ b/core/os/pool_allocator.cpp
@@ -305,7 +305,7 @@ Error PoolAllocator::resize(ID p_mem, int p_new_size) {
if (!e) {
mt_unlock();
- ERR_FAIL_COND_V(!e, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(e, ERR_INVALID_PARAMETER);
}
if (needs_locking && e->lock) {
@@ -431,7 +431,7 @@ bool PoolAllocator::is_locked(ID p_mem) const {
const void *PoolAllocator::get(ID p_mem) const {
if (!needs_locking) {
const Entry *e = get_entry(p_mem);
- ERR_FAIL_COND_V(!e, nullptr);
+ ERR_FAIL_NULL_V(e, nullptr);
return &pool[e->pos];
}
@@ -440,7 +440,7 @@ const void *PoolAllocator::get(ID p_mem) const {
if (!e) {
mt_unlock();
- ERR_FAIL_COND_V(!e, nullptr);
+ ERR_FAIL_NULL_V(e, nullptr);
}
if (e->lock == 0) {
mt_unlock();
@@ -463,7 +463,7 @@ const void *PoolAllocator::get(ID p_mem) const {
void *PoolAllocator::get(ID p_mem) {
if (!needs_locking) {
Entry *e = get_entry(p_mem);
- ERR_FAIL_COND_V(!e, nullptr);
+ ERR_FAIL_NULL_V(e, nullptr);
return &pool[e->pos];
}
@@ -472,7 +472,7 @@ void *PoolAllocator::get(ID p_mem) {
if (!e) {
mt_unlock();
- ERR_FAIL_COND_V(!e, nullptr);
+ ERR_FAIL_NULL_V(e, nullptr);
}
if (e->lock == 0) {
mt_unlock();
@@ -500,7 +500,7 @@ void PoolAllocator::unlock(ID p_mem) {
Entry *e = get_entry(p_mem);
if (!e) {
mt_unlock();
- ERR_FAIL_COND(!e);
+ ERR_FAIL_NULL(e);
}
if (e->lock == 0) {
mt_unlock();
@@ -540,7 +540,7 @@ void PoolAllocator::create_pool(void *p_mem, int p_size, int p_max_entries) {
PoolAllocator::PoolAllocator(int p_size, bool p_needs_locking, int p_max_entries) {
mem_ptr = memalloc(p_size);
- ERR_FAIL_COND(!mem_ptr);
+ ERR_FAIL_NULL(mem_ptr);
align = 1;
create_pool(mem_ptr, p_size, p_max_entries);
needs_locking = p_needs_locking;
diff --git a/core/string/node_path.cpp b/core/string/node_path.cpp
index af7c18741d..32e4564c5e 100644
--- a/core/string/node_path.cpp
+++ b/core/string/node_path.cpp
@@ -73,7 +73,7 @@ int NodePath::get_name_count() const {
}
StringName NodePath::get_name(int p_idx) const {
- ERR_FAIL_COND_V(!data, StringName());
+ ERR_FAIL_NULL_V(data, StringName());
ERR_FAIL_INDEX_V(p_idx, data->path.size(), StringName());
return data->path[p_idx];
}
@@ -87,7 +87,7 @@ int NodePath::get_subname_count() const {
}
StringName NodePath::get_subname(int p_idx) const {
- ERR_FAIL_COND_V(!data, StringName());
+ ERR_FAIL_NULL_V(data, StringName());
ERR_FAIL_INDEX_V(p_idx, data->subpath.size(), StringName());
return data->subpath[p_idx];
}
@@ -200,7 +200,7 @@ Vector<StringName> NodePath::get_subnames() const {
}
StringName NodePath::get_concatenated_names() const {
- ERR_FAIL_COND_V(!data, StringName());
+ ERR_FAIL_NULL_V(data, StringName());
if (!data->concatenated_path) {
int pc = data->path.size();
@@ -215,7 +215,7 @@ StringName NodePath::get_concatenated_names() const {
}
StringName NodePath::get_concatenated_subnames() const {
- ERR_FAIL_COND_V(!data, StringName());
+ ERR_FAIL_NULL_V(data, StringName());
if (!data->concatenated_subpath) {
int spc = data->subpath.size();
diff --git a/core/string/print_string.cpp b/core/string/print_string.cpp
index dcdde3c175..e3614be359 100644
--- a/core/string/print_string.cpp
+++ b/core/string/print_string.cpp
@@ -65,7 +65,7 @@ void remove_print_handler(const PrintHandlerList *p_handler) {
//OS::get_singleton()->print("print handler list is %p\n",print_handler_list);
_global_unlock();
- ERR_FAIL_COND(l == nullptr);
+ ERR_FAIL_NULL(l);
}
void __print_line(String p_string) {
diff --git a/core/string/string_name.cpp b/core/string/string_name.cpp
index 6099fea13f..4402e44ad4 100644
--- a/core/string/string_name.cpp
+++ b/core/string/string_name.cpp
@@ -390,7 +390,7 @@ StringName::StringName(const String &p_name, bool p_static) {
StringName StringName::search(const char *p_name) {
ERR_FAIL_COND_V(!configured, StringName());
- ERR_FAIL_COND_V(!p_name, StringName());
+ ERR_FAIL_NULL_V(p_name, StringName());
if (!p_name[0]) {
return StringName();
}
@@ -426,7 +426,7 @@ StringName StringName::search(const char *p_name) {
StringName StringName::search(const char32_t *p_name) {
ERR_FAIL_COND_V(!configured, StringName());
- ERR_FAIL_COND_V(!p_name, StringName());
+ ERR_FAIL_NULL_V(p_name, StringName());
if (!p_name[0]) {
return StringName();
}
diff --git a/core/templates/command_queue_mt.h b/core/templates/command_queue_mt.h
index b7dd1bae34..7e480653ac 100644
--- a/core/templates/command_queue_mt.h
+++ b/core/templates/command_queue_mt.h
@@ -409,7 +409,7 @@ public:
}
void wait_and_flush() {
- ERR_FAIL_COND(!sync);
+ ERR_FAIL_NULL(sync);
sync->wait();
_flush();
}
diff --git a/core/templates/cowdata.h b/core/templates/cowdata.h
index e33822fedf..46d9797d6c 100644
--- a/core/templates/cowdata.h
+++ b/core/templates/cowdata.h
@@ -90,6 +90,10 @@ private:
}
_FORCE_INLINE_ bool _get_alloc_size_checked(size_t p_elements, size_t *out) const {
+ if (unlikely(p_elements == 0)) {
+ *out = 0;
+ return true;
+ }
#if defined(__GNUC__)
size_t o;
size_t p;
@@ -101,13 +105,12 @@ private:
if (__builtin_add_overflow(o, static_cast<size_t>(32), &p)) {
return false; // No longer allocated here.
}
- return true;
#else
// Speed is more important than correctness here, do the operations unchecked
// and hope for the best.
*out = _get_alloc_size(p_elements);
- return true;
#endif
+ return *out;
}
void _unref(void *p_data);
@@ -286,7 +289,7 @@ Error CowData<T>::resize(int p_size) {
if (current_size == 0) {
// alloc from scratch
uint32_t *ptr = (uint32_t *)Memory::alloc_static(alloc_size, true);
- ERR_FAIL_COND_V(!ptr, ERR_OUT_OF_MEMORY);
+ ERR_FAIL_NULL_V(ptr, ERR_OUT_OF_MEMORY);
*(ptr - 1) = 0; //size, currently none
new (ptr - 2) SafeNumeric<uint32_t>(1); //refcount
@@ -294,7 +297,7 @@ Error CowData<T>::resize(int p_size) {
} else {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
- ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+ ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); //refcount
_ptr = (T *)(_ptrnew);
@@ -324,7 +327,7 @@ Error CowData<T>::resize(int p_size) {
if (alloc_size != current_alloc_size) {
uint32_t *_ptrnew = (uint32_t *)Memory::realloc_static(_ptr, alloc_size, true);
- ERR_FAIL_COND_V(!_ptrnew, ERR_OUT_OF_MEMORY);
+ ERR_FAIL_NULL_V(_ptrnew, ERR_OUT_OF_MEMORY);
new (_ptrnew - 2) SafeNumeric<uint32_t>(rc); //refcount
_ptr = (T *)(_ptrnew);
diff --git a/core/templates/list.h b/core/templates/list.h
index 809d7e1667..6393b942ff 100644
--- a/core/templates/list.h
+++ b/core/templates/list.h
@@ -219,7 +219,7 @@ private:
int size_cache = 0;
bool erase(const Element *p_I) {
- ERR_FAIL_COND_V(!p_I, false);
+ ERR_FAIL_NULL_V(p_I, false);
ERR_FAIL_COND_V(p_I->data != this, false);
if (first == p_I) {
diff --git a/core/templates/paged_array.h b/core/templates/paged_array.h
index 45b90869b9..863e3eef11 100644
--- a/core/templates/paged_array.h
+++ b/core/templates/paged_array.h
@@ -112,7 +112,7 @@ public:
}
void configure(uint32_t p_page_size) {
- ERR_FAIL_COND(page_pool != nullptr); //sanity check
+ ERR_FAIL_COND(page_pool != nullptr); // Safety check.
ERR_FAIL_COND(p_page_size == 0);
page_size = nearest_power_of_2_templated(p_page_size);
}
@@ -185,7 +185,7 @@ public:
uint32_t new_page_count = page_count + 1;
if (unlikely(new_page_count > max_pages_used)) {
- ERR_FAIL_COND(page_pool == nullptr); //sanity check
+ ERR_FAIL_NULL(page_pool); // Safety check.
_grow_page_array(); //keep out of inline
}
@@ -352,7 +352,7 @@ public:
}
void set_page_pool(PagedArrayPool<T> *p_page_pool) {
- ERR_FAIL_COND(max_pages_used > 0); //sanity check
+ ERR_FAIL_COND(max_pages_used > 0); // Safety check.
page_pool = p_page_pool;
page_size_mask = page_pool->get_page_size_mask();
diff --git a/core/templates/rid_owner.h b/core/templates/rid_owner.h
index e2ffabdaf0..e6c62ebf43 100644
--- a/core/templates/rid_owner.h
+++ b/core/templates/rid_owner.h
@@ -211,12 +211,12 @@ public:
}
void initialize_rid(RID p_rid) {
T *mem = get_or_null(p_rid, true);
- ERR_FAIL_COND(!mem);
+ ERR_FAIL_NULL(mem);
memnew_placement(mem, T);
}
void initialize_rid(RID p_rid, const T &p_value) {
T *mem = get_or_null(p_rid, true);
- ERR_FAIL_COND(!mem);
+ ERR_FAIL_NULL(mem);
memnew_placement(mem, T(p_value));
}
@@ -391,7 +391,7 @@ public:
_FORCE_INLINE_ void replace(const RID &p_rid, T *p_new_ptr) {
T **ptr = alloc.get_or_null(p_rid);
- ERR_FAIL_COND(!ptr);
+ ERR_FAIL_NULL(ptr);
*ptr = p_new_ptr;
}
diff --git a/core/typedefs.h b/core/typedefs.h
index 1dcba58188..24c247fd38 100644
--- a/core/typedefs.h
+++ b/core/typedefs.h
@@ -109,7 +109,7 @@ constexpr T ABS(T m_v) {
template <typename T>
constexpr const T SIGN(const T m_v) {
- return m_v == 0 ? 0.0f : (m_v < 0 ? -1.0f : +1.0f);
+ return m_v > 0 ? +1.0f : (m_v < 0 ? -1.0f : 0.0f);
}
template <typename T, typename T2>
diff --git a/core/variant/array.cpp b/core/variant/array.cpp
index 5a0ded6c01..4c9ee68ab5 100644
--- a/core/variant/array.cpp
+++ b/core/variant/array.cpp
@@ -52,7 +52,7 @@ public:
void Array::_ref(const Array &p_from) const {
ArrayPrivate *_fp = p_from._p;
- ERR_FAIL_COND(!_fp); // should NOT happen.
+ ERR_FAIL_NULL(_fp); // Should NOT happen.
if (_fp == _p) {
return; // whatever it is, nothing to do here move along
diff --git a/core/variant/callable.cpp b/core/variant/callable.cpp
index 630873ec2e..d7034f1c00 100644
--- a/core/variant/callable.cpp
+++ b/core/variant/callable.cpp
@@ -465,20 +465,20 @@ Error Signal::emit(const Variant **p_arguments, int p_argcount) const {
Error Signal::connect(const Callable &p_callable, uint32_t p_flags) {
Object *obj = get_object();
- ERR_FAIL_COND_V(!obj, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(obj, ERR_UNCONFIGURED);
return obj->connect(name, p_callable, p_flags);
}
void Signal::disconnect(const Callable &p_callable) {
Object *obj = get_object();
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->disconnect(name, p_callable);
}
bool Signal::is_connected(const Callable &p_callable) const {
Object *obj = get_object();
- ERR_FAIL_COND_V(!obj, false);
+ ERR_FAIL_NULL_V(obj, false);
return obj->is_connected(name, p_callable);
}
@@ -500,7 +500,7 @@ Array Signal::get_connections() const {
}
Signal::Signal(const Object *p_object, const StringName &p_name) {
- ERR_FAIL_COND_MSG(p_object == nullptr, "Object argument to Signal constructor must be non-null");
+ ERR_FAIL_NULL_MSG(p_object, "Object argument to Signal constructor must be non-null.");
object = p_object->get_instance_id();
name = p_name;
diff --git a/core/variant/container_type_validate.h b/core/variant/container_type_validate.h
index ffe1dc90a3..0a23c69cb4 100644
--- a/core/variant/container_type_validate.h
+++ b/core/variant/container_type_validate.h
@@ -113,7 +113,7 @@ struct ContainerTypeValidate {
return true; // This is fine, it's null.
}
Object *object = ObjectDB::get_instance(object_id);
- ERR_FAIL_COND_V_MSG(object == nullptr, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
+ ERR_FAIL_NULL_V_MSG(object, false, "Attempted to " + String(p_operation) + " an invalid (previously freed?) object instance into a '" + String(where) + ".");
#else
Object *object = p_variant;
if (object == nullptr) {
diff --git a/core/variant/dictionary.cpp b/core/variant/dictionary.cpp
index f019273735..2dda9fc1f8 100644
--- a/core/variant/dictionary.cpp
+++ b/core/variant/dictionary.cpp
@@ -248,7 +248,7 @@ void Dictionary::merge(const Dictionary &p_dictionary, bool p_overwrite) {
}
void Dictionary::_unref() const {
- ERR_FAIL_COND(!_p);
+ ERR_FAIL_NULL(_p);
if (_p->refcount.unref()) {
if (_p->read_only) {
memdelete(_p->read_only);
diff --git a/core/variant/method_ptrcall.h b/core/variant/method_ptrcall.h
index cbfb9cc257..79be85cae6 100644
--- a/core/variant/method_ptrcall.h
+++ b/core/variant/method_ptrcall.h
@@ -38,26 +38,26 @@
template <class T>
struct PtrToArg {};
-#define MAKE_PTRARG(m_type) \
- template <> \
- struct PtrToArg<m_type> { \
- _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
- return *reinterpret_cast<const m_type *>(p_ptr); \
- } \
- typedef m_type EncodeT; \
- _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
- *((m_type *)p_ptr) = p_val; \
- } \
- }; \
- template <> \
- struct PtrToArg<const m_type &> { \
- _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
- return *reinterpret_cast<const m_type *>(p_ptr); \
- } \
- typedef m_type EncodeT; \
- _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
- *((m_type *)p_ptr) = p_val; \
- } \
+#define MAKE_PTRARG(m_type) \
+ template <> \
+ struct PtrToArg<m_type> { \
+ _FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
+ return *reinterpret_cast<const m_type *>(p_ptr); \
+ } \
+ typedef m_type EncodeT; \
+ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
+ *((m_type *)p_ptr) = p_val; \
+ } \
+ }; \
+ template <> \
+ struct PtrToArg<const m_type &> { \
+ _FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
+ return *reinterpret_cast<const m_type *>(p_ptr); \
+ } \
+ typedef m_type EncodeT; \
+ _FORCE_INLINE_ static void encode(m_type p_val, void *p_ptr) { \
+ *((m_type *)p_ptr) = p_val; \
+ } \
}
#define MAKE_PTRARGCONV(m_type, m_conv) \
@@ -85,7 +85,7 @@ struct PtrToArg {};
#define MAKE_PTRARG_BY_REFERENCE(m_type) \
template <> \
struct PtrToArg<m_type> { \
- _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
+ _FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
@@ -95,7 +95,7 @@ struct PtrToArg {};
}; \
template <> \
struct PtrToArg<const m_type &> { \
- _FORCE_INLINE_ static m_type convert(const void *p_ptr) { \
+ _FORCE_INLINE_ static const m_type &convert(const void *p_ptr) { \
return *reinterpret_cast<const m_type *>(p_ptr); \
} \
typedef m_type EncodeT; \
diff --git a/core/variant/typed_array.h b/core/variant/typed_array.h
index 055c52aa63..037c5c7c2e 100644
--- a/core/variant/typed_array.h
+++ b/core/variant/typed_array.h
@@ -145,8 +145,7 @@ struct PtrToArg<TypedArray<T>> {
template <class T>
struct PtrToArg<const TypedArray<T> &> {
typedef Array EncodeT;
- _FORCE_INLINE_ static TypedArray<T>
- convert(const void *p_ptr) {
+ _FORCE_INLINE_ static TypedArray<T> convert(const void *p_ptr) {
return TypedArray<T>(*reinterpret_cast<const Array *>(p_ptr));
}
};
diff --git a/core/variant/variant_call.cpp b/core/variant/variant_call.cpp
index 5a405a7080..772a540d22 100644
--- a/core/variant/variant_call.cpp
+++ b/core/variant/variant_call.cpp
@@ -1259,28 +1259,28 @@ bool Variant::has_builtin_method(Variant::Type p_type, const StringName &p_metho
Variant::ValidatedBuiltInMethod Variant::get_validated_builtin_method(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, nullptr);
+ ERR_FAIL_NULL_V(method, nullptr);
return method->validated_call;
}
Variant::PTRBuiltInMethod Variant::get_ptr_builtin_method(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, nullptr);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, nullptr);
+ ERR_FAIL_NULL_V(method, nullptr);
return method->ptrcall;
}
int Variant::get_builtin_method_argument_count(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, 0);
+ ERR_FAIL_NULL_V(method, 0);
return method->argument_count;
}
Variant::Type Variant::get_builtin_method_argument_type(Variant::Type p_type, const StringName &p_method, int p_argument) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, Variant::NIL);
+ ERR_FAIL_NULL_V(method, Variant::NIL);
ERR_FAIL_INDEX_V(p_argument, method->argument_count, Variant::NIL);
return method->get_argument_type(p_argument);
}
@@ -1288,7 +1288,7 @@ Variant::Type Variant::get_builtin_method_argument_type(Variant::Type p_type, co
String Variant::get_builtin_method_argument_name(Variant::Type p_type, const StringName &p_method, int p_argument) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, String());
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, String());
+ ERR_FAIL_NULL_V(method, String());
#ifdef DEBUG_METHODS_ENABLED
ERR_FAIL_INDEX_V(p_argument, method->argument_count, String());
return method->argument_names[p_argument];
@@ -1300,14 +1300,14 @@ String Variant::get_builtin_method_argument_name(Variant::Type p_type, const Str
Vector<Variant> Variant::get_builtin_method_default_arguments(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Vector<Variant>());
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, Vector<Variant>());
+ ERR_FAIL_NULL_V(method, Vector<Variant>());
return method->default_arguments;
}
bool Variant::has_builtin_method_return_value(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, false);
+ ERR_FAIL_NULL_V(method, false);
return method->has_return_type;
}
@@ -1326,35 +1326,35 @@ int Variant::get_builtin_method_count(Variant::Type p_type) {
Variant::Type Variant::get_builtin_method_return_type(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, Variant::NIL);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, Variant::NIL);
+ ERR_FAIL_NULL_V(method, Variant::NIL);
return method->return_type;
}
bool Variant::is_builtin_method_const(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, false);
+ ERR_FAIL_NULL_V(method, false);
return method->is_const;
}
bool Variant::is_builtin_method_static(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, false);
+ ERR_FAIL_NULL_V(method, false);
return method->is_static;
}
bool Variant::is_builtin_method_vararg(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, false);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, false);
+ ERR_FAIL_NULL_V(method, false);
return method->is_vararg;
}
uint32_t Variant::get_builtin_method_hash(Variant::Type p_type, const StringName &p_method) {
ERR_FAIL_INDEX_V(p_type, Variant::VARIANT_MAX, 0);
const VariantBuiltInMethodInfo *method = builtin_method_info[p_type].lookup_ptr(p_method);
- ERR_FAIL_COND_V(!method, 0);
+ ERR_FAIL_NULL_V(method, 0);
uint32_t hash = hash_murmur3_one_32(method->is_const);
hash = hash_murmur3_one_32(method->is_static, hash);
hash = hash_murmur3_one_32(method->is_vararg, hash);
@@ -2569,9 +2569,13 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::VECTOR4I, "ZERO", Vector4i(0, 0, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR4I, "ONE", Vector4i(1, 1, 1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR4I, "MIN", Vector4i(INT32_MIN, INT32_MIN, INT32_MIN, INT32_MIN));
+ _VariantCall::add_variant_constant(Variant::VECTOR4I, "MAX", Vector4i(INT32_MAX, INT32_MAX, INT32_MAX, INT32_MAX));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "ZERO", Vector3i(0, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "ONE", Vector3i(1, 1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "MIN", Vector3i(INT32_MIN, INT32_MIN, INT32_MIN));
+ _VariantCall::add_variant_constant(Variant::VECTOR3I, "MAX", Vector3i(INT32_MAX, INT32_MAX, INT32_MAX));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "LEFT", Vector3i(-1, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "RIGHT", Vector3i(1, 0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR3I, "UP", Vector3i(0, 1, 0));
@@ -2601,6 +2605,8 @@ static void _register_variant_builtin_methods() {
_VariantCall::add_variant_constant(Variant::VECTOR2I, "ZERO", Vector2i(0, 0));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "ONE", Vector2i(1, 1));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "MIN", Vector2i(INT32_MIN, INT32_MIN));
+ _VariantCall::add_variant_constant(Variant::VECTOR2I, "MAX", Vector2i(INT32_MAX, INT32_MAX));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "LEFT", Vector2i(-1, 0));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "RIGHT", Vector2i(1, 0));
_VariantCall::add_variant_constant(Variant::VECTOR2I, "UP", Vector2i(0, -1));
diff --git a/core/variant/variant_op.h b/core/variant/variant_op.h
index fc1f7828a2..9e6367ab6d 100644
--- a/core/variant/variant_op.h
+++ b/core/variant/variant_op.h
@@ -1493,7 +1493,7 @@ public:
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
Object *l = right->get_validated_object();
- ERR_FAIL_COND(l == nullptr);
+ ERR_FAIL_NULL(l);
const String &a = *VariantGetInternalPtr<String>::get_ptr(left);
bool valid;
@@ -1527,7 +1527,7 @@ public:
}
static inline void validated_evaluate(const Variant *left, const Variant *right, Variant *r_ret) {
Object *l = right->get_validated_object();
- ERR_FAIL_COND(l == nullptr);
+ ERR_FAIL_NULL(l);
const StringName &a = *VariantGetInternalPtr<StringName>::get_ptr(left);
bool valid;
diff --git a/core/variant/variant_setget.cpp b/core/variant/variant_setget.cpp
index 30fb5d0e9f..05f7abf32c 100644
--- a/core/variant/variant_setget.cpp
+++ b/core/variant/variant_setget.cpp
@@ -318,7 +318,7 @@ Variant Variant::get_named(const StringName &p_member, bool &r_valid) const {
#ifdef DEBUG_ENABLED
#define NULL_TEST(m_key) \
- ERR_FAIL_COND(!m_key)
+ ERR_FAIL_NULL(m_key)
#else
@@ -1068,7 +1068,7 @@ struct VariantKeyedSetGetObject {
}
static uint32_t ptr_has(const void *base, const void *key) {
const Object *obj = PtrToArg<Object *>::convert(base);
- ERR_FAIL_COND_V(!obj, false);
+ ERR_FAIL_NULL_V(obj, false);
bool valid;
obj->getvar(PtrToArg<Variant>::convert(key), &valid);
return valid;
@@ -1245,7 +1245,7 @@ void Variant::get_property_list(List<PropertyInfo> *p_list) const {
}
} else if (type == OBJECT) {
Object *obj = get_validated_object();
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->get_property_list(p_list);
} else {
diff --git a/core/variant/variant_utility.cpp b/core/variant/variant_utility.cpp
index b51df89bec..0a63749ac5 100644
--- a/core/variant/variant_utility.cpp
+++ b/core/variant/variant_utility.cpp
@@ -752,6 +752,90 @@ int64_t VariantUtilityFunctions::_typeof(const Variant &obj) {
return obj.get_type();
}
+Variant VariantUtilityFunctions::type_convert(const Variant &p_variant, const Variant::Type p_type) {
+ switch (p_type) {
+ case Variant::Type::NIL:
+ return Variant();
+ case Variant::Type::BOOL:
+ return p_variant.operator bool();
+ case Variant::Type::INT:
+ return p_variant.operator int64_t();
+ case Variant::Type::FLOAT:
+ return p_variant.operator double();
+ case Variant::Type::STRING:
+ return p_variant.operator String();
+ case Variant::Type::VECTOR2:
+ return p_variant.operator Vector2();
+ case Variant::Type::VECTOR2I:
+ return p_variant.operator Vector2i();
+ case Variant::Type::RECT2:
+ return p_variant.operator Rect2();
+ case Variant::Type::RECT2I:
+ return p_variant.operator Rect2i();
+ case Variant::Type::VECTOR3:
+ return p_variant.operator Vector3();
+ case Variant::Type::VECTOR3I:
+ return p_variant.operator Vector3i();
+ case Variant::Type::TRANSFORM2D:
+ return p_variant.operator Transform2D();
+ case Variant::Type::VECTOR4:
+ return p_variant.operator Vector4();
+ case Variant::Type::VECTOR4I:
+ return p_variant.operator Vector4i();
+ case Variant::Type::PLANE:
+ return p_variant.operator Plane();
+ case Variant::Type::QUATERNION:
+ return p_variant.operator Quaternion();
+ case Variant::Type::AABB:
+ return p_variant.operator ::AABB();
+ case Variant::Type::BASIS:
+ return p_variant.operator Basis();
+ case Variant::Type::TRANSFORM3D:
+ return p_variant.operator Transform3D();
+ case Variant::Type::PROJECTION:
+ return p_variant.operator Projection();
+ case Variant::Type::COLOR:
+ return p_variant.operator Color();
+ case Variant::Type::STRING_NAME:
+ return p_variant.operator StringName();
+ case Variant::Type::NODE_PATH:
+ return p_variant.operator NodePath();
+ case Variant::Type::RID:
+ return p_variant.operator ::RID();
+ case Variant::Type::OBJECT:
+ return p_variant.operator Object *();
+ case Variant::Type::CALLABLE:
+ return p_variant.operator Callable();
+ case Variant::Type::SIGNAL:
+ return p_variant.operator Signal();
+ case Variant::Type::DICTIONARY:
+ return p_variant.operator Dictionary();
+ case Variant::Type::ARRAY:
+ return p_variant.operator Array();
+ case Variant::Type::PACKED_BYTE_ARRAY:
+ return p_variant.operator PackedByteArray();
+ case Variant::Type::PACKED_INT32_ARRAY:
+ return p_variant.operator PackedInt32Array();
+ case Variant::Type::PACKED_INT64_ARRAY:
+ return p_variant.operator PackedInt64Array();
+ case Variant::Type::PACKED_FLOAT32_ARRAY:
+ return p_variant.operator PackedFloat32Array();
+ case Variant::Type::PACKED_FLOAT64_ARRAY:
+ return p_variant.operator PackedFloat64Array();
+ case Variant::Type::PACKED_STRING_ARRAY:
+ return p_variant.operator PackedStringArray();
+ case Variant::Type::PACKED_VECTOR2_ARRAY:
+ return p_variant.operator PackedVector2Array();
+ case Variant::Type::PACKED_VECTOR3_ARRAY:
+ return p_variant.operator PackedVector3Array();
+ case Variant::Type::PACKED_COLOR_ARRAY:
+ return p_variant.operator PackedColorArray();
+ case Variant::Type::VARIANT_MAX:
+ ERR_PRINT("Invalid type argument to type_convert(), use the TYPE_* constants. Returning the unconverted Variant.");
+ }
+ return p_variant;
+}
+
String VariantUtilityFunctions::str(const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
if (p_arg_count < 1) {
r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
@@ -1615,6 +1699,7 @@ void Variant::_register_variant_utility_functions() {
FUNCBINDVR(weakref, sarray("obj"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDR(_typeof, sarray("variable"), Variant::UTILITY_FUNC_TYPE_GENERAL);
+ FUNCBINDR(type_convert, sarray("variant", "type"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGS(str, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDR(error_string, sarray("error"), Variant::UTILITY_FUNC_TYPE_GENERAL);
FUNCBINDVARARGV(print, sarray(), Variant::UTILITY_FUNC_TYPE_GENERAL);
@@ -1788,7 +1873,7 @@ bool Variant::is_utility_function_vararg(const StringName &p_name) {
uint32_t Variant::get_utility_function_hash(const StringName &p_name) {
const VariantUtilityFunctionInfo *bfi = utility_function_table.lookup_ptr(p_name);
- ERR_FAIL_COND_V(!bfi, 0);
+ ERR_FAIL_NULL_V(bfi, 0);
uint32_t hash = hash_murmur3_one_32(bfi->is_vararg);
hash = hash_murmur3_one_32(bfi->returns_value, hash);
diff --git a/doc/classes/@GlobalScope.xml b/doc/classes/@GlobalScope.xml
index fa3f6e434e..1b43f13e37 100644
--- a/doc/classes/@GlobalScope.xml
+++ b/doc/classes/@GlobalScope.xml
@@ -1168,11 +1168,13 @@
<return type="Variant" />
<param index="0" name="x" type="Variant" />
<description>
- Returns the same type of [Variant] as [param x], with [code]-1[/code] for negative values, [code]1[/code] for positive values, and [code]0[/code] for zeros. Supported types: [int], [float], [Vector2], [Vector2i], [Vector3], [Vector3i], [Vector4], [Vector4i].
+ Returns the same type of [Variant] as [param x], with [code]-1[/code] for negative values, [code]1[/code] for positive values, and [code]0[/code] for zeros. For [code]nan[/code] values it returns 0.
+ Supported types: [int], [float], [Vector2], [Vector2i], [Vector3], [Vector3i], [Vector4], [Vector4i].
[codeblock]
sign(-6.0) # Returns -1
sign(0.0) # Returns 0
sign(6.0) # Returns 1
+ sign(NAN) # Returns 0
sign(Vector3(-6.0, 0.0, 6.0)) # Returns (-1, 0, 1)
[/codeblock]
@@ -1183,11 +1185,12 @@
<return type="float" />
<param index="0" name="x" type="float" />
<description>
- Returns [code]-1.0[/code] if [param x] is negative, [code]1.0[/code] if [param x] is positive, and [code]0.0[/code] if [param x] is zero.
+ Returns [code]-1.0[/code] if [param x] is negative, [code]1.0[/code] if [param x] is positive, and [code]0.0[/code] if [param x] is zero. For [code]nan[/code] values of [param x] it returns 0.0.
[codeblock]
signf(-6.5) # Returns -1.0
signf(0.0) # Returns 0.0
signf(6.5) # Returns 1.0
+ signf(NAN) # Returns 0.0
[/codeblock]
</description>
</method>
@@ -1364,6 +1367,23 @@
[/codeblock]
</description>
</method>
+ <method name="type_convert">
+ <return type="Variant" />
+ <param index="0" name="variant" type="Variant" />
+ <param index="1" name="type" type="int" />
+ <description>
+ Converts the given [param variant] to the given [param type], using the [enum Variant.Type] values. This method is generous with how it handles types, it can automatically convert between array types, convert numeric [String]s to [int], and converting most things to [String].
+ If the type conversion cannot be done, this method will return the default value for that type, for example converting [Rect2] to [Vector2] will always return [code]Vector2.ZERO[/code]. This method will never show error messages as long as [param type] is a valid Variant type.
+ The returned value is a [Variant], but the data inside and the [enum Variant.Type] will be the same as the requested type.
+ [codeblock]
+ type_convert("Hi!", TYPE_INT) # Returns 0
+ type_convert("123", TYPE_INT) # Returns 123
+ type_convert(123.4, TYPE_INT) # Returns 123
+ type_convert(5, TYPE_VECTOR2) # Returns (0, 0)
+ type_convert("Hi!", TYPE_NIL) # Returns null
+ [/codeblock]
+ </description>
+ </method>
<method name="typeof">
<return type="int" />
<param index="0" name="variable" type="Variant" />
diff --git a/doc/classes/AABB.xml b/doc/classes/AABB.xml
index 0aa493361d..a803e4f106 100644
--- a/doc/classes/AABB.xml
+++ b/doc/classes/AABB.xml
@@ -126,7 +126,7 @@
<return type="Vector3" />
<param index="0" name="dir" type="Vector3" />
<description>
- Returns the support point in a given direction. This is useful for collision detection algorithms.
+ Returns the vertex of the AABB that's the farthest in a given direction. This point is commonly known as the support point in collision detection algorithms.
</description>
</method>
<method name="get_volume" qualifiers="const">
diff --git a/doc/classes/AudioServer.xml b/doc/classes/AudioServer.xml
index 5d3d7a0591..21ad817c6c 100644
--- a/doc/classes/AudioServer.xml
+++ b/doc/classes/AudioServer.xml
@@ -317,7 +317,15 @@
<signals>
<signal name="bus_layout_changed">
<description>
- Emitted when the [AudioBusLayout] changes.
+ Emitted when an audio bus is added, deleted, or moved.
+ </description>
+ </signal>
+ <signal name="bus_renamed">
+ <param index="0" name="bus_index" type="int" />
+ <param index="1" name="old_name" type="StringName" />
+ <param index="2" name="new_name" type="StringName" />
+ <description>
+ Emitted when the audio bus at [param bus_index] is renamed from [param old_name] to [param new_name].
</description>
</signal>
</signals>
diff --git a/doc/classes/CanvasTexture.xml b/doc/classes/CanvasTexture.xml
index df3f8e8125..1b22adb723 100644
--- a/doc/classes/CanvasTexture.xml
+++ b/doc/classes/CanvasTexture.xml
@@ -8,6 +8,7 @@
[b]Note:[/b] [CanvasTexture] cannot be used in 3D rendering. For physically-based materials in 3D, use [BaseMaterial3D] instead.
</description>
<tutorials>
+ <link title="2D Lights and Shadows">$DOCS_URL/tutorials/2d/2d_lights_and_shadows.html</link>
</tutorials>
<members>
<member name="diffuse_texture" type="Texture2D" setter="set_diffuse_texture" getter="get_diffuse_texture">
diff --git a/doc/classes/CodeEdit.xml b/doc/classes/CodeEdit.xml
index 0e829127f2..d9146cf604 100644
--- a/doc/classes/CodeEdit.xml
+++ b/doc/classes/CodeEdit.xml
@@ -137,6 +137,15 @@
Values of [code]-1[/code] convert the entire text.
</description>
</method>
+ <method name="create_code_region">
+ <return type="void" />
+ <description>
+ Creates a new code region with the selection. At least one single line comment delimiter have to be defined (see [method add_comment_delimiter]).
+ A code region is a part of code that is highlighted when folded and can help organize your script.
+ Code region start and end tags can be customized (see [method set_code_region_tags]).
+ Code regions are delimited using start and end tags (respectively [code]region[/code] and [code]endregion[/code] by default) preceded by one line comment delimiter. (eg. [code]#region[/code] and [code]#endregion[/code])
+ </description>
+ </method>
<method name="do_indent">
<return type="void" />
<description>
@@ -200,6 +209,18 @@
Gets the index of the current selected completion option.
</description>
</method>
+ <method name="get_code_region_end_tag" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the code region end tag (without comment delimiter).
+ </description>
+ </method>
+ <method name="get_code_region_start_tag" qualifiers="const">
+ <return type="String" />
+ <description>
+ Returns the code region start tag (without comment delimiter).
+ </description>
+ </method>
<method name="get_delimiter_end_key" qualifiers="const">
<return type="String" />
<param index="0" name="delimiter_index" type="int" />
@@ -326,6 +347,20 @@
Returns whether the line at the specified index is breakpointed or not.
</description>
</method>
+ <method name="is_line_code_region_end" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="line" type="int" />
+ <description>
+ Returns whether the line at the specified index is a code region end.
+ </description>
+ </method>
+ <method name="is_line_code_region_start" qualifiers="const">
+ <return type="bool" />
+ <param index="0" name="line" type="int" />
+ <description>
+ Returns whether the line at the specified index is a code region start.
+ </description>
+ </method>
<method name="is_line_executing" qualifiers="const">
<return type="bool" />
<param index="0" name="line" type="int" />
@@ -382,6 +417,14 @@
Sets if the code hint should draw below the text.
</description>
</method>
+ <method name="set_code_region_tags">
+ <return type="void" />
+ <param index="0" name="start" type="String" default="&quot;region&quot;" />
+ <param index="1" name="end" type="String" default="&quot;endregion&quot;" />
+ <description>
+ Sets the code region start and end tags (without comment delimiter).
+ </description>
+ </method>
<method name="set_line_as_bookmarked">
<return type="void" />
<param index="0" name="line" type="int" />
@@ -629,6 +672,9 @@
<theme_item name="executing_line_color" data_type="color" type="Color" default="Color(0.98, 0.89, 0.27, 1)">
[Color] of the executing icon for executing lines.
</theme_item>
+ <theme_item name="folded_code_region_color" data_type="color" type="Color" default="Color(0.68, 0.46, 0.77, 0.2)">
+ [Color] of background line highlight for folded code region.
+ </theme_item>
<theme_item name="font_color" data_type="color" type="Color" default="Color(0.875, 0.875, 0.875, 1)">
Sets the font [Color].
</theme_item>
@@ -693,12 +739,18 @@
<theme_item name="can_fold" data_type="icon" type="Texture2D">
Sets a custom [Texture2D] to draw in the line folding gutter when a line can be folded.
</theme_item>
+ <theme_item name="can_fold_code_region" data_type="icon" type="Texture2D">
+ Sets a custom [Texture2D] to draw in the line folding gutter when a code region can be folded.
+ </theme_item>
<theme_item name="executing_line" data_type="icon" type="Texture2D">
Icon to draw in the executing gutter for executing lines.
</theme_item>
<theme_item name="folded" data_type="icon" type="Texture2D">
Sets a custom [Texture2D] to draw in the line folding gutter when a line is folded and can be unfolded.
</theme_item>
+ <theme_item name="folded_code_region" data_type="icon" type="Texture2D">
+ Sets a custom [Texture2D] to draw in the line folding gutter when a code region is folded and can be unfolded.
+ </theme_item>
<theme_item name="folded_eol_icon" data_type="icon" type="Texture2D">
Sets a custom [Texture2D] to draw at the end of a folded line.
</theme_item>
diff --git a/doc/classes/DisplayServer.xml b/doc/classes/DisplayServer.xml
index 44b2d72ebe..579d38666d 100644
--- a/doc/classes/DisplayServer.xml
+++ b/doc/classes/DisplayServer.xml
@@ -1858,16 +1858,16 @@
[b]Note:[/b] This flag is implemented only on macOS.
</constant>
<constant name="VSYNC_DISABLED" value="0" enum="VSyncMode">
- No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible). Framerate is unlimited (nonwithstanding [member Engine.max_fps]).
+ No vertical synchronization, which means the engine will display frames as fast as possible (tearing may be visible). Framerate is unlimited (notwithstanding [member Engine.max_fps]).
</constant>
<constant name="VSYNC_ENABLED" value="1" enum="VSyncMode">
- Default vertical synchronization mode, the image is displayed only on vertical blanking intervals (no tearing is visible). Framerate is limited by the monitor refresh rate (nonwithstanding [member Engine.max_fps]).
+ Default vertical synchronization mode, the image is displayed only on vertical blanking intervals (no tearing is visible). Framerate is limited by the monitor refresh rate (notwithstanding [member Engine.max_fps]).
</constant>
<constant name="VSYNC_ADAPTIVE" value="2" enum="VSyncMode">
- Behaves like [constant VSYNC_DISABLED] when the framerate drops below the screen's refresh rate to reduce stuttering (tearing may be visible). Otherwise, vertical synchronization is enabled to avoid tearing. Framerate is limited by the monitor refresh rate (nonwithstanding [member Engine.max_fps]). Behaves like [constant VSYNC_ENABLED] when using the Compatibility rendering method.
+ Behaves like [constant VSYNC_DISABLED] when the framerate drops below the screen's refresh rate to reduce stuttering (tearing may be visible). Otherwise, vertical synchronization is enabled to avoid tearing. Framerate is limited by the monitor refresh rate (notwithstanding [member Engine.max_fps]). Behaves like [constant VSYNC_ENABLED] when using the Compatibility rendering method.
</constant>
<constant name="VSYNC_MAILBOX" value="3" enum="VSyncMode">
- Displays the most recent image in the queue on vertical blanking intervals, while rendering to the other images (no tearing is visible). Framerate is unlimited (nonwithstanding [member Engine.max_fps]).
+ Displays the most recent image in the queue on vertical blanking intervals, while rendering to the other images (no tearing is visible). Framerate is unlimited (notwithstanding [member Engine.max_fps]).
Although not guaranteed, the images can be rendered as fast as possible, which may reduce input lag (also called "Fast" V-Sync mode). [constant VSYNC_MAILBOX] works best when at least twice as many frames as the display refresh rate are rendered. Behaves like [constant VSYNC_ENABLED] when using the Compatibility rendering method.
</constant>
<constant name="DISPLAY_HANDLE" value="0" enum="HandleType">
@@ -1891,9 +1891,9 @@
</constant>
<constant name="OPENGL_CONTEXT" value="3" enum="HandleType">
OpenGL context (only with the GL Compatibility renderer):
- - Windows: [code]HGLRC[/code] for the window.
+ - Windows: [code]HGLRC[/code] for the window (native GL), or [code]EGLContext[/code] for the window (ANGLE).
- Linux: [code]GLXContext*[/code] for the window.
- - macOS: [code]NSOpenGLContext*[/code] for the window.
+ - macOS: [code]NSOpenGLContext*[/code] for the window (native GL), or [code]EGLContext[/code] for the window (ANGLE).
- Android: [code]EGLContext[/code] for the window.
</constant>
<constant name="TTS_UTTERANCE_STARTED" value="0" enum="TTSUtteranceEvent">
diff --git a/doc/classes/EditorDebuggerPlugin.xml b/doc/classes/EditorDebuggerPlugin.xml
index 6f6b4f69e4..4c602b8359 100644
--- a/doc/classes/EditorDebuggerPlugin.xml
+++ b/doc/classes/EditorDebuggerPlugin.xml
@@ -81,7 +81,7 @@
<return type="Array" />
<description>
Returns an array of [EditorDebuggerSession] currently available to this debugger plugin.
- [b]Note:[/b] Not sessions in the array may be inactive, check their state via [method EditorDebuggerSession.is_active]
+ [b]Note:[/b] Sessions in the array may be inactive, check their state via [method EditorDebuggerSession.is_active].
</description>
</method>
</methods>
diff --git a/doc/classes/EditorInterface.xml b/doc/classes/EditorInterface.xml
index 3ae4b7f812..64a311d857 100644
--- a/doc/classes/EditorInterface.xml
+++ b/doc/classes/EditorInterface.xml
@@ -109,6 +109,13 @@
Returns the editor's [EditorSettings] instance.
</description>
</method>
+ <method name="get_editor_theme" qualifiers="const">
+ <return type="Theme" />
+ <description>
+ Returns the editor's [Theme].
+ [b]Note:[/b] When creating custom editor UI, prefer accessing theme items directly from your GUI nodes using the [code]get_theme_*[/code] methods.
+ </description>
+ </method>
<method name="get_file_system_dock" qualifiers="const">
<return type="FileSystemDock" />
<description>
diff --git a/doc/classes/EditorPlugin.xml b/doc/classes/EditorPlugin.xml
index 8aea15c087..6f858942aa 100644
--- a/doc/classes/EditorPlugin.xml
+++ b/doc/classes/EditorPlugin.xml
@@ -246,7 +246,7 @@
# You can use a custom icon:
return preload("res://addons/my_plugin/my_plugin_icon.svg")
# Or use a built-in icon:
- return EditorInterface.get_base_control().get_theme_icon("Node", "EditorIcons")
+ return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
[/gdscript]
[csharp]
public override Texture2D _GetPluginIcon()
@@ -254,7 +254,7 @@
// You can use a custom icon:
return ResourceLoader.Load&lt;Texture2D&gt;("res://addons/my_plugin/my_plugin_icon.svg");
// Or use a built-in icon:
- return EditorInterface.Singleton.GetBaseControl().GetThemeIcon("Node", "EditorIcons");
+ return EditorInterface.Singleton.GetEditorTheme().GetIcon("Node", "EditorIcons");
}
[/csharp]
[/codeblocks]
@@ -354,7 +354,7 @@
return "My Super Cool Plugin 3000"
func _get_plugin_icon():
- return EditorInterface.get_base_control().get_theme_icon("Node", "EditorIcons")
+ return EditorInterface.get_editor_theme().get_icon("Node", "EditorIcons")
[/codeblock]
</description>
</method>
diff --git a/doc/classes/EditorSettings.xml b/doc/classes/EditorSettings.xml
index aa3bf3c535..5a0cb9fc5e 100644
--- a/doc/classes/EditorSettings.xml
+++ b/doc/classes/EditorSettings.xml
@@ -959,6 +959,9 @@
<member name="text_editor/theme/highlighting/executing_line_color" type="Color" setter="" getter="">
The script editor's color for the debugger's executing line icon (displayed in the gutter).
</member>
+ <member name="text_editor/theme/highlighting/folded_code_region_color" type="Color" setter="" getter="">
+ The script editor's background line highlighting color for folded code region.
+ </member>
<member name="text_editor/theme/highlighting/function_color" type="Color" setter="" getter="">
The script editor's function call color.
[b]Note:[/b] When using the GDScript syntax highlighter, this is replaced by the function definition color configured in the syntax theme for function definitions (e.g. [code]func _ready():[/code]).
diff --git a/doc/classes/Image.xml b/doc/classes/Image.xml
index 5f1f9e6c18..2782e877a9 100644
--- a/doc/classes/Image.xml
+++ b/doc/classes/Image.xml
@@ -201,7 +201,8 @@
<return type="int" enum="Error" />
<param index="0" name="renormalize" type="bool" default="false" />
<description>
- Generates mipmaps for the image. Mipmaps are precalculated lower-resolution copies of the image that are automatically used if the image needs to be scaled down when rendered. They help improve image quality and performance when rendering. This method returns an error if the image is compressed, in a custom format, or if the image's width/height is [code]0[/code].
+ Generates mipmaps for the image. Mipmaps are precalculated lower-resolution copies of the image that are automatically used if the image needs to be scaled down when rendered. They help improve image quality and performance when rendering. This method returns an error if the image is compressed, in a custom format, or if the image's width/height is [code]0[/code]. Enabling [param renormalize] when generating mipmaps for normal textures will make sure all resulting vector values are normalized.
+ It is possible to check if the image has mipmaps by calling [method has_mipmaps] or [method get_mipmap_count].
</description>
</method>
<method name="get_data" qualifiers="const">
@@ -222,6 +223,12 @@
Returns the image's height.
</description>
</method>
+ <method name="get_mipmap_count" qualifiers="const">
+ <return type="int" />
+ <description>
+ Returns the number of mipmap levels or 0 if the image has no mipmaps. The largest main level image is not counted as a mipmap level by this method, so if you want to include it you can add 1 to this count.
+ </description>
+ </method>
<method name="get_mipmap_offset" qualifiers="const">
<return type="int" />
<param index="0" name="mipmap" type="int" />
diff --git a/doc/classes/ItemList.xml b/doc/classes/ItemList.xml
index f6ad422234..593f41bc70 100644
--- a/doc/classes/ItemList.xml
+++ b/doc/classes/ItemList.xml
@@ -57,6 +57,12 @@
Ensure current selection is visible, adjusting the scroll position as necessary.
</description>
</method>
+ <method name="force_update_list_size">
+ <return type="void" />
+ <description>
+ Forces an update to the list size based on its items. This happens automatically whenever size of the items, or other relevant settings like [member auto_height], change. The method can be used to trigger the update ahead of next drawing pass.
+ </description>
+ </method>
<method name="get_item_at_position" qualifiers="const">
<return type="int" />
<param index="0" name="position" type="Vector2" />
diff --git a/doc/classes/Joint2D.xml b/doc/classes/Joint2D.xml
index 6a43180561..9fb9154827 100644
--- a/doc/classes/Joint2D.xml
+++ b/doc/classes/Joint2D.xml
@@ -8,6 +8,14 @@
</description>
<tutorials>
</tutorials>
+ <methods>
+ <method name="get_rid" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the joint's [RID].
+ </description>
+ </method>
+ </methods>
<members>
<member name="bias" type="float" setter="set_bias" getter="get_bias" default="0.0">
When [member node_a] and [member node_b] move in different directions the [code]bias[/code] controls how fast the joint pulls them back to their original position. The lower the [code]bias[/code] the more the two bodies can pull on the joint.
diff --git a/doc/classes/Joint3D.xml b/doc/classes/Joint3D.xml
index d848bdc0cd..9e0b753701 100644
--- a/doc/classes/Joint3D.xml
+++ b/doc/classes/Joint3D.xml
@@ -9,6 +9,14 @@
<tutorials>
<link title="3D Truck Town Demo">https://godotengine.org/asset-library/asset/524</link>
</tutorials>
+ <methods>
+ <method name="get_rid" qualifiers="const">
+ <return type="RID" />
+ <description>
+ Returns the joint's [RID].
+ </description>
+ </method>
+ </methods>
<members>
<member name="exclude_nodes_from_collision" type="bool" setter="set_exclude_nodes_from_collision" getter="get_exclude_nodes_from_collision" default="true">
If [code]true[/code], the two bodies of the nodes are not able to collide with each other.
diff --git a/doc/classes/LightmapGI.xml b/doc/classes/LightmapGI.xml
index a626c71377..2b2fca7d35 100644
--- a/doc/classes/LightmapGI.xml
+++ b/doc/classes/LightmapGI.xml
@@ -118,6 +118,9 @@
<constant name="BAKE_ERROR_USER_ABORTED" value="8" enum="BakeError">
The user aborted the lightmap baking operation (typically by clicking the [b]Cancel[/b] button in the progress dialog).
</constant>
+ <constant name="BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL" value="9" enum="BakeError">
+ Lightmap baking failed as the maximum texture size is too small to fit some of the meshes marked for baking.
+ </constant>
<constant name="ENVIRONMENT_MODE_DISABLED" value="0" enum="EnvironmentMode">
Ignore environment lighting when baking lightmaps.
</constant>
diff --git a/doc/classes/Line2D.xml b/doc/classes/Line2D.xml
index 7e02a520a0..4c444721f4 100644
--- a/doc/classes/Line2D.xml
+++ b/doc/classes/Line2D.xml
@@ -63,16 +63,21 @@
[b]Note:[/b] [Line2D] is not accelerated by batching when being anti-aliased.
</member>
<member name="begin_cap_mode" type="int" setter="set_begin_cap_mode" getter="get_begin_cap_mode" enum="Line2D.LineCapMode" default="0">
- The style of the beginning of the polyline. Use [enum LineCapMode] constants.
+ The style of the beginning of the polyline, if [member closed] is [code]false[/code]. Use [enum LineCapMode] constants.
+ </member>
+ <member name="closed" type="bool" setter="set_closed" getter="is_closed" default="false">
+ If [code]true[/code] and the polyline has more than 2 points, the last point and the first one will be connected by a segment.
+ [b]Note:[/b] The shape of the closing segment is not guaranteed to be seamless if a [member width_curve] is provided.
+ [b]Note:[/b] The joint between the closing segment and the first segment is drawn first and it samples the [member gradient] and the [member width_curve] at the beginning. This is an implementation detail that might change in a future version.
</member>
<member name="default_color" type="Color" setter="set_default_color" getter="get_default_color" default="Color(1, 1, 1, 1)">
The color of the polyline. Will not be used if a gradient is set.
</member>
<member name="end_cap_mode" type="int" setter="set_end_cap_mode" getter="get_end_cap_mode" enum="Line2D.LineCapMode" default="0">
- The style of the end of the polyline. Use [enum LineCapMode] constants.
+ The style of the end of the polyline, if [member closed] is [code]false[/code]. Use [enum LineCapMode] constants.
</member>
<member name="gradient" type="Gradient" setter="set_gradient" getter="get_gradient">
- The gradient is drawn through the whole line from start to finish. The default color will not be used if a gradient is set.
+ The gradient is drawn through the whole line from start to finish. The [member default_color] will not be used if this property is set.
</member>
<member name="joint_mode" type="int" setter="set_joint_mode" getter="get_joint_mode" enum="Line2D.LineJointMode" default="0">
The style of the connections between segments of the polyline. Use [enum LineJointMode] constants.
@@ -93,7 +98,7 @@
The style to render the [member texture] of the polyline. Use [enum LineTextureMode] constants.
</member>
<member name="width" type="float" setter="set_width" getter="get_width" default="10.0">
- The polyline's width
+ The polyline's width.
</member>
<member name="width_curve" type="Curve" setter="set_curve" getter="get_curve">
The polyline's width curve. The width of the polyline over its length will be equivalent to the value of the width curve over its domain.
diff --git a/doc/classes/Node.xml b/doc/classes/Node.xml
index 7510d6bb64..c9c94eff36 100644
--- a/doc/classes/Node.xml
+++ b/doc/classes/Node.xml
@@ -100,10 +100,10 @@
<return type="void" />
<param index="0" name="event" type="InputEvent" />
<description>
- Called when an [InputEventKey] or [InputEventShortcut] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
+ Called when an [InputEventKey] or [InputEventShortcut] hasn't been consumed by [method _input] or any GUI [Control] item. It is called before [method _unhandled_key_input] and [method _unhandled_input]. The input event propagates up through the node tree until a node consumes it.
It is only called if shortcut processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_shortcut_input].
To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
- This method can be used to handle shortcuts.
+ This method can be used to handle shortcuts. For generic GUI events, use [method _input] instead. Gameplay events should usually be handled with either [method _unhandled_input] or [method _unhandled_key_input].
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not orphan).
</description>
</method>
@@ -111,10 +111,10 @@
<return type="void" />
<param index="0" name="event" type="InputEvent" />
<description>
- Called when an [InputEvent] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
+ Called when an [InputEvent] hasn't been consumed by [method _input] or any GUI [Control] item. It is called after [method _shortcut_input] and after [method _unhandled_key_input]. The input event propagates up through the node tree until a node consumes it.
It is only called if unhandled input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_input].
To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
- For gameplay input, this and [method _unhandled_key_input] are usually a better fit than [method _input] as they allow the GUI to intercept the events first.
+ For gameplay input, this method is usually a better fit than [method _input], as GUI events need a higher priority. For keyboard shortcuts, consider using [method _shortcut_input] instead, as it is called before this method. Finally, to handle keyboard events, consider using [method _unhandled_key_input] for performance reasons.
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
</description>
</method>
@@ -122,12 +122,11 @@
<return type="void" />
<param index="0" name="event" type="InputEvent" />
<description>
- Called when an [InputEventKey] hasn't been consumed by [method _input] or any GUI [Control] item. The input event propagates up through the node tree until a node consumes it.
+ Called when an [InputEventKey] hasn't been consumed by [method _input] or any GUI [Control] item. It is called after [method _shortcut_input] but before [method _unhandled_input]. The input event propagates up through the node tree until a node consumes it.
It is only called if unhandled key input processing is enabled, which is done automatically if this method is overridden, and can be toggled with [method set_process_unhandled_key_input].
To consume the input event and stop it propagating further to other nodes, [method Viewport.set_input_as_handled] can be called.
This method can be used to handle Unicode character input with [kbd]Alt[/kbd], [kbd]Alt + Ctrl[/kbd], and [kbd]Alt + Shift[/kbd] modifiers, after shortcuts were handled.
- For gameplay input, this and [method _unhandled_input] are usually a better fit than [method _input] as they allow the GUI to intercept the events first.
- This method also performs better than [method _unhandled_input], since unrelated events such as [InputEventMouseMotion] are automatically filtered.
+ For gameplay input, this and [method _unhandled_input] are usually a better fit than [method _input], as GUI events should be handled first. This method also performs better than [method _unhandled_input], since unrelated events such as [InputEventMouseMotion] are automatically filtered. For shortcuts, consider using [method _shortcut_input] instead.
[b]Note:[/b] This method is only called if the node is present in the scene tree (i.e. if it's not an orphan).
</description>
</method>
diff --git a/doc/classes/PhysicsServer3DRenderingServerHandler.xml b/doc/classes/PhysicsServer3DRenderingServerHandler.xml
index da04cd918c..c04dbf2bd7 100644
--- a/doc/classes/PhysicsServer3DRenderingServerHandler.xml
+++ b/doc/classes/PhysicsServer3DRenderingServerHandler.xml
@@ -12,20 +12,48 @@
<return type="void" />
<param index="0" name="aabb" type="AABB" />
<description>
+ Called by the [PhysicsServer3D] to set the bounding box for the [SoftBody3D].
</description>
</method>
<method name="_set_normal" qualifiers="virtual">
<return type="void" />
<param index="0" name="vertex_id" type="int" />
- <param index="1" name="normals" type="const void*" />
+ <param index="1" name="normal" type="Vector3" />
<description>
+ Called by the [PhysicsServer3D] to set the normal for the [SoftBody3D] vertex at the index specified by [param vertex_id].
+ [b]Note:[/b] The [param normal] parameter used to be of type [code]const void*[/code] prior to Godot 4.2.
</description>
</method>
<method name="_set_vertex" qualifiers="virtual">
<return type="void" />
<param index="0" name="vertex_id" type="int" />
- <param index="1" name="vertices" type="const void*" />
+ <param index="1" name="vertex" type="Vector3" />
<description>
+ Called by the [PhysicsServer3D] to set the position for the [SoftBody3D] vertex at the index specified by [param vertex_id].
+ [b]Note:[/b] The [param vertex] parameter used to be of type [code]const void*[/code] prior to Godot 4.2.
+ </description>
+ </method>
+ <method name="set_aabb">
+ <return type="void" />
+ <param index="0" name="aabb" type="AABB" />
+ <description>
+ Sets the bounding box for the [SoftBody3D].
+ </description>
+ </method>
+ <method name="set_normal">
+ <return type="void" />
+ <param index="0" name="vertex_id" type="int" />
+ <param index="1" name="normal" type="Vector3" />
+ <description>
+ Sets the normal for the [SoftBody3D] vertex at the index specified by [param vertex_id].
+ </description>
+ </method>
+ <method name="set_vertex">
+ <return type="void" />
+ <param index="0" name="vertex_id" type="int" />
+ <param index="1" name="vertex" type="Vector3" />
+ <description>
+ Sets the position for the [SoftBody3D] vertex at the index specified by [param vertex_id].
</description>
</method>
</methods>
diff --git a/doc/classes/PopupMenu.xml b/doc/classes/PopupMenu.xml
index b72e65e63a..c31416b823 100644
--- a/doc/classes/PopupMenu.xml
+++ b/doc/classes/PopupMenu.xml
@@ -13,6 +13,16 @@
<tutorials>
</tutorials>
<methods>
+ <method name="activate_item_by_event">
+ <return type="bool" />
+ <param index="0" name="event" type="InputEvent" />
+ <param index="1" name="for_global_only" type="bool" default="false" />
+ <description>
+ Checks the provided [param event] against the [PopupMenu]'s shortcuts and accelerators, and activates the first item with matching events. If [param for_global_only] is [code]true[/code], only shortcuts and accelerators with [code]global[/code] set to [code]true[/code] will be called.
+ Returns [code]true[/code] if an item was successfully activated.
+ [b]Note:[/b] Certain [Control]s, such as [MenuButton], will call this method automatically.
+ </description>
+ </method>
<method name="add_check_item">
<return type="void" />
<param index="0" name="label" type="String" />
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index e8a440b76f..fe5269e95d 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -247,6 +247,7 @@
<member name="application/boot_splash/image" type="String" setter="" getter="" default="&quot;&quot;">
Path to an image used as the boot splash. If left empty, the default Godot Engine splash will be displayed instead.
[b]Note:[/b] Only effective if [member application/boot_splash/show_image] is [code]true[/code].
+ [b]Note:[/b] The only supported format is PNG. Using another image format will result in an error.
</member>
<member name="application/boot_splash/minimum_display_time" type="int" setter="" getter="" default="0">
Minimum boot splash display time (in milliseconds). It is not recommended to set too high values for this setting.
@@ -399,6 +400,9 @@
<member name="audio/video/video_delay_compensation_ms" type="int" setter="" getter="" default="0">
Setting to hardcode audio delay when playing video. Best to leave this untouched unless you know what you are doing.
</member>
+ <member name="collada/use_ambient" type="bool" setter="" getter="" default="false">
+ If [code]true[/code], ambient lights will be imported from COLLADA models as [DirectionalLight3D]. If [code]false[/code], ambient lights will be ignored.
+ </member>
<member name="compression/formats/gzip/compression_level" type="int" setter="" getter="" default="-1">
The default compression level for gzip. Affects compressed scenes and resources. Higher levels result in smaller files at the cost of compression speed. Decompression speed is mostly unaffected by the compression level. [code]-1[/code] uses the default gzip compression level, which is identical to [code]6[/code] but could change in the future due to underlying zlib updates.
</member>
@@ -492,9 +496,6 @@
<member name="debug/gdscript/warnings/redundant_await" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a function that is not a coroutine is called with await.
</member>
- <member name="debug/gdscript/warnings/redundant_for_variable_type" type="int" setter="" getter="" default="1">
- When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a [code]for[/code] variable type specifier is a supertype of the inferred type.
- </member>
<member name="debug/gdscript/warnings/redundant_static_unload" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when the [code]@static_unload[/code] annotation is used in a script without any static variables.
</member>
@@ -549,6 +550,9 @@
<member name="debug/gdscript/warnings/unsafe_void_return" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when returning a call from a [code]void[/code] function when such call cannot be guaranteed to be also [code]void[/code].
</member>
+ <member name="debug/gdscript/warnings/untyped_declaration" type="int" setter="" getter="" default="0">
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a variable or parameter has no static type, or if a function has no static return type.
+ </member>
<member name="debug/gdscript/warnings/unused_local_constant" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local constant is never used.
</member>
@@ -2113,11 +2117,11 @@
[codeblocks]
[gdscript]
# Set the default gravity strength to 9.8.
- PhysicsServer3D.area_set_param(get_viewport().find_world().space, PhysicsServer3D.AREA_PARAM_GRAVITY, 9.8)
+ PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY, 9.8)
[/gdscript]
[csharp]
// Set the default gravity strength to 9.8.
- PhysicsServer3D.AreaSetParam(GetViewport().FindWorld().Space, PhysicsServer3D.AreaParameter.Gravity, 9.8);
+ PhysicsServer3D.AreaSetParam(GetViewport().FindWorld3D().Space, PhysicsServer3D.AreaParameter.Gravity, 9.8);
[/csharp]
[/codeblocks]
</member>
@@ -2127,11 +2131,11 @@
[codeblocks]
[gdscript]
# Set the default gravity direction to `Vector3(0, -1, 0)`.
- PhysicsServer3D.area_set_param(get_viewport().find_world().get_space(), PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, Vector3.DOWN)
+ PhysicsServer3D.area_set_param(get_viewport().find_world_3d().space, PhysicsServer3D.AREA_PARAM_GRAVITY_VECTOR, Vector3.DOWN)
[/gdscript]
[csharp]
// Set the default gravity direction to `Vector3(0, -1, 0)`.
- PhysicsServer3D.AreaSetParam(GetViewport().FindWorld().Space, PhysicsServer3D.AreaParameter.GravityVector, Vector3.Down)
+ PhysicsServer3D.AreaSetParam(GetViewport().FindWorld3D().Space, PhysicsServer3D.AreaParameter.GravityVector, Vector3.Down)
[/csharp]
[/codeblocks]
</member>
@@ -2706,6 +2710,9 @@
<member name="xr/openxr/enabled" type="bool" setter="" getter="" default="false">
If [code]true[/code] Godot will setup and initialize OpenXR on startup.
</member>
+ <member name="xr/openxr/environment_blend_mode" type="int" setter="" getter="" default="&quot;0&quot;">
+ Specify how OpenXR should blend in the environment. This is specific to certain AR and passthrough devices where camera images are blended in by the XR compositor.
+ </member>
<member name="xr/openxr/form_factor" type="int" setter="" getter="" default="&quot;0&quot;">
Specify whether OpenXR should be configured for an HMD or a hand held device.
</member>
diff --git a/doc/classes/RDShaderSPIRV.xml b/doc/classes/RDShaderSPIRV.xml
index de7c1a4ca7..dd8a292c61 100644
--- a/doc/classes/RDShaderSPIRV.xml
+++ b/doc/classes/RDShaderSPIRV.xml
@@ -4,7 +4,7 @@
SPIR-V intermediate representation as part of a [RDShaderFile] (used by [RenderingDevice]).
</brief_description>
<description>
- [RDShaderSPIRV] represents a [RDShaderFile]'s [url=https://www.khronos.org/spir/]SPIR-V[/url] code for various shader stages, as well as possible compilation error messages. SPIR-V a low-level intermediate shader representation. This intermediate representation is not used directly by GPUs for rendering, but it can be compiled into binary shaders that GPUs can understand. Unlike compiled shaders, SPIR-V is portable across GPU models and driver versions.
+ [RDShaderSPIRV] represents a [RDShaderFile]'s [url=https://www.khronos.org/spir/]SPIR-V[/url] code for various shader stages, as well as possible compilation error messages. SPIR-V is a low-level intermediate shader representation. This intermediate representation is not used directly by GPUs for rendering, but it can be compiled into binary shaders that GPUs can understand. Unlike compiled shaders, SPIR-V is portable across GPU models and driver versions.
This object is used by [RenderingDevice].
</description>
<tutorials>
diff --git a/doc/classes/ScrollContainer.xml b/doc/classes/ScrollContainer.xml
index 15a2f2cabf..2181194fd4 100644
--- a/doc/classes/ScrollContainer.xml
+++ b/doc/classes/ScrollContainer.xml
@@ -50,7 +50,7 @@
Deadzone for touch scrolling. Lower deadzone makes the scrolling more sensitive.
</member>
<member name="scroll_horizontal" type="int" setter="set_h_scroll" getter="get_h_scroll" default="0">
- The current horizontal scroll value.
+ The current horizontal scroll value.
[b]Note:[/b] If you are setting this value in the [method Node._ready] function or earlier, it needs to be wrapped with [method Object.set_deferred], since scroll bar's [member Range.max_value] is not initialized yet.
[codeblock]
func _ready():
@@ -78,12 +78,14 @@
<signals>
<signal name="scroll_ended">
<description>
- Emitted when scrolling stops.
+ Emitted when scrolling stops when dragging the scrollable area [i]with a touch event[/i]. This signal is [i]not[/i] emitted when scrolling by dragging the scrollbar, scrolling with the mouse wheel or scrolling with keyboard/gamepad events.
+ [b]Note:[/b] This signal is only emitted on Android or iOS, or on desktop/web platforms when [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse] is enabled.
</description>
</signal>
<signal name="scroll_started">
<description>
- Emitted when scrolling is started.
+ Emitted when scrolling starts when dragging the scrollable area w[i]ith a touch event[/i]. This signal is [i]not[/i] emitted when scrolling by dragging the scrollbar, scrolling with the mouse wheel or scrolling with keyboard/gamepad events.
+ [b]Note:[/b] This signal is only emitted on Android or iOS, or on desktop/web platforms when [member ProjectSettings.input_devices/pointing/emulate_touch_from_mouse] is enabled.
</description>
</signal>
</signals>
diff --git a/doc/classes/SurfaceTool.xml b/doc/classes/SurfaceTool.xml
index 494f41422f..5562342eac 100644
--- a/doc/classes/SurfaceTool.xml
+++ b/doc/classes/SurfaceTool.xml
@@ -119,7 +119,7 @@
Removes the index array by expanding the vertex array.
</description>
</method>
- <method name="generate_lod">
+ <method name="generate_lod" is_deprecated="true">
<return type="PackedInt32Array" />
<param index="0" name="nd_threshold" type="float" />
<param index="1" name="target_index_count" type="int" default="3" />
diff --git a/doc/classes/TileSetAtlasSource.xml b/doc/classes/TileSetAtlasSource.xml
index 1623cd87ee..f478f37500 100644
--- a/doc/classes/TileSetAtlasSource.xml
+++ b/doc/classes/TileSetAtlasSource.xml
@@ -287,5 +287,20 @@
<constant name="TILE_ANIMATION_MODE_MAX" value="2" enum="TileAnimationMode">
Represents the size of the [enum TileAnimationMode] enum.
</constant>
+ <constant name="TRANSFORM_FLIP_H" value="4096">
+ Represents cell's horizontal flip flag. Should be used directly with [TileMap] to flip placed tiles by altering their alternative IDs.
+ [codeblock]
+ var alternate_id = $TileMap.get_cell_alternative_tile(0, Vector2i(2, 2))
+ if not alternate_id &amp; TileSetAtlasSource.TRANSFORM_FLIP_H:
+ # If tile is not already flipped, flip it.
+ $TileMap.set_cell(0, Vector2i(2, 2), source_id, atlas_coords, alternate_id | TileSetAtlasSource.TRANSFORM_FLIP_H)
+ [/codeblock]
+ </constant>
+ <constant name="TRANSFORM_FLIP_V" value="8192">
+ Represents cell's vertical flip flag. See [constant TRANSFORM_FLIP_H] for usage.
+ </constant>
+ <constant name="TRANSFORM_TRANSPOSE" value="16384">
+ Represents cell's transposed flag. See [constant TRANSFORM_FLIP_H] for usage.
+ </constant>
</constants>
</class>
diff --git a/doc/classes/Vector2i.xml b/doc/classes/Vector2i.xml
index ccb5bb7815..2100cd7612 100644
--- a/doc/classes/Vector2i.xml
+++ b/doc/classes/Vector2i.xml
@@ -124,6 +124,12 @@
<constant name="ONE" value="Vector2i(1, 1)">
One vector, a vector with all components set to [code]1[/code].
</constant>
+ <constant name="MIN" value="Vector2i(-2147483648, -2147483648)">
+ Min vector, a vector with all components equal to [code]INT32_MIN[/code]. Can be used as a negative integer equivalent of [constant Vector2.INF].
+ </constant>
+ <constant name="MAX" value="Vector2i(2147483647, 2147483647)">
+ Max vector, a vector with all components equal to [code]INT32_MAX[/code]. Can be used as an integer equivalent of [constant Vector2.INF].
+ </constant>
<constant name="LEFT" value="Vector2i(-1, 0)">
Left unit vector. Represents the direction of left.
</constant>
diff --git a/doc/classes/Vector3i.xml b/doc/classes/Vector3i.xml
index 90cb70f347..8906bf0aa7 100644
--- a/doc/classes/Vector3i.xml
+++ b/doc/classes/Vector3i.xml
@@ -125,6 +125,12 @@
<constant name="ONE" value="Vector3i(1, 1, 1)">
One vector, a vector with all components set to [code]1[/code].
</constant>
+ <constant name="MIN" value="Vector3i(-2147483648, -2147483648, -2147483648)">
+ Min vector, a vector with all components equal to [code]INT32_MIN[/code]. Can be used as a negative integer equivalent of [constant Vector3.INF].
+ </constant>
+ <constant name="MAX" value="Vector3i(2147483647, 2147483647, 2147483647)">
+ Max vector, a vector with all components equal to [code]INT32_MAX[/code]. Can be used as an integer equivalent of [constant Vector3.INF].
+ </constant>
<constant name="LEFT" value="Vector3i(-1, 0, 0)">
Left unit vector. Represents the local direction of left, and the global direction of west.
</constant>
diff --git a/doc/classes/Vector4i.xml b/doc/classes/Vector4i.xml
index f2eb353b5a..a612c135dd 100644
--- a/doc/classes/Vector4i.xml
+++ b/doc/classes/Vector4i.xml
@@ -129,6 +129,12 @@
<constant name="ONE" value="Vector4i(1, 1, 1, 1)">
One vector, a vector with all components set to [code]1[/code].
</constant>
+ <constant name="MIN" value="Vector4i(-2147483648, -2147483648, -2147483648, -2147483648)">
+ Min vector, a vector with all components equal to [code]INT32_MIN[/code]. Can be used as a negative integer equivalent of [constant Vector4.INF].
+ </constant>
+ <constant name="MAX" value="Vector4i(2147483647, 2147483647, 2147483647, 2147483647)">
+ Max vector, a vector with all components equal to [code]INT32_MAX[/code]. Can be used as an integer equivalent of [constant Vector4.INF].
+ </constant>
</constants>
<operators>
<operator name="operator !=">
diff --git a/doc/classes/XRInterface.xml b/doc/classes/XRInterface.xml
index 7b741b43d8..99d6e67e51 100644
--- a/doc/classes/XRInterface.xml
+++ b/doc/classes/XRInterface.xml
@@ -188,6 +188,9 @@
<member name="ar_is_anchor_detection_enabled" type="bool" setter="set_anchor_detection_is_enabled" getter="get_anchor_detection_is_enabled" default="false">
On an AR interface, [code]true[/code] if anchor detection is enabled.
</member>
+ <member name="environment_blend_mode" type="int" setter="set_environment_blend_mode" getter="get_environment_blend_mode" enum="XRInterface.EnvironmentBlendMode" default="0">
+ Specify how XR should blend in the environment. This is specific to certain AR and passthrough devices where camera images are blended in by the XR compositor.
+ </member>
<member name="interface_is_primary" type="bool" setter="set_primary" getter="is_primary" default="false">
[code]true[/code] if this is the primary interface.
</member>
diff --git a/drivers/SCsub b/drivers/SCsub
index 276b99e10b..c633a0591b 100644
--- a/drivers/SCsub
+++ b/drivers/SCsub
@@ -28,6 +28,7 @@ if env["vulkan"]:
if env["opengl3"]:
SConscript("gl_context/SCsub")
SConscript("gles3/SCsub")
+ SConscript("egl/SCsub")
# Core dependencies
SConscript("png/SCsub")
diff --git a/drivers/coreaudio/audio_driver_coreaudio.cpp b/drivers/coreaudio/audio_driver_coreaudio.cpp
index f3920863b4..98a8d4b2ef 100644
--- a/drivers/coreaudio/audio_driver_coreaudio.cpp
+++ b/drivers/coreaudio/audio_driver_coreaudio.cpp
@@ -80,7 +80,7 @@ Error AudioDriverCoreAudio::init() {
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
- ERR_FAIL_COND_V(comp == nullptr, FAILED);
+ ERR_FAIL_NULL_V(comp, FAILED);
OSStatus result = AudioComponentInstanceNew(comp, &audio_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
@@ -349,7 +349,7 @@ Error AudioDriverCoreAudio::init_input_device() {
desc.componentManufacturer = kAudioUnitManufacturer_Apple;
AudioComponent comp = AudioComponentFindNext(nullptr, &desc);
- ERR_FAIL_COND_V(comp == nullptr, FAILED);
+ ERR_FAIL_NULL_V(comp, FAILED);
OSStatus result = AudioComponentInstanceNew(comp, &input_unit);
ERR_FAIL_COND_V(result != noErr, FAILED);
diff --git a/drivers/egl/SCsub b/drivers/egl/SCsub
new file mode 100644
index 0000000000..1fd15b4bae
--- /dev/null
+++ b/drivers/egl/SCsub
@@ -0,0 +1,6 @@
+#!/usr/bin/env python
+
+Import("env")
+
+# Godot source files
+env.add_source_files(env.drivers_sources, "*.cpp")
diff --git a/drivers/egl/egl_manager.cpp b/drivers/egl/egl_manager.cpp
new file mode 100644
index 0000000000..ac80bc8111
--- /dev/null
+++ b/drivers/egl/egl_manager.cpp
@@ -0,0 +1,404 @@
+/**************************************************************************/
+/* egl_manager.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 "egl_manager.h"
+
+#ifdef EGL_ENABLED
+
+#if defined(EGL_STATIC)
+#define KHRONOS_STATIC 1
+extern "C" EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#undef KHRONOS_STATIC
+#endif
+
+// Creates and caches a GLDisplay. Returns -1 on error.
+int EGLManager::_get_gldisplay_id(void *p_display) {
+ // Look for a cached GLDisplay.
+ for (unsigned int i = 0; i < displays.size(); i++) {
+ if (displays[i].display == p_display) {
+ return i;
+ }
+ }
+
+ // We didn't find any, so we'll have to create one, along with its own
+ // EGLDisplay and EGLContext.
+ GLDisplay new_gldisplay;
+ new_gldisplay.display = p_display;
+
+ Vector<EGLAttrib> attribs = _get_platform_display_attributes();
+
+ new_gldisplay.egl_display = eglGetPlatformDisplay(_get_platform_extension_enum(), new_gldisplay.display, (attribs.size() > 0) ? attribs.ptr() : nullptr);
+ ERR_FAIL_COND_V(eglGetError() != EGL_SUCCESS, -1);
+
+ ERR_FAIL_COND_V_MSG(new_gldisplay.egl_display == EGL_NO_DISPLAY, -1, "Can't create an EGL display.");
+
+ if (!eglInitialize(new_gldisplay.egl_display, nullptr, nullptr)) {
+ ERR_FAIL_V_MSG(-1, "Can't initialize an EGL display.");
+ }
+
+ if (!eglBindAPI(_get_platform_api_enum())) {
+ ERR_FAIL_V_MSG(-1, "OpenGL not supported.");
+ }
+
+ Error err = _gldisplay_create_context(new_gldisplay);
+
+ if (err != OK) {
+ eglTerminate(new_gldisplay.egl_display);
+ ERR_FAIL_V(-1);
+ }
+
+#ifdef EGL_ANDROID_blob_cache
+#if defined(EGL_STATIC)
+ bool has_blob_cache = true;
+#else
+ bool has_blob_cache = (eglSetBlobCacheFuncsANDROID != nullptr);
+#endif
+ if (has_blob_cache && !shader_cache_dir.is_empty()) {
+ eglSetBlobCacheFuncsANDROID(new_gldisplay.egl_display, &EGLManager::_set_cache, &EGLManager::_get_cache);
+ }
+#endif
+
+ displays.push_back(new_gldisplay);
+
+ // Return the new GLDisplay's ID.
+ return displays.size() - 1;
+}
+
+#ifdef EGL_ANDROID_blob_cache
+String EGLManager::shader_cache_dir;
+
+void EGLManager::_set_cache(const void *p_key, EGLsizeiANDROID p_key_size, const void *p_value, EGLsizeiANDROID p_value_size) {
+ String name = CryptoCore::b64_encode_str((const uint8_t *)p_key, p_key_size).replace("/", "_");
+ String path = shader_cache_dir.path_join(name) + ".cache";
+
+ Error err = OK;
+ Ref<FileAccess> file = FileAccess::open(path, FileAccess::WRITE, &err);
+ if (err != OK) {
+ return;
+ }
+ file->store_buffer((const uint8_t *)p_value, p_value_size);
+}
+
+EGLsizeiANDROID EGLManager::_get_cache(const void *p_key, EGLsizeiANDROID p_key_size, void *p_value, EGLsizeiANDROID p_value_size) {
+ String name = CryptoCore::b64_encode_str((const uint8_t *)p_key, p_key_size).replace("/", "_");
+ String path = shader_cache_dir.path_join(name) + ".cache";
+
+ Error err = OK;
+ Ref<FileAccess> file = FileAccess::open(path, FileAccess::READ, &err);
+ if (err != OK) {
+ return 0;
+ }
+ EGLsizeiANDROID len = file->get_length();
+ if (len <= p_value_size) {
+ file->get_buffer((uint8_t *)p_value, len);
+ }
+ return len;
+}
+#endif
+
+Error EGLManager::_gldisplay_create_context(GLDisplay &p_gldisplay) {
+ EGLint attribs[] = {
+ EGL_RED_SIZE,
+ 1,
+ EGL_BLUE_SIZE,
+ 1,
+ EGL_GREEN_SIZE,
+ 1,
+ EGL_DEPTH_SIZE,
+ 24,
+ EGL_NONE,
+ };
+
+ EGLint attribs_layered[] = {
+ EGL_RED_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_GREEN_SIZE,
+ 8,
+ EGL_ALPHA_SIZE,
+ 8,
+ EGL_DEPTH_SIZE,
+ 24,
+ EGL_NONE,
+ };
+
+ EGLint config_count = 0;
+
+ if (OS::get_singleton()->is_layered_allowed()) {
+ eglChooseConfig(p_gldisplay.egl_display, attribs_layered, &p_gldisplay.egl_config, 1, &config_count);
+ } else {
+ eglChooseConfig(p_gldisplay.egl_display, attribs, &p_gldisplay.egl_config, 1, &config_count);
+ }
+
+ ERR_FAIL_COND_V(eglGetError() != EGL_SUCCESS, ERR_BUG);
+ ERR_FAIL_COND_V(config_count == 0, ERR_UNCONFIGURED);
+
+ Vector<EGLint> context_attribs = _get_platform_context_attribs();
+ p_gldisplay.egl_context = eglCreateContext(p_gldisplay.egl_display, p_gldisplay.egl_config, EGL_NO_CONTEXT, (context_attribs.size() > 0) ? context_attribs.ptr() : nullptr);
+ ERR_FAIL_COND_V_MSG(p_gldisplay.egl_context == EGL_NO_CONTEXT, ERR_CANT_CREATE, vformat("Can't create an EGL context. Error code: %d", eglGetError()));
+
+ return OK;
+}
+
+int EGLManager::display_get_native_visual_id(void *p_display) {
+ int gldisplay_id = _get_gldisplay_id(p_display);
+ ERR_FAIL_COND_V(gldisplay_id < 0, ERR_CANT_CREATE);
+
+ GLDisplay gldisplay = displays[gldisplay_id];
+
+ EGLint native_visual_id = -1;
+
+ if (!eglGetConfigAttrib(gldisplay.egl_display, gldisplay.egl_config, EGL_NATIVE_VISUAL_ID, &native_visual_id)) {
+ ERR_FAIL_V(-1);
+ }
+
+ return native_visual_id;
+}
+
+Error EGLManager::window_create(DisplayServer::WindowID p_window_id, void *p_display, void *p_native_window, int p_width, int p_height) {
+ int gldisplay_id = _get_gldisplay_id(p_display);
+ ERR_FAIL_COND_V(gldisplay_id < 0, ERR_CANT_CREATE);
+
+ GLDisplay &gldisplay = displays[gldisplay_id];
+
+ // In order to ensure a fast lookup, make sure we got enough elements in the
+ // windows local vector to use the window id as an index.
+ if (p_window_id >= (int)windows.size()) {
+ windows.resize(p_window_id + 1);
+ }
+
+ GLWindow &glwindow = windows[p_window_id];
+ glwindow.gldisplay_id = gldisplay_id;
+
+ glwindow.egl_surface = eglCreatePlatformWindowSurface(gldisplay.egl_display, gldisplay.egl_config, p_native_window, nullptr);
+
+ if (glwindow.egl_surface == EGL_NO_SURFACE) {
+ return ERR_CANT_CREATE;
+ }
+
+ glwindow.initialized = true;
+
+ window_make_current(p_window_id);
+
+ return OK;
+}
+
+void EGLManager::window_destroy(DisplayServer::WindowID p_window_id) {
+ ERR_FAIL_INDEX(p_window_id, (int)windows.size());
+
+ GLWindow &glwindow = windows[p_window_id];
+
+ if (!glwindow.initialized) {
+ return;
+ }
+
+ glwindow.initialized = false;
+
+ ERR_FAIL_INDEX(glwindow.gldisplay_id, (int)displays.size());
+ GLDisplay &gldisplay = displays[glwindow.gldisplay_id];
+
+ if (glwindow.egl_surface != EGL_NO_SURFACE) {
+ eglDestroySurface(gldisplay.egl_display, glwindow.egl_surface);
+ glwindow.egl_surface = nullptr;
+ }
+}
+
+void EGLManager::release_current() {
+ if (!current_window) {
+ return;
+ }
+
+ GLDisplay &current_display = displays[current_window->gldisplay_id];
+
+ eglMakeCurrent(current_display.egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
+}
+
+void EGLManager::make_current() {
+ if (!current_window) {
+ return;
+ }
+
+ if (!current_window->initialized) {
+ WARN_PRINT("Current OpenGL window is uninitialized!");
+ return;
+ }
+
+ GLDisplay &current_display = displays[current_window->gldisplay_id];
+
+ eglMakeCurrent(current_display.egl_display, current_window->egl_surface, current_window->egl_surface, current_display.egl_context);
+}
+
+void EGLManager::swap_buffers() {
+ if (!current_window) {
+ return;
+ }
+
+ if (!current_window->initialized) {
+ WARN_PRINT("Current OpenGL window is uninitialized!");
+ return;
+ }
+
+ GLDisplay &current_display = displays[current_window->gldisplay_id];
+
+ eglSwapBuffers(current_display.egl_display, current_window->egl_surface);
+}
+
+void EGLManager::window_make_current(DisplayServer::WindowID p_window_id) {
+ if (p_window_id == DisplayServer::INVALID_WINDOW_ID) {
+ return;
+ }
+
+ GLWindow &glwindow = windows[p_window_id];
+
+ if (&glwindow == current_window || !glwindow.initialized) {
+ return;
+ }
+
+ current_window = &glwindow;
+
+ GLDisplay &current_display = displays[current_window->gldisplay_id];
+
+ eglMakeCurrent(current_display.egl_display, current_window->egl_surface, current_window->egl_surface, current_display.egl_context);
+}
+
+void EGLManager::set_use_vsync(bool p_use) {
+ // Force vsync in the editor for now, as a safety measure.
+ bool is_editor = Engine::get_singleton()->is_editor_hint();
+ if (is_editor) {
+ p_use = true;
+ }
+
+ // We need an active window to get a display to set the vsync.
+ if (!current_window) {
+ return;
+ }
+
+ GLDisplay &disp = displays[current_window->gldisplay_id];
+
+ int swap_interval = p_use ? 1 : 0;
+
+ if (!eglSwapInterval(disp.egl_display, swap_interval)) {
+ WARN_PRINT("Could not set V-Sync mode.");
+ }
+
+ use_vsync = p_use;
+}
+
+bool EGLManager::is_using_vsync() const {
+ return use_vsync;
+}
+
+EGLContext EGLManager::get_context(DisplayServer::WindowID p_window_id) {
+ GLWindow &glwindow = windows[p_window_id];
+
+ if (!glwindow.initialized) {
+ return EGL_NO_CONTEXT;
+ }
+
+ GLDisplay &display = displays[glwindow.gldisplay_id];
+
+ return display.egl_context;
+}
+
+Error EGLManager::initialize() {
+#if defined(GLAD_ENABLED) && !defined(EGL_STATIC)
+ // Passing a null display loads just the bare minimum to create one. We'll have
+ // to create a temporary test display and reload EGL with it to get a good idea
+ // of what version is supported on this machine. Currently we're looking for
+ // 1.5, the latest at the time of writing, which is actually pretty old.
+ if (!gladLoaderLoadEGL(nullptr)) {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "Can't load EGL.");
+ }
+
+ // NOTE: EGL_DEFAULT_DISPLAY returns whatever the O.S. deems suitable. I have
+ // no idea if this may cause problems with multiple display servers and if we
+ // should handle different EGL contexts in another way.
+ EGLDisplay tmp_display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ ERR_FAIL_COND_V(tmp_display == EGL_NO_DISPLAY, ERR_UNAVAILABLE);
+
+ eglInitialize(tmp_display, nullptr, nullptr);
+
+ int version = gladLoaderLoadEGL(tmp_display);
+
+ ERR_FAIL_COND_V_MSG(!version, ERR_UNAVAILABLE, "Can't load EGL.");
+ print_verbose(vformat("Loaded EGL %d.%d", GLAD_VERSION_MAJOR(version), GLAD_VERSION_MINOR(version)));
+
+ ERR_FAIL_COND_V_MSG(!GLAD_EGL_VERSION_1_5, ERR_UNAVAILABLE, "EGL version is too old!");
+
+ eglTerminate(tmp_display);
+#endif
+
+#ifdef EGL_ANDROID_blob_cache
+ shader_cache_dir = Engine::get_singleton()->get_shader_cache_path();
+ if (shader_cache_dir.is_empty()) {
+ shader_cache_dir = "user://";
+ }
+ Error err = OK;
+ Ref<DirAccess> da = DirAccess::open(shader_cache_dir);
+ if (da.is_null()) {
+ ERR_PRINT("EGL: Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
+ shader_cache_dir = String();
+ } else {
+ err = da->change_dir(String("shader_cache").path_join("EGL"));
+ if (err != OK) {
+ err = da->make_dir_recursive(String("shader_cache").path_join("EGL"));
+ }
+ if (err != OK) {
+ ERR_PRINT("EGL: Can't create shader cache folder, no shader caching will happen: " + shader_cache_dir);
+ shader_cache_dir = String();
+ } else {
+ shader_cache_dir = shader_cache_dir.path_join(String("shader_cache").path_join("EGL"));
+ }
+ }
+#endif
+
+ String extensions_string = eglQueryString(EGL_NO_DISPLAY, EGL_EXTENSIONS);
+ // The above method should always work. If it doesn't, something's very wrong.
+ ERR_FAIL_COND_V(eglGetError() != EGL_SUCCESS, ERR_BUG);
+
+ const char *platform = _get_platform_extension_name();
+ if (extensions_string.split(" ").find(platform) < 0) {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, vformat("EGL platform extension \"%s\" not found.", platform));
+ }
+
+ return OK;
+}
+
+EGLManager::EGLManager() {
+}
+
+EGLManager::~EGLManager() {
+ for (unsigned int i = 0; i < displays.size(); i++) {
+ eglTerminate(displays[i].egl_display);
+ }
+}
+
+#endif // EGL_ENABLED
diff --git a/drivers/egl/egl_manager.h b/drivers/egl/egl_manager.h
new file mode 100644
index 0000000000..5814cb9826
--- /dev/null
+++ b/drivers/egl/egl_manager.h
@@ -0,0 +1,118 @@
+/**************************************************************************/
+/* egl_manager.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 EGL_MANAGER_H
+#define EGL_MANAGER_H
+
+#ifdef EGL_ENABLED
+
+// These must come first to avoid windows.h mess.
+#include "platform_gl.h"
+
+#include "core/config/project_settings.h"
+#include "core/crypto/crypto_core.h"
+#include "core/io/dir_access.h"
+#include "core/io/file_access.h"
+#include "core/templates/local_vector.h"
+#include "servers/display_server.h"
+
+class EGLManager {
+private:
+ // An EGL-side rappresentation of a display with its own rendering
+ // context.
+ struct GLDisplay {
+ void *display = nullptr;
+
+ EGLDisplay egl_display = EGL_NO_DISPLAY;
+ EGLContext egl_context = EGL_NO_CONTEXT;
+ EGLConfig egl_config = nullptr;
+ };
+
+ // EGL specific window data.
+ struct GLWindow {
+ bool initialized = false;
+
+ // An handle to the GLDisplay associated with this window.
+ int gldisplay_id = -1;
+
+ EGLSurface egl_surface = EGL_NO_SURFACE;
+ };
+
+ LocalVector<GLDisplay> displays;
+ LocalVector<GLWindow> windows;
+
+ GLWindow *current_window = nullptr;
+
+ // On EGL the default swap interval is 1 and thus vsync is on by default.
+ bool use_vsync = true;
+
+ virtual const char *_get_platform_extension_name() const = 0;
+ virtual EGLenum _get_platform_extension_enum() const = 0;
+ virtual EGLenum _get_platform_api_enum() const = 0;
+ virtual Vector<EGLAttrib> _get_platform_display_attributes() const = 0;
+ virtual Vector<EGLint> _get_platform_context_attribs() const = 0;
+
+#ifdef EGL_ANDROID_blob_cache
+ static String shader_cache_dir;
+
+ static void _set_cache(const void *p_key, EGLsizeiANDROID p_key_size, const void *p_value, EGLsizeiANDROID p_value_size);
+ static EGLsizeiANDROID _get_cache(const void *p_key, EGLsizeiANDROID p_key_size, void *p_value, EGLsizeiANDROID p_value_size);
+#endif
+
+ int _get_gldisplay_id(void *p_display);
+ Error _gldisplay_create_context(GLDisplay &p_gldisplay);
+
+public:
+ int display_get_native_visual_id(void *p_display);
+
+ Error window_create(DisplayServer::WindowID p_window_id, void *p_display, void *p_native_window, int p_width, int p_height);
+
+ void window_destroy(DisplayServer::WindowID p_window_id);
+
+ void release_current();
+ void make_current();
+ void swap_buffers();
+
+ void window_make_current(DisplayServer::WindowID p_window_id);
+
+ void set_use_vsync(bool p_use);
+ bool is_using_vsync() const;
+
+ EGLContext get_context(DisplayServer::WindowID p_window_id);
+
+ Error initialize();
+
+ EGLManager();
+ virtual ~EGLManager();
+};
+
+#endif // EGL_ENABLED
+
+#endif // EGL_MANAGER_H
diff --git a/drivers/gl_context/SCsub b/drivers/gl_context/SCsub
index ce3a598573..ce6ea747b1 100644
--- a/drivers/gl_context/SCsub
+++ b/drivers/gl_context/SCsub
@@ -5,9 +5,11 @@ Import("env")
if env["platform"] in ["macos", "windows", "linuxbsd"]:
# Thirdparty source files
thirdparty_dir = "#thirdparty/glad/"
- thirdparty_sources = [
- "gl.c",
- ]
+ thirdparty_sources = ["gl.c"]
+
+ if not env.get("angle_libs"):
+ thirdparty_sources += ["egl.c"]
+
thirdparty_sources = [thirdparty_dir + file for file in thirdparty_sources]
# Treat glad headers as system headers to avoid raising warnings. Not supported on MSVC.
@@ -17,7 +19,7 @@ if env["platform"] in ["macos", "windows", "linuxbsd"]:
env.Prepend(CPPPATH=[thirdparty_dir])
env.Append(CPPDEFINES=["GLAD_ENABLED"])
- env.Append(CPPDEFINES=["GLES_OVER_GL"])
+ env.Append(CPPDEFINES=["EGL_ENABLED"])
env_thirdparty = env.Clone()
env_thirdparty.disable_warnings()
diff --git a/drivers/gles3/environment/gi.h b/drivers/gles3/environment/gi.h
index 713c3ef3a5..41958e43e6 100644
--- a/drivers/gles3/environment/gi.h
+++ b/drivers/gles3/environment/gi.h
@@ -38,12 +38,7 @@
#include "core/templates/self_list.h"
#include "servers/rendering/environment/renderer_gi.h"
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
+#include "platform_gl.h"
namespace GLES3 {
diff --git a/drivers/gles3/rasterizer_canvas_gles3.cpp b/drivers/gles3/rasterizer_canvas_gles3.cpp
index 9818674de6..2894f4164f 100644
--- a/drivers/gles3/rasterizer_canvas_gles3.cpp
+++ b/drivers/gles3/rasterizer_canvas_gles3.cpp
@@ -33,6 +33,7 @@
#ifdef GLES3_ENABLED
#include "core/os/os.h"
+#include "rasterizer_gles3.h"
#include "rasterizer_scene_gles3.h"
#include "core/config/project_settings.h"
@@ -1259,7 +1260,7 @@ void RasterizerCanvasGLES3::_render_batch(Light *p_lights, uint32_t p_index) {
const Item::CommandPolygon *polygon = static_cast<const Item::CommandPolygon *>(state.canvas_instance_batches[p_index].command);
PolygonBuffers *pb = polygon_buffers.polygons.getptr(polygon->polygon.polygon_id);
- ERR_FAIL_COND(!pb);
+ ERR_FAIL_NULL(pb);
glBindVertexArray(pb->vertex_array);
glBindBuffer(GL_ARRAY_BUFFER, state.canvas_instance_data_buffers[state.current_data_buffer_index].instance_buffers[state.canvas_instance_batches[p_index].instance_buffer_index]);
@@ -1515,7 +1516,7 @@ void RasterizerCanvasGLES3::light_set_texture(RID p_rid, RID p_texture) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!cl);
+ ERR_FAIL_NULL(cl);
if (cl->texture == p_texture) {
return;
}
@@ -1534,7 +1535,7 @@ void RasterizerCanvasGLES3::light_set_texture(RID p_rid, RID p_texture) {
void RasterizerCanvasGLES3::light_set_use_shadow(RID p_rid, bool p_enable) {
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!cl);
+ ERR_FAIL_NULL(cl);
cl->shadow.enabled = p_enable;
}
@@ -1561,7 +1562,8 @@ void RasterizerCanvasGLES3::light_update_shadow(RID p_rid, int p_shadow_index, c
glEnable(GL_SCISSOR_TEST);
glScissor(0, p_shadow_index * 2, state.shadow_texture_size, 2);
glClearColor(p_far, p_far, p_far, 1.0);
- glClearDepth(1.0);
+ RasterizerGLES3::clear_depth(1.0);
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCullFace(GL_BACK);
@@ -1682,7 +1684,8 @@ void RasterizerCanvasGLES3::light_update_directional_shadow(RID p_rid, int p_sha
glEnable(GL_SCISSOR_TEST);
glScissor(0, p_shadow_index * 2, state.shadow_texture_size, 2);
glClearColor(1.0, 1.0, 1.0, 1.0);
- glClearDepth(1.0);
+ RasterizerGLES3::clear_depth(1.0);
+
glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);
glCullFace(GL_BACK);
@@ -1868,7 +1871,7 @@ RID RasterizerCanvasGLES3::occluder_polygon_create() {
void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vector<Vector2> &p_points, bool p_closed) {
OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
- ERR_FAIL_COND(!oc);
+ ERR_FAIL_NULL(oc);
Vector<Vector2> lines;
@@ -2041,7 +2044,7 @@ void RasterizerCanvasGLES3::occluder_polygon_set_shape(RID p_occluder, const Vec
void RasterizerCanvasGLES3::occluder_polygon_set_cull_mode(RID p_occluder, RS::CanvasOccluderPolygonCullMode p_mode) {
OccluderPolygon *oc = occluder_polygon_owner.get_or_null(p_occluder);
- ERR_FAIL_COND(!oc);
+ ERR_FAIL_NULL(oc);
oc->cull_mode = p_mode;
}
@@ -2073,7 +2076,7 @@ void RasterizerCanvasGLES3::set_shadow_texture_size(int p_size) {
bool RasterizerCanvasGLES3::free(RID p_rid) {
if (canvas_light_owner.owns(p_rid)) {
CanvasLight *cl = canvas_light_owner.get_or_null(p_rid);
- ERR_FAIL_COND_V(!cl, false);
+ ERR_FAIL_NULL_V(cl, false);
canvas_light_owner.free(p_rid);
} else if (occluder_polygon_owner.owns(p_rid)) {
occluder_polygon_set_shape(p_rid, Vector<Vector2>(), false);
@@ -2455,7 +2458,7 @@ RendererCanvasRender::PolygonID RasterizerCanvasGLES3::request_polygon(const Vec
void RasterizerCanvasGLES3::free_polygon(PolygonID p_polygon) {
PolygonBuffers *pb_ptr = polygon_buffers.polygons.getptr(p_polygon);
- ERR_FAIL_COND(!pb_ptr);
+ ERR_FAIL_NULL(pb_ptr);
PolygonBuffers &pb = *pb_ptr;
diff --git a/drivers/gles3/rasterizer_gles3.cpp b/drivers/gles3/rasterizer_gles3.cpp
index 29806bbece..c048e9bf37 100644
--- a/drivers/gles3/rasterizer_gles3.cpp
+++ b/drivers/gles3/rasterizer_gles3.cpp
@@ -76,19 +76,14 @@
#define CAN_DEBUG
#endif
-#if !defined(GLES_OVER_GL) && defined(CAN_DEBUG)
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-#include <GLES3/gl3platform.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#endif
+#include "platform_gl.h"
#if defined(MINGW_ENABLED) || defined(_MSC_VER)
#define strcpy strcpy_s
#endif
+bool RasterizerGLES3::gles_over_gl = true;
+
void RasterizerGLES3::begin_frame(double frame_step) {
frame++;
delta = frame_step;
@@ -115,6 +110,19 @@ void RasterizerGLES3::end_frame(bool p_swap_buffers) {
}
}
+void RasterizerGLES3::clear_depth(float p_depth) {
+#ifdef GL_API_ENABLED
+ if (is_gles_over_gl()) {
+ glClearDepth(p_depth);
+ }
+#endif // GL_API_ENABLED
+#ifdef GLES_API_ENABLED
+ if (!is_gles_over_gl()) {
+ glClearDepthf(p_depth);
+ }
+#endif // GLES_API_ENABLED
+}
+
#ifdef CAN_DEBUG
static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar *message, const GLvoid *userParam) {
if (type == _EXT_DEBUG_TYPE_OTHER_ARB) {
@@ -169,7 +177,7 @@ static void GLAPIENTRY _gl_debug_print(GLenum source, GLenum type, GLuint id, GL
}
#endif
-typedef void (*DEBUGPROCARB)(GLenum source,
+typedef void(GLAPIENTRY *DEBUGPROCARB)(GLenum source,
GLenum type,
GLuint id,
GLenum severity,
@@ -177,7 +185,7 @@ typedef void (*DEBUGPROCARB)(GLenum source,
const char *message,
const void *userParam);
-typedef void (*DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam);
+typedef void(GLAPIENTRY *DebugMessageCallbackARB)(DEBUGPROCARB callback, const void *userParam);
void RasterizerGLES3::initialize() {
print_line(vformat("OpenGL API %s - Compatibility - Using Device: %s - %s", RS::get_singleton()->get_video_adapter_api_version(), RS::get_singleton()->get_video_adapter_vendor(), RS::get_singleton()->get_video_adapter_name()));
@@ -200,61 +208,99 @@ void RasterizerGLES3::finalize() {
RasterizerGLES3 *RasterizerGLES3::singleton = nullptr;
+#ifdef EGL_ENABLED
+void *_egl_load_function_wrapper(const char *p_name) {
+ return (void *)eglGetProcAddress(p_name);
+}
+#endif
+
RasterizerGLES3::RasterizerGLES3() {
singleton = this;
#ifdef GLAD_ENABLED
- if (!gladLoaderLoadGL()) {
- ERR_PRINT("Error initializing GLAD");
- // FIXME this is an early return from a constructor. Any other code using this instance will crash or the finalizer will crash, because none of
- // the members of this instance are initialized, so this just makes debugging harder. It should either crash here intentionally,
- // or we need to actually test for this situation before constructing this.
- return;
- }
+ bool glad_loaded = false;
+
+#ifdef EGL_ENABLED
+ // There should be a more flexible system for getting the GL pointer, as
+ // different DisplayServers can have different ways. We can just use the GLAD
+ // version global to see if it loaded for now though, otherwise we fall back to
+ // the generic loader below.
+#if defined(EGL_STATIC)
+ bool has_egl = true;
+#else
+ bool has_egl = (eglGetProcAddress != nullptr);
#endif
-#ifdef GLAD_ENABLED
- if (OS::get_singleton()->is_stdout_verbose()) {
- if (GLAD_GL_ARB_debug_output) {
- glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
- glDebugMessageCallbackARB(_gl_debug_print, nullptr);
- glEnable(_EXT_DEBUG_OUTPUT);
- } else {
- print_line("OpenGL debugging not supported!");
+ if (gles_over_gl) {
+ if (has_egl && !glad_loaded && gladLoadGL((GLADloadfunc)&_egl_load_function_wrapper)) {
+ glad_loaded = true;
+ }
+ } else {
+ if (has_egl && !glad_loaded && gladLoadGLES2((GLADloadfunc)&_egl_load_function_wrapper)) {
+ glad_loaded = true;
+ }
+ }
+#endif // EGL_ENABLED
+
+ if (gles_over_gl) {
+ if (!glad_loaded && gladLoaderLoadGL()) {
+ glad_loaded = true;
+ }
+ } else {
+ if (!glad_loaded && gladLoaderLoadGLES2()) {
+ glad_loaded = true;
+ }
+ }
+
+ // FIXME this is an early return from a constructor. Any other code using this instance will crash or the finalizer will crash, because none of
+ // the members of this instance are initialized, so this just makes debugging harder. It should either crash here intentionally,
+ // or we need to actually test for this situation before constructing this.
+ ERR_FAIL_COND_MSG(!glad_loaded, "Error initializing GLAD.");
+
+ if (gles_over_gl) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ if (GLAD_GL_ARB_debug_output) {
+ glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ glDebugMessageCallbackARB((GLDEBUGPROCARB)_gl_debug_print, nullptr);
+ glEnable(_EXT_DEBUG_OUTPUT);
+ } else {
+ print_line("OpenGL debugging not supported!");
+ }
}
}
#endif // GLAD_ENABLED
// For debugging
#ifdef CAN_DEBUG
-#ifdef GLES_OVER_GL
- if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) {
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PORTABILITY_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PERFORMANCE_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
- glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_OTHER_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
- // glDebugMessageInsertARB(
- // GL_DEBUG_SOURCE_API_ARB,
- // GL_DEBUG_TYPE_OTHER_ARB, 1,
- // GL_DEBUG_SEVERITY_HIGH_ARB, 5, "hello");
- }
-#else
- if (OS::get_singleton()->is_stdout_verbose()) {
- DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback");
- if (!callback) {
- callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR");
+#ifdef GL_API_ENABLED
+ if (gles_over_gl) {
+ if (OS::get_singleton()->is_stdout_verbose() && GLAD_GL_ARB_debug_output) {
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_ERROR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_DEPRECATED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_UNDEFINED_BEHAVIOR_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PORTABILITY_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_PERFORMANCE_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
+ glDebugMessageControlARB(_EXT_DEBUG_SOURCE_API_ARB, _EXT_DEBUG_TYPE_OTHER_ARB, _EXT_DEBUG_SEVERITY_HIGH_ARB, 0, nullptr, GL_TRUE);
}
+ }
+#endif // GL_API_ENABLED
+#ifdef GLES_API_ENABLED
+ if (!gles_over_gl) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ DebugMessageCallbackARB callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallback");
+ if (!callback) {
+ callback = (DebugMessageCallbackARB)eglGetProcAddress("glDebugMessageCallbackKHR");
+ }
- if (callback) {
- print_line("godot: ENABLING GL DEBUG");
- glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
- callback(_gl_debug_print, NULL);
- glEnable(_EXT_DEBUG_OUTPUT);
+ if (callback) {
+ print_line("godot: ENABLING GL DEBUG");
+ glEnable(_EXT_DEBUG_OUTPUT_SYNCHRONOUS_ARB);
+ callback((DEBUGPROCARB)_gl_debug_print, NULL);
+ glEnable(_EXT_DEBUG_OUTPUT);
+ }
}
}
-#endif // GLES_OVER_GL
+#endif // GLES_API_ENABLED
#endif // CAN_DEBUG
{
@@ -318,7 +364,7 @@ void RasterizerGLES3::prepare_for_blitting_render_targets() {
void RasterizerGLES3::_blit_render_target_to_screen(RID p_render_target, DisplayServer::WindowID p_screen, const Rect2 &p_screen_rect, uint32_t p_layer, bool p_first) {
GLES3::RenderTarget *rt = GLES3::TextureStorage::get_singleton()->get_render_target(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
// We normally render to the render target upside down, so flip Y when blitting to the screen.
bool flip_y = true;
diff --git a/drivers/gles3/rasterizer_gles3.h b/drivers/gles3/rasterizer_gles3.h
index e29ccefdbd..b19ca0e9c9 100644
--- a/drivers/gles3/rasterizer_gles3.h
+++ b/drivers/gles3/rasterizer_gles3.h
@@ -54,6 +54,8 @@ private:
double time_total = 0.0;
+ static bool gles_over_gl;
+
protected:
GLES3::Config *config = nullptr;
GLES3::Utilities *utilities = nullptr;
@@ -99,7 +101,11 @@ public:
return memnew(RasterizerGLES3);
}
- static void make_current() {
+ static bool is_gles_over_gl() { return gles_over_gl; }
+ static void clear_depth(float p_depth);
+
+ static void make_current(bool p_gles_over_gl) {
+ gles_over_gl = p_gles_over_gl;
_create_func = _create_current;
low_end = true;
}
diff --git a/drivers/gles3/rasterizer_scene_gles3.cpp b/drivers/gles3/rasterizer_scene_gles3.cpp
index 1fe33b7914..de2de54c44 100644
--- a/drivers/gles3/rasterizer_scene_gles3.cpp
+++ b/drivers/gles3/rasterizer_scene_gles3.cpp
@@ -29,15 +29,18 @@
/**************************************************************************/
#include "rasterizer_scene_gles3.h"
-#include "core/config/project_settings.h"
-#include "core/templates/sort_array.h"
-#include "servers/rendering/rendering_server_default.h"
-#include "servers/rendering/rendering_server_globals.h"
+
+#include "rasterizer_gles3.h"
#include "storage/config.h"
#include "storage/mesh_storage.h"
#include "storage/particles_storage.h"
#include "storage/texture_storage.h"
+#include "core/config/project_settings.h"
+#include "core/templates/sort_array.h"
+#include "servers/rendering/rendering_server_default.h"
+#include "servers/rendering/rendering_server_globals.h"
+
#ifdef GLES3_ENABLED
RasterizerSceneGLES3 *RasterizerSceneGLES3::singleton = nullptr;
@@ -95,7 +98,7 @@ void RasterizerSceneGLES3::GeometryInstanceGLES3::pair_light_instances(const RID
void RasterizerSceneGLES3::geometry_instance_free(RenderGeometryInstance *p_geometry_instance) {
GeometryInstanceGLES3 *ginstance = static_cast<GeometryInstanceGLES3 *>(p_geometry_instance);
- ERR_FAIL_COND(!ginstance);
+ ERR_FAIL_NULL(ginstance);
GeometryInstanceSurface *surf = ginstance->surface_caches;
while (surf) {
GeometryInstanceSurface *next = surf->next;
@@ -300,7 +303,7 @@ void RasterizerSceneGLES3::_geometry_instance_add_surface(GeometryInstanceGLES3
m_src = scene_globals.default_material;
}
- ERR_FAIL_COND(!material_data);
+ ERR_FAIL_NULL(material_data);
_geometry_instance_add_surface_with_material_chain(ginstance, p_surface, material_data, m_src, p_mesh);
@@ -462,7 +465,7 @@ void RasterizerSceneGLES3::sky_initialize(RID p_rid) {
void RasterizerSceneGLES3::sky_set_radiance_size(RID p_sky, int p_radiance_size) {
Sky *sky = sky_owner.get_or_null(p_sky);
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
ERR_FAIL_COND_MSG(p_radiance_size < 32 || p_radiance_size > 2048, "Sky radiance size must be between 32 and 2048");
if (sky->radiance_size == p_radiance_size) {
@@ -477,7 +480,7 @@ void RasterizerSceneGLES3::sky_set_radiance_size(RID p_sky, int p_radiance_size)
void RasterizerSceneGLES3::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
Sky *sky = sky_owner.get_or_null(p_sky);
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
if (sky->mode == p_mode) {
return;
@@ -489,7 +492,7 @@ void RasterizerSceneGLES3::sky_set_mode(RID p_sky, RS::SkyMode p_mode) {
void RasterizerSceneGLES3::sky_set_material(RID p_sky, RID p_material) {
Sky *sky = sky_owner.get_or_null(p_sky);
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
if (sky->material == p_material) {
return;
@@ -501,7 +504,7 @@ void RasterizerSceneGLES3::sky_set_material(RID p_sky, RID p_material) {
float RasterizerSceneGLES3::sky_get_baked_exposure(RID p_sky) const {
Sky *sky = sky_owner.get_or_null(p_sky);
- ERR_FAIL_COND_V(!sky, 1.0);
+ ERR_FAIL_NULL_V(sky, 1.0);
return sky->baked_exposure;
}
@@ -528,19 +531,24 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
glGenTextures(1, &sky->radiance);
glBindTexture(GL_TEXTURE_CUBE_MAP, sky->radiance);
-#ifdef GLES_OVER_GL
- GLenum format = GL_RGBA;
- GLenum type = GL_UNSIGNED_INT_2_10_10_10_REV;
- //TODO, on low-end compare this to allocating each face of each mip individually
- // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
- for (int i = 0; i < 6; i++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
- }
+#ifdef GL_API_ENABLED
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ GLenum format = GL_RGBA;
+ GLenum type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ //TODO, on low-end compare this to allocating each face of each mip individually
+ // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
+ }
- glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
-#else
- glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
-#endif
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ }
+#endif // GL_API_ENABLED
+#ifdef GLES_API_ENABLED
+ if (!RasterizerGLES3::is_gles_over_gl()) {
+ glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
+ }
+#endif // GLES_API_ENABLED
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -553,17 +561,24 @@ void RasterizerSceneGLES3::_update_dirty_skys() {
glGenTextures(1, &sky->raw_radiance);
glBindTexture(GL_TEXTURE_CUBE_MAP, sky->raw_radiance);
-#ifdef GLES_OVER_GL
- //TODO, on low-end compare this to allocating each face of each mip individually
- // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
- for (int i = 0; i < 6; i++) {
- glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
- }
+#ifdef GL_API_ENABLED
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ GLenum format = GL_RGBA;
+ GLenum type = GL_UNSIGNED_INT_2_10_10_10_REV;
+ //TODO, on low-end compare this to allocating each face of each mip individually
+ // see: https://www.khronos.org/registry/OpenGL-Refpages/es3.0/html/glTexStorage2D.xhtml
+ for (int i = 0; i < 6; i++) {
+ glTexImage2D(GL_TEXTURE_CUBE_MAP_POSITIVE_X + i, 0, internal_format, sky->radiance_size, sky->radiance_size, 0, format, type, nullptr);
+ }
- glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
-#else
- glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
-#endif
+ glGenerateMipmap(GL_TEXTURE_CUBE_MAP);
+ }
+#endif // GL_API_ENABLED
+#ifdef GLES_API_ENABLED
+ if (!RasterizerGLES3::is_gles_over_gl()) {
+ glTexStorage2D(GL_TEXTURE_CUBE_MAP, sky->mipmap_count, internal_format, sky->radiance_size, sky->radiance_size);
+ }
+#endif // GLES_API_ENABLED
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_CUBE_MAP, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
@@ -615,11 +630,11 @@ void RasterizerSceneGLES3::_setup_sky(const RenderDataGLES3 *p_render_data, cons
material = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
}
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
shader_data = material->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_NULL(shader_data);
if (sky) {
if (shader_data->uses_time && time - sky->prev_time > 0.00001) {
@@ -757,7 +772,7 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
ERR_FAIL_COND(p_env.is_null());
Sky *sky = sky_owner.get_or_null(environment_get_sky(p_env));
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
GLES3::SkyMaterialData *material_data = nullptr;
RID sky_material;
@@ -788,12 +803,12 @@ void RasterizerSceneGLES3::_draw_sky(RID p_env, const Projection &p_projection,
material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
}
- ERR_FAIL_COND(!material_data);
+ ERR_FAIL_NULL(material_data);
material_data->bind_uniforms();
GLES3::SkyShaderData *shader_data = material_data->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_NULL(shader_data);
// Camera
Projection camera;
@@ -836,7 +851,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
ERR_FAIL_COND(p_env.is_null());
Sky *sky = sky_owner.get_or_null(environment_get_sky(p_env));
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
GLES3::SkyMaterialData *material_data = nullptr;
RID sky_material;
@@ -844,7 +859,7 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
RS::EnvironmentBG background = environment_get_background(p_env);
if (sky) {
- ERR_FAIL_COND(!sky);
+ ERR_FAIL_NULL(sky);
sky_material = sky->material;
if (sky_material.is_valid()) {
@@ -863,12 +878,12 @@ void RasterizerSceneGLES3::_update_sky_radiance(RID p_env, const Projection &p_p
material_data = static_cast<GLES3::SkyMaterialData *>(material_storage->material_get_data(sky_material, RS::SHADER_SKY));
}
- ERR_FAIL_COND(!material_data);
+ ERR_FAIL_NULL(material_data);
material_data->bind_uniforms();
GLES3::SkyShaderData *shader_data = material_data->shader_data;
- ERR_FAIL_COND(!shader_data);
+ ERR_FAIL_NULL(shader_data);
bool update_single_frame = sky->mode == RS::SKY_MODE_REALTIME || sky->mode == RS::SKY_MODE_QUALITY;
RS::SkyMode sky_mode = sky->mode;
@@ -1731,7 +1746,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
}
GLES3::RenderTarget *rt = texture_storage->get_render_target(rb->render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
// Assign render data
// Use the format from rendererRD
@@ -1944,7 +1959,8 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
glDisable(GL_SCISSOR_TEST);
glColorMask(0, 0, 0, 0);
- glClearDepth(1.0f);
+ RasterizerGLES3::clear_depth(1.0);
+
glClear(GL_DEPTH_BUFFER_BIT);
uint64_t spec_constant = SceneShaderGLES3::DISABLE_FOG | SceneShaderGLES3::DISABLE_LIGHT_DIRECTIONAL |
SceneShaderGLES3::DISABLE_LIGHTMAP | SceneShaderGLES3::DISABLE_LIGHT_OMNI |
@@ -1979,7 +1995,7 @@ void RasterizerSceneGLES3::render_scene(const Ref<RenderSceneBuffers> &p_render_
scene_state.current_depth_draw = GLES3::SceneShaderData::DEPTH_DRAW_ALWAYS;
if (!fb_cleared) {
- glClearDepth(1.0f);
+ RasterizerGLES3::clear_depth(1.0);
glClear(GL_DEPTH_BUFFER_BIT);
}
@@ -2505,7 +2521,8 @@ void RasterizerSceneGLES3::render_particle_collider_heightfield(RID p_collider,
scene_state.cull_mode = GLES3::SceneShaderData::CULL_BACK;
glColorMask(0, 0, 0, 0);
- glClearDepth(1.0f);
+ RasterizerGLES3::clear_depth(1.0);
+
glClear(GL_DEPTH_BUFFER_BIT);
RenderListParameters render_list_params(render_list[RENDER_LIST_SECONDARY].elements.ptr(), render_list[RENDER_LIST_SECONDARY].elements.size(), false, 31, false);
@@ -2584,7 +2601,7 @@ bool RasterizerSceneGLES3::free(RID p_rid) {
environment_free(p_rid);
} else if (sky_owner.owns(p_rid)) {
Sky *sky = sky_owner.get_or_null(p_rid);
- ERR_FAIL_COND_V(!sky, false);
+ ERR_FAIL_NULL_V(sky, false);
_free_sky_data(sky);
sky_owner.free(p_rid);
} else if (GLES3::LightStorage::get_singleton()->owns_light_instance(p_rid)) {
@@ -2666,7 +2683,7 @@ RasterizerSceneGLES3::RasterizerSceneGLES3() {
global_defines += "#define MAX_GLOBAL_SHADER_UNIFORMS 256\n"; // TODO: this is arbitrary for now
global_defines += "\n#define MAX_LIGHT_DATA_STRUCTS " + itos(config->max_renderable_lights) + "\n";
global_defines += "\n#define MAX_DIRECTIONAL_LIGHT_DATA_STRUCTS " + itos(MAX_DIRECTIONAL_LIGHTS) + "\n";
- global_defines += "\n#define MAX_FORWARD_LIGHTS uint(" + itos(config->max_lights_per_object) + ")\n";
+ global_defines += "\n#define MAX_FORWARD_LIGHTS " + itos(config->max_lights_per_object) + "u\n";
material_storage->shaders.scene_shader.initialize(global_defines);
scene_globals.shader_default_version = material_storage->shaders.scene_shader.version_create();
material_storage->shaders.scene_shader.version_bind_shader(scene_globals.shader_default_version, SceneShaderGLES3::MODE_COLOR);
@@ -2778,9 +2795,11 @@ void sky() {
glBindBuffer(GL_ARRAY_BUFFER, 0); //unbind
}
-#ifdef GLES_OVER_GL
- glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS);
-#endif
+#ifdef GL_API_ENABLED
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ glEnable(_EXT_TEXTURE_CUBE_MAP_SEAMLESS);
+ }
+#endif // GL_API_ENABLED
// MultiMesh may read from color when color is disabled, so make sure that the color defaults to white instead of black;
glVertexAttrib4f(RS::ARRAY_COLOR, 1.0, 1.0, 1.0, 1.0);
diff --git a/drivers/gles3/shader_gles3.cpp b/drivers/gles3/shader_gles3.cpp
index b963224c21..51fed4da98 100644
--- a/drivers/gles3/shader_gles3.cpp
+++ b/drivers/gles3/shader_gles3.cpp
@@ -36,6 +36,8 @@
#include "core/io/dir_access.h"
#include "core/io/file_access.h"
+#include "drivers/gles3/rasterizer_gles3.h"
+
static String _mkid(const String &p_id) {
String id = "m_" + p_id.replace("__", "_dus_");
return id.replace("__", "_dus_"); //doubleunderscore is reserved in glsl
@@ -150,12 +152,12 @@ RID ShaderGLES3::version_create() {
}
void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant, const Version *p_version, StageType p_stage_type, uint64_t p_specialization) {
-#ifdef GLES_OVER_GL
- builder.append("#version 330\n");
- builder.append("#define USE_GLES_OVER_GL\n");
-#else
- builder.append("#version 300 es\n");
-#endif
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ builder.append("#version 330\n");
+ builder.append("#define USE_GLES_OVER_GL\n");
+ } else {
+ builder.append("#version 300 es\n");
+ }
for (int i = 0; i < specialization_count; i++) {
if (p_specialization & (uint64_t(1) << uint64_t(i))) {
@@ -199,11 +201,11 @@ void ShaderGLES3::_build_variant_code(StringBuilder &builder, uint32_t p_variant
// Default to highp precision unless specified otherwise.
builder.append("precision highp float;\n");
builder.append("precision highp int;\n");
-#ifndef GLES_OVER_GL
- builder.append("precision highp sampler2D;\n");
- builder.append("precision highp samplerCube;\n");
- builder.append("precision highp sampler2DArray;\n");
-#endif
+ if (!RasterizerGLES3::is_gles_over_gl()) {
+ builder.append("precision highp sampler2D;\n");
+ builder.append("precision highp samplerCube;\n");
+ builder.append("precision highp sampler2DArray;\n");
+ }
const StageTemplate &stage_template = stage_templates[p_stage_type];
for (uint32_t i = 0; i < stage_template.chunks.size(); i++) {
@@ -452,7 +454,7 @@ void ShaderGLES3::_compile_specialization(Version::Specialization &spec, uint32_
RS::ShaderNativeSourceCode ShaderGLES3::version_get_native_source_code(RID p_version) {
Version *version = version_owner.get_or_null(p_version);
RS::ShaderNativeSourceCode source_code;
- ERR_FAIL_COND_V(!version, source_code);
+ ERR_FAIL_NULL_V(version, source_code);
source_code.versions.resize(variant_count);
@@ -510,6 +512,11 @@ String ShaderGLES3::_version_get_sha1(Version *p_version) const {
hash_build.append("[custom_defines:" + itos(i) + "]");
hash_build.append(p_version->custom_defines[i].get_data());
}
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ hash_build.append("[gl]");
+ } else {
+ hash_build.append("[gles]");
+ }
return hash_build.as_string().sha1_text();
}
@@ -523,8 +530,8 @@ bool ShaderGLES3::_load_from_cache(Version *p_version) {
#ifdef WEB_ENABLED // not supported in webgl
return false;
#else
-#ifdef GLES_OVER_GL
- if (glProgramBinary == NULL) { // ARB_get_program_binary extension not available
+#if !defined(ANDROID_ENABLED) && !defined(IOS_ENABLED)
+ if (RasterizerGLES3::is_gles_over_gl() && (glProgramBinary == NULL)) { // ARB_get_program_binary extension not available.
return false;
}
#endif
@@ -596,8 +603,8 @@ void ShaderGLES3::_save_to_cache(Version *p_version) {
#ifdef WEB_ENABLED // not supported in webgl
return;
#else
-#ifdef GLES_OVER_GL
- if (glGetProgramBinary == NULL) { // ARB_get_program_binary extension not available
+#if !defined(ANDROID_ENABLED) && !defined(IOS_ENABLED)
+ if (RasterizerGLES3::is_gles_over_gl() && (glGetProgramBinary == NULL)) { // ARB_get_program_binary extension not available.
return;
}
#endif
@@ -685,7 +692,7 @@ void ShaderGLES3::_initialize_version(Version *p_version) {
void ShaderGLES3::version_set_code(RID p_version, const HashMap<String, String> &p_code, const String &p_uniforms, const String &p_vertex_globals, const String &p_fragment_globals, const Vector<String> &p_custom_defines, const LocalVector<ShaderGLES3::TextureUniformData> &p_texture_uniforms, bool p_initialize) {
Version *version = version_owner.get_or_null(p_version);
- ERR_FAIL_COND(!version);
+ ERR_FAIL_NULL(version);
_clear_version(version); //clear if existing
diff --git a/drivers/gles3/shader_gles3.h b/drivers/gles3/shader_gles3.h
index 7265202ced..0cb53da316 100644
--- a/drivers/gles3/shader_gles3.h
+++ b/drivers/gles3/shader_gles3.h
@@ -43,13 +43,7 @@
#ifdef GLES3_ENABLED
-// This must come first to avoid windows.h mess
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
+#include "platform_gl.h"
#include <stdio.h>
@@ -197,7 +191,7 @@ protected:
ERR_FAIL_INDEX_V(p_variant, variant_count, false);
Version *version = version_owner.get_or_null(p_version);
- ERR_FAIL_COND_V(!version, false);
+ ERR_FAIL_NULL_V(version, false);
if (version->variants.size() == 0) {
_initialize_version(version); //may lack initialization
@@ -235,10 +229,10 @@ protected:
_FORCE_INLINE_ int _version_get_uniform(int p_which, RID p_version, int p_variant, uint64_t p_specialization) {
ERR_FAIL_INDEX_V(p_which, uniform_count, -1);
Version *version = version_owner.get_or_null(p_version);
- ERR_FAIL_COND_V(!version, -1);
+ ERR_FAIL_NULL_V(version, -1);
ERR_FAIL_INDEX_V(p_variant, int(version->variants.size()), -1);
Version::Specialization *spec = version->variants[p_variant].lookup_ptr(p_specialization);
- ERR_FAIL_COND_V(!spec, -1);
+ ERR_FAIL_NULL_V(spec, -1);
ERR_FAIL_INDEX_V(p_which, int(spec->uniform_location.size()), -1);
return spec->uniform_location[p_which];
}
diff --git a/drivers/gles3/shaders/canvas.glsl b/drivers/gles3/shaders/canvas.glsl
index e47e3ae9a3..ce8fe25625 100644
--- a/drivers/gles3/shaders/canvas.glsl
+++ b/drivers/gles3/shaders/canvas.glsl
@@ -199,6 +199,10 @@ void main() {
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
+
+#ifdef USE_WORLD_VERTEX_COORDS
+ vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
+#endif
{
#CODE : VERTEX
}
@@ -207,7 +211,7 @@ void main() {
pixel_size_interp = abs(read_draw_data_dst_rect.zw) * vertex_base;
#endif
-#if !defined(SKIP_TRANSFORM_USED)
+#if !defined(SKIP_TRANSFORM_USED) && !defined(USE_WORLD_VERTEX_COORDS)
vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
#endif
diff --git a/drivers/gles3/storage/config.cpp b/drivers/gles3/storage/config.cpp
index 03dde88d4b..be7555788a 100644
--- a/drivers/gles3/storage/config.cpp
+++ b/drivers/gles3/storage/config.cpp
@@ -31,17 +31,9 @@
#ifdef GLES3_ENABLED
#include "config.h"
-#include "core/config/project_settings.h"
-#include "core/templates/vector.h"
-#ifdef ANDROID_ENABLED
-#include <GLES3/gl3.h>
-#include <GLES3/gl3ext.h>
-#include <GLES3/gl3platform.h>
-
-#include <EGL/egl.h>
-#include <EGL/eglext.h>
-#endif
+#include "../rasterizer_gles3.h"
+#include "texture_storage.h"
using namespace GLES3;
@@ -69,24 +61,24 @@ Config::Config() {
astc_hdr_supported = extensions.has("GL_KHR_texture_compression_astc_ldr");
astc_layered_supported = extensions.has("GL_KHR_texture_compression_astc_sliced_3d");
-#ifdef GLES_OVER_GL
- float_texture_supported = true;
- etc2_supported = false;
- s3tc_supported = true;
- rgtc_supported = true; //RGTC - core since OpenGL version 3.0
-#else
- float_texture_supported = extensions.has("GL_EXT_color_buffer_float");
- etc2_supported = true;
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ float_texture_supported = true;
+ etc2_supported = false;
+ s3tc_supported = true;
+ rgtc_supported = true; //RGTC - core since OpenGL version 3.0
+ } else {
+ float_texture_supported = extensions.has("GL_EXT_color_buffer_float");
+ etc2_supported = true;
#if defined(ANDROID_ENABLED) || defined(IOS_ENABLED)
- // Some Android devices report support for S3TC but we don't expect that and don't export the textures.
- // This could be fixed but so few devices support it that it doesn't seem useful (and makes bigger APKs).
- // For good measure we do the same hack for iOS, just in case.
- s3tc_supported = false;
+ // Some Android devices report support for S3TC but we don't expect that and don't export the textures.
+ // This could be fixed but so few devices support it that it doesn't seem useful (and makes bigger APKs).
+ // For good measure we do the same hack for iOS, just in case.
+ s3tc_supported = false;
#else
- s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc");
-#endif
- rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc");
+ s3tc_supported = extensions.has("GL_EXT_texture_compression_dxt1") || extensions.has("GL_EXT_texture_compression_s3tc") || extensions.has("WEBGL_compressed_texture_s3tc");
#endif
+ rgtc_supported = extensions.has("GL_EXT_texture_compression_rgtc") || extensions.has("GL_ARB_texture_compression_rgtc") || extensions.has("EXT_texture_compression_rgtc");
+ }
glGetInteger64v(GL_MAX_VERTEX_TEXTURE_IMAGE_UNITS, &max_vertex_texture_image_units);
glGetInteger64v(GL_MAX_TEXTURE_IMAGE_UNITS, &max_texture_image_units);
diff --git a/drivers/gles3/storage/config.h b/drivers/gles3/storage/config.h
index 6b90c8c359..b2dd98f025 100644
--- a/drivers/gles3/storage/config.h
+++ b/drivers/gles3/storage/config.h
@@ -33,16 +33,12 @@
#ifdef GLES3_ENABLED
+#include "core/config/project_settings.h"
#include "core/string/ustring.h"
#include "core/templates/hash_set.h"
+#include "core/templates/vector.h"
-// This must come first to avoid windows.h mess
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
+#include "platform_gl.h"
#ifdef ANDROID_ENABLED
typedef void (*PFNGLFRAMEBUFFERTEXTUREMULTIVIEWOVRPROC)(GLenum, GLenum, GLuint, GLint, GLint, GLsizei);
diff --git a/drivers/gles3/storage/light_storage.cpp b/drivers/gles3/storage/light_storage.cpp
index 5aab91e8ae..2fa99707b0 100644
--- a/drivers/gles3/storage/light_storage.cpp
+++ b/drivers/gles3/storage/light_storage.cpp
@@ -116,14 +116,14 @@ void LightStorage::light_free(RID p_rid) {
void LightStorage::light_set_color(RID p_light, const Color &p_color) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->color = p_color;
}
void LightStorage::light_set_param(RID p_light, RS::LightParam p_param, float p_value) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
ERR_FAIL_INDEX(p_param, RS::LIGHT_PARAM_MAX);
if (light->param[p_param] == p_value) {
@@ -158,7 +158,7 @@ void LightStorage::light_set_param(RID p_light, RS::LightParam p_param, float p_
void LightStorage::light_set_shadow(RID p_light, bool p_enabled) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->shadow = p_enabled;
light->version++;
@@ -168,7 +168,7 @@ void LightStorage::light_set_shadow(RID p_light, bool p_enabled) {
void LightStorage::light_set_projector(RID p_light, RID p_texture) {
GLES3::TextureStorage *texture_storage = GLES3::TextureStorage::get_singleton();
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
if (light->projector == p_texture) {
return;
@@ -190,14 +190,14 @@ void LightStorage::light_set_projector(RID p_light, RID p_texture) {
void LightStorage::light_set_negative(RID p_light, bool p_enable) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->negative = p_enable;
}
void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->cull_mask = p_mask;
@@ -207,7 +207,7 @@ void LightStorage::light_set_cull_mask(RID p_light, uint32_t p_mask) {
void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_begin, float p_shadow, float p_length) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->distance_fade = p_enabled;
light->distance_fade_begin = p_begin;
@@ -217,7 +217,7 @@ void LightStorage::light_set_distance_fade(RID p_light, bool p_enabled, float p_
void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->reverse_cull = p_enabled;
@@ -227,7 +227,7 @@ void LightStorage::light_set_reverse_cull_face_mode(RID p_light, bool p_enabled)
void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mode) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->bake_mode = p_bake_mode;
@@ -237,7 +237,7 @@ void LightStorage::light_set_bake_mode(RID p_light, RS::LightBakeMode p_bake_mod
void LightStorage::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMode p_mode) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->omni_shadow_mode = p_mode;
@@ -247,14 +247,14 @@ void LightStorage::light_omni_set_shadow_mode(RID p_light, RS::LightOmniShadowMo
RS::LightOmniShadowMode LightStorage::light_omni_get_shadow_mode(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_OMNI_SHADOW_CUBE);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_OMNI_SHADOW_CUBE);
return light->omni_shadow_mode;
}
void LightStorage::light_directional_set_shadow_mode(RID p_light, RS::LightDirectionalShadowMode p_mode) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->directional_shadow_mode = p_mode;
light->version++;
@@ -263,7 +263,7 @@ void LightStorage::light_directional_set_shadow_mode(RID p_light, RS::LightDirec
void LightStorage::light_directional_set_blend_splits(RID p_light, bool p_enable) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->directional_blend_splits = p_enable;
light->version++;
@@ -272,56 +272,56 @@ void LightStorage::light_directional_set_blend_splits(RID p_light, bool p_enable
bool LightStorage::light_directional_get_blend_splits(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, false);
+ ERR_FAIL_NULL_V(light, false);
return light->directional_blend_splits;
}
void LightStorage::light_directional_set_sky_mode(RID p_light, RS::LightDirectionalSkyMode p_mode) {
Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND(!light);
+ ERR_FAIL_NULL(light);
light->directional_sky_mode = p_mode;
}
RS::LightDirectionalSkyMode LightStorage::light_directional_get_sky_mode(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL_SKY_MODE_LIGHT_AND_SKY);
return light->directional_sky_mode;
}
RS::LightDirectionalShadowMode LightStorage::light_directional_get_shadow_mode(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL_SHADOW_ORTHOGONAL);
return light->directional_shadow_mode;
}
RS::LightBakeMode LightStorage::light_get_bake_mode(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_BAKE_DISABLED);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_BAKE_DISABLED);
return light->bake_mode;
}
uint64_t LightStorage::light_get_version(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0);
+ ERR_FAIL_NULL_V(light, 0);
return light->version;
}
uint32_t LightStorage::light_get_cull_mask(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0);
+ ERR_FAIL_NULL_V(light, 0);
return light->cull_mask;
}
AABB LightStorage::light_get_aabb(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, AABB());
+ ERR_FAIL_NULL_V(light, AABB());
switch (light->type) {
case RS::LIGHT_SPOT: {
@@ -357,20 +357,20 @@ RID LightStorage::light_instance_create(RID p_light) {
void LightStorage::light_instance_free(RID p_light_instance) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
+ ERR_FAIL_NULL(light_instance);
light_instance_owner.free(p_light_instance);
}
void LightStorage::light_instance_set_transform(RID p_light_instance, const Transform3D &p_transform) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
+ ERR_FAIL_NULL(light_instance);
light_instance->transform = p_transform;
}
void LightStorage::light_instance_set_aabb(RID p_light_instance, const AABB &p_aabb) {
LightInstance *light_instance = light_instance_owner.get_or_null(p_light_instance);
- ERR_FAIL_COND(!light_instance);
+ ERR_FAIL_NULL(light_instance);
light_instance->aabb = p_aabb;
}
diff --git a/drivers/gles3/storage/light_storage.h b/drivers/gles3/storage/light_storage.h
index 0f8120be15..8491b378fe 100644
--- a/drivers/gles3/storage/light_storage.h
+++ b/drivers/gles3/storage/light_storage.h
@@ -33,6 +33,8 @@
#ifdef GLES3_ENABLED
+#include "platform_gl.h"
+
#include "core/templates/local_vector.h"
#include "core/templates/rid_owner.h"
#include "core/templates/self_list.h"
@@ -41,13 +43,6 @@
#include "servers/rendering/storage/light_storage.h"
#include "servers/rendering/storage/utilities.h"
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
-
namespace GLES3 {
/* LIGHT */
@@ -212,7 +207,7 @@ public:
virtual RS::LightOmniShadowMode light_omni_get_shadow_mode(RID p_light) override;
virtual RS::LightType light_get_type(RID p_light) const override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
return light->type;
}
@@ -220,21 +215,21 @@ public:
virtual float light_get_param(RID p_light, RS::LightParam p_param) override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0);
+ ERR_FAIL_NULL_V(light, 0);
return light->param[p_param];
}
_FORCE_INLINE_ RID light_get_projector(RID p_light) {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RID());
+ ERR_FAIL_NULL_V(light, RID());
return light->projector;
}
virtual Color light_get_color(RID p_light) override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, Color());
+ ERR_FAIL_NULL_V(light, Color());
return light->color;
}
@@ -261,35 +256,35 @@ public:
virtual bool light_has_shadow(RID p_light) const override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
return light->shadow;
}
virtual bool light_has_projector(RID p_light) const override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
return TextureStorage::get_singleton()->owns_texture(light->projector);
}
_FORCE_INLINE_ bool light_is_negative(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, RS::LIGHT_DIRECTIONAL);
+ ERR_FAIL_NULL_V(light, RS::LIGHT_DIRECTIONAL);
return light->negative;
}
_FORCE_INLINE_ float light_get_transmittance_bias(RID p_light) const {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, 0.0);
+ ERR_FAIL_NULL_V(light, 0.0);
return light->param[RS::LIGHT_PARAM_TRANSMITTANCE_BIAS];
}
virtual bool light_get_reverse_cull_face_mode(RID p_light) const override {
const Light *light = light_owner.get_or_null(p_light);
- ERR_FAIL_COND_V(!light, false);
+ ERR_FAIL_NULL_V(light, false);
return light->reverse_cull;
}
diff --git a/drivers/gles3/storage/material_storage.cpp b/drivers/gles3/storage/material_storage.cpp
index 32b62ee605..a594813ed0 100644
--- a/drivers/gles3/storage/material_storage.cpp
+++ b/drivers/gles3/storage/material_storage.cpp
@@ -1184,6 +1184,7 @@ MaterialStorage::MaterialStorage() {
actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n";
+ actions.render_mode_defines["world_vertex_coords"] = "#define USE_WORLD_VERTEX_COORDS\n";
actions.global_buffer_array_variable = "global_shader_uniforms";
@@ -2137,7 +2138,7 @@ void MaterialStorage::shader_initialize(RID p_rid) {
void MaterialStorage::shader_free(RID p_rid) {
GLES3::Shader *shader = shader_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
//make material unreference this
while (shader->owners.size()) {
@@ -2153,7 +2154,7 @@ void MaterialStorage::shader_free(RID p_rid) {
void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
shader->code = p_code;
@@ -2231,7 +2232,7 @@ void MaterialStorage::shader_set_code(RID p_shader, const String &p_code) {
void MaterialStorage::shader_set_path_hint(RID p_shader, const String &p_path) {
GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
shader->path_hint = p_path;
if (shader->data) {
@@ -2241,13 +2242,13 @@ void MaterialStorage::shader_set_path_hint(RID p_shader, const String &p_path) {
String MaterialStorage::shader_get_code(RID p_shader) const {
const GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, String());
+ ERR_FAIL_NULL_V(shader, String());
return shader->code;
}
void MaterialStorage::get_shader_parameter_list(RID p_shader, List<PropertyInfo> *p_param_list) const {
GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
if (shader->data) {
return shader->data->get_shader_uniform_list(p_param_list);
}
@@ -2255,7 +2256,7 @@ void MaterialStorage::get_shader_parameter_list(RID p_shader, List<PropertyInfo>
void MaterialStorage::shader_set_default_texture_parameter(RID p_shader, const StringName &p_name, RID p_texture, int p_index) {
GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
if (p_texture.is_valid() && TextureStorage::get_singleton()->owns_texture(p_texture)) {
if (!shader->default_texture_parameter.has(p_name)) {
@@ -2282,7 +2283,7 @@ void MaterialStorage::shader_set_default_texture_parameter(RID p_shader, const S
RID MaterialStorage::shader_get_default_texture_parameter(RID p_shader, const StringName &p_name, int p_index) const {
const GLES3::Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, RID());
+ ERR_FAIL_NULL_V(shader, RID());
if (shader->default_texture_parameter.has(p_name) && shader->default_texture_parameter[p_name].has(p_index)) {
return shader->default_texture_parameter[p_name][p_index];
}
@@ -2292,7 +2293,7 @@ RID MaterialStorage::shader_get_default_texture_parameter(RID p_shader, const St
Variant MaterialStorage::shader_get_parameter_default(RID p_shader, const StringName &p_param) const {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, Variant());
+ ERR_FAIL_NULL_V(shader, Variant());
if (shader->data) {
return shader->data->get_default_parameter(p_param);
}
@@ -2301,7 +2302,7 @@ Variant MaterialStorage::shader_get_parameter_default(RID p_shader, const String
RS::ShaderNativeSourceCode MaterialStorage::shader_get_native_source_code(RID p_shader) const {
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, RS::ShaderNativeSourceCode());
+ ERR_FAIL_NULL_V(shader, RS::ShaderNativeSourceCode());
if (shader->data) {
return shader->data->get_native_source_code();
}
@@ -2347,7 +2348,7 @@ void MaterialStorage::material_initialize(RID p_rid) {
void MaterialStorage::material_free(RID p_rid) {
Material *material = material_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
// Need to clear texture arrays to prevent spin locking of their RID's.
// This happens when the app is being closed.
@@ -2365,7 +2366,7 @@ void MaterialStorage::material_free(RID p_rid) {
void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
GLES3::Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
if (material->data) {
memdelete(material->data);
@@ -2385,7 +2386,7 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
}
Shader *shader = get_shader(p_shader);
- ERR_FAIL_COND(!shader);
+ ERR_FAIL_NULL(shader);
material->shader = shader;
material->shader_mode = shader->mode;
material->shader_id = p_shader.get_local_index();
@@ -2408,7 +2409,7 @@ void MaterialStorage::material_set_shader(RID p_material, RID p_shader) {
void MaterialStorage::material_set_param(RID p_material, const StringName &p_param, const Variant &p_value) {
GLES3::Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
if (p_value.get_type() == Variant::NIL) {
material->params.erase(p_param);
@@ -2427,7 +2428,7 @@ void MaterialStorage::material_set_param(RID p_material, const StringName &p_par
Variant MaterialStorage::material_get_param(RID p_material, const StringName &p_param) const {
const GLES3::Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, Variant());
+ ERR_FAIL_NULL_V(material, Variant());
if (material->params.has(p_param)) {
return material->params[p_param];
} else {
@@ -2437,7 +2438,7 @@ Variant MaterialStorage::material_get_param(RID p_material, const StringName &p_
void MaterialStorage::material_set_next_pass(RID p_material, RID p_next_material) {
GLES3::Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
if (material->next_pass == p_next_material) {
return;
@@ -2456,7 +2457,7 @@ void MaterialStorage::material_set_render_priority(RID p_material, int priority)
ERR_FAIL_COND(priority > RS::MATERIAL_RENDER_PRIORITY_MAX);
GLES3::Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
material->priority = priority;
if (material->data) {
material->data->set_render_priority(priority);
@@ -2466,7 +2467,7 @@ void MaterialStorage::material_set_render_priority(RID p_material, int priority)
bool MaterialStorage::material_is_animated(RID p_material) {
GLES3::Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, false);
+ ERR_FAIL_NULL_V(material, false);
if (material->shader && material->shader->data) {
if (material->shader->data->is_animated()) {
return true;
@@ -2479,7 +2480,7 @@ bool MaterialStorage::material_is_animated(RID p_material) {
bool MaterialStorage::material_casts_shadows(RID p_material) {
GLES3::Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND_V(!material, true);
+ ERR_FAIL_NULL_V(material, true);
if (material->shader && material->shader->data) {
if (material->shader->data->casts_shadows()) {
return true;
@@ -2492,7 +2493,7 @@ bool MaterialStorage::material_casts_shadows(RID p_material) {
void MaterialStorage::material_get_instance_shader_parameters(RID p_material, List<InstanceShaderParam> *r_parameters) {
GLES3::Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
if (material->shader && material->shader->data) {
material->shader->data->get_instance_param_list(r_parameters);
@@ -2504,7 +2505,7 @@ void MaterialStorage::material_get_instance_shader_parameters(RID p_material, Li
void MaterialStorage::material_update_dependency(RID p_material, DependencyTracker *p_instance) {
Material *material = material_owner.get_or_null(p_material);
- ERR_FAIL_COND(!material);
+ ERR_FAIL_NULL(material);
p_instance->update_dependency(&material->dependency);
if (material->next_pass.is_valid()) {
material_update_dependency(material->next_pass, p_instance);
diff --git a/drivers/gles3/storage/mesh_storage.cpp b/drivers/gles3/storage/mesh_storage.cpp
index a96a491517..cc6031fa57 100644
--- a/drivers/gles3/storage/mesh_storage.cpp
+++ b/drivers/gles3/storage/mesh_storage.cpp
@@ -70,7 +70,7 @@ void MeshStorage::mesh_free(RID p_rid) {
mesh_clear(p_rid);
mesh_set_shadow_mesh(p_rid, RID());
Mesh *mesh = mesh_owner.get_or_null(p_rid);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
mesh->dependency.deleted_notify(p_rid);
if (mesh->instances.size()) {
@@ -90,7 +90,7 @@ void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count
ERR_FAIL_COND(p_blend_shape_count < 0);
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_COND(mesh->surface_count > 0); //surfaces already exist
mesh->blend_shape_count = p_blend_shape_count;
@@ -98,14 +98,14 @@ void MeshStorage::mesh_set_blend_shape_count(RID p_mesh, int p_blend_shape_count
bool MeshStorage::mesh_needs_instance(RID p_mesh, bool p_has_skeleton) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, false);
+ ERR_FAIL_NULL_V(mesh, false);
return mesh->blend_shape_count > 0 || (mesh->has_bone_weights && p_has_skeleton);
}
void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_COND(mesh->surface_count == RS::MAX_MESH_SURFACES);
@@ -352,13 +352,13 @@ void MeshStorage::mesh_add_surface(RID p_mesh, const RS::SurfaceData &p_surface)
int MeshStorage::mesh_get_blend_shape_count(RID p_mesh) const {
const Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, -1);
+ ERR_FAIL_NULL_V(mesh, -1);
return mesh->blend_shape_count;
}
void MeshStorage::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mode) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_INDEX((int)p_mode, 2);
mesh->blend_shape_mode = p_mode;
@@ -366,13 +366,13 @@ void MeshStorage::mesh_set_blend_shape_mode(RID p_mesh, RS::BlendShapeMode p_mod
RS::BlendShapeMode MeshStorage::mesh_get_blend_shape_mode(RID p_mesh) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
+ ERR_FAIL_NULL_V(mesh, RS::BLEND_SHAPE_MODE_NORMALIZED);
return mesh->blend_shape_mode;
}
void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
ERR_FAIL_COND(p_data.size() == 0);
@@ -387,7 +387,7 @@ void MeshStorage::mesh_surface_update_vertex_region(RID p_mesh, int p_surface, i
void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
ERR_FAIL_COND(p_data.size() == 0);
@@ -402,7 +402,7 @@ void MeshStorage::mesh_surface_update_attribute_region(RID p_mesh, int p_surface
void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int p_offset, const Vector<uint8_t> &p_data) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
ERR_FAIL_COND(p_data.size() == 0);
@@ -417,7 +417,7 @@ void MeshStorage::mesh_surface_update_skin_region(RID p_mesh, int p_surface, int
void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_material) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
ERR_FAIL_UNSIGNED_INDEX((uint32_t)p_surface, mesh->surface_count);
mesh->surfaces[p_surface]->material = p_material;
@@ -427,7 +427,7 @@ void MeshStorage::mesh_surface_set_material(RID p_mesh, int p_surface, RID p_mat
RID MeshStorage::mesh_surface_get_material(RID p_mesh, int p_surface) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_NULL_V(mesh, RID());
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RID());
return mesh->surfaces[p_surface]->material;
@@ -435,7 +435,7 @@ RID MeshStorage::mesh_surface_get_material(RID p_mesh, int p_surface) const {
RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, RS::SurfaceData());
+ ERR_FAIL_NULL_V(mesh, RS::SurfaceData());
ERR_FAIL_UNSIGNED_INDEX_V((uint32_t)p_surface, mesh->surface_count, RS::SurfaceData());
Mesh::Surface &s = *mesh->surfaces[p_surface];
@@ -484,13 +484,13 @@ RS::SurfaceData MeshStorage::mesh_get_surface(RID p_mesh, int p_surface) const {
int MeshStorage::mesh_get_surface_count(RID p_mesh) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, 0);
+ ERR_FAIL_NULL_V(mesh, 0);
return mesh->surface_count;
}
void MeshStorage::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
mesh->custom_aabb = p_aabb;
mesh->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
@@ -498,13 +498,13 @@ void MeshStorage::mesh_set_custom_aabb(RID p_mesh, const AABB &p_aabb) {
AABB MeshStorage::mesh_get_custom_aabb(RID p_mesh) const {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, AABB());
+ ERR_FAIL_NULL_V(mesh, AABB());
return mesh->custom_aabb;
}
AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, AABB());
+ ERR_FAIL_NULL_V(mesh, AABB());
if (mesh->custom_aabb != AABB()) {
return mesh->custom_aabb;
@@ -613,7 +613,7 @@ AABB MeshStorage::mesh_get_aabb(RID p_mesh, RID p_skeleton) {
void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
Mesh *shadow_mesh = mesh_owner.get_or_null(mesh->shadow_mesh);
if (shadow_mesh) {
@@ -632,7 +632,7 @@ void MeshStorage::mesh_set_shadow_mesh(RID p_mesh, RID p_shadow_mesh) {
void MeshStorage::mesh_clear(RID p_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND(!mesh);
+ ERR_FAIL_NULL(mesh);
// Clear instance data before mesh data.
for (MeshInstance *mi : mesh->instances) {
@@ -862,7 +862,7 @@ void MeshStorage::_mesh_surface_generate_version_for_input_mask(Mesh::Surface::V
RID MeshStorage::mesh_instance_create(RID p_base) {
Mesh *mesh = mesh_owner.get_or_null(p_base);
- ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_NULL_V(mesh, RID());
RID rid = mesh_instance_owner.make_rid();
MeshInstance *mi = mesh_instance_owner.get_or_null(rid);
@@ -901,7 +901,7 @@ void MeshStorage::mesh_instance_set_skeleton(RID p_mesh_instance, RID p_skeleton
void MeshStorage::mesh_instance_set_blend_shape_weight(RID p_mesh_instance, int p_shape, float p_weight) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
- ERR_FAIL_COND(!mi);
+ ERR_FAIL_NULL(mi);
ERR_FAIL_INDEX(p_shape, (int)mi->blend_weights.size());
mi->blend_weights[p_shape] = p_weight;
mi->dirty = true;
@@ -1268,7 +1268,7 @@ void MeshStorage::multimesh_free(RID p_rid) {
void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::MultimeshTransformFormat p_transform_format, bool p_use_colors, bool p_use_custom_data) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
if (multimesh->instances == p_instances && multimesh->xform_format == p_transform_format && multimesh->uses_colors == p_use_colors && multimesh->uses_custom_data == p_use_custom_data) {
return;
@@ -1315,13 +1315,13 @@ void MeshStorage::multimesh_allocate_data(RID p_multimesh, int p_instances, RS::
int MeshStorage::multimesh_get_instance_count(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, 0);
+ ERR_FAIL_NULL_V(multimesh, 0);
return multimesh->instances;
}
void MeshStorage::multimesh_set_mesh(RID p_multimesh, RID p_mesh) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
if (multimesh->mesh == p_mesh || p_mesh.is_null()) {
return;
}
@@ -1468,7 +1468,7 @@ void MeshStorage::_multimesh_re_create_aabb(MultiMesh *multimesh, const float *p
void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index, const Transform3D &p_transform) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D);
@@ -1498,7 +1498,7 @@ void MeshStorage::multimesh_instance_set_transform(RID p_multimesh, int p_index,
void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_index, const Transform2D &p_transform) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D);
@@ -1524,7 +1524,7 @@ void MeshStorage::multimesh_instance_set_transform_2d(RID p_multimesh, int p_ind
void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, const Color &p_color) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(!multimesh->uses_colors);
@@ -1544,7 +1544,7 @@ void MeshStorage::multimesh_instance_set_color(RID p_multimesh, int p_index, con
void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_index, const Color &p_color) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_INDEX(p_index, multimesh->instances);
ERR_FAIL_COND(!multimesh->uses_custom_data);
@@ -1563,14 +1563,14 @@ void MeshStorage::multimesh_instance_set_custom_data(RID p_multimesh, int p_inde
RID MeshStorage::multimesh_get_mesh(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, RID());
+ ERR_FAIL_NULL_V(multimesh, RID());
return multimesh->mesh;
}
AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, AABB());
+ ERR_FAIL_NULL_V(multimesh, AABB());
if (multimesh->aabb_dirty) {
const_cast<MeshStorage *>(this)->_update_dirty_multimeshes();
}
@@ -1579,7 +1579,7 @@ AABB MeshStorage::multimesh_get_aabb(RID p_multimesh) const {
Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Transform3D());
+ ERR_FAIL_NULL_V(multimesh, Transform3D());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform3D());
ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_3D, Transform3D());
@@ -1610,7 +1610,7 @@ Transform3D MeshStorage::multimesh_instance_get_transform(RID p_multimesh, int p
Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Transform2D());
+ ERR_FAIL_NULL_V(multimesh, Transform2D());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Transform2D());
ERR_FAIL_COND_V(multimesh->xform_format != RS::MULTIMESH_TRANSFORM_2D, Transform2D());
@@ -1635,7 +1635,7 @@ Transform2D MeshStorage::multimesh_instance_get_transform_2d(RID p_multimesh, in
Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_NULL_V(multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
ERR_FAIL_COND_V(!multimesh->uses_colors, Color());
@@ -1659,7 +1659,7 @@ Color MeshStorage::multimesh_instance_get_color(RID p_multimesh, int p_index) co
Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_index) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Color());
+ ERR_FAIL_NULL_V(multimesh, Color());
ERR_FAIL_INDEX_V(p_index, multimesh->instances, Color());
ERR_FAIL_COND_V(!multimesh->uses_custom_data, Color());
@@ -1683,7 +1683,7 @@ Color MeshStorage::multimesh_instance_get_custom_data(RID p_multimesh, int p_ind
void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_buffer) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
if (multimesh->uses_colors || multimesh->uses_custom_data) {
// Color and custom need to be packed so copy buffer to data_cache and pack.
@@ -1769,7 +1769,7 @@ void MeshStorage::multimesh_set_buffer(RID p_multimesh, const Vector<float> &p_b
Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, Vector<float>());
+ ERR_FAIL_NULL_V(multimesh, Vector<float>());
Vector<float> ret;
if (multimesh->buffer == 0 || multimesh->instances == 0) {
return Vector<float>();
@@ -1841,7 +1841,7 @@ Vector<float> MeshStorage::multimesh_get_buffer(RID p_multimesh) const {
void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible) {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND(!multimesh);
+ ERR_FAIL_NULL(multimesh);
ERR_FAIL_COND(p_visible < -1 || p_visible > multimesh->instances);
if (multimesh->visible_instances == p_visible) {
return;
@@ -1863,7 +1863,7 @@ void MeshStorage::multimesh_set_visible_instances(RID p_multimesh, int p_visible
int MeshStorage::multimesh_get_visible_instances(RID p_multimesh) const {
MultiMesh *multimesh = multimesh_owner.get_or_null(p_multimesh);
- ERR_FAIL_COND_V(!multimesh, 0);
+ ERR_FAIL_NULL_V(multimesh, 0);
return multimesh->visible_instances;
}
@@ -1953,7 +1953,7 @@ void MeshStorage::_skeleton_make_dirty(Skeleton *skeleton) {
void MeshStorage::skeleton_allocate_data(RID p_skeleton, int p_bones, bool p_2d_skeleton) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
ERR_FAIL_COND(p_bones < 0);
if (skeleton->size == p_bones && skeleton->use_2d == p_2d_skeleton) {
@@ -2004,7 +2004,7 @@ void MeshStorage::skeleton_set_base_transform_2d(RID p_skeleton, const Transform
int MeshStorage::skeleton_get_bone_count(RID p_skeleton) const {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, 0);
+ ERR_FAIL_NULL_V(skeleton, 0);
return skeleton->size;
}
@@ -2012,7 +2012,7 @@ int MeshStorage::skeleton_get_bone_count(RID p_skeleton) const {
void MeshStorage::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const Transform3D &p_transform) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
ERR_FAIL_INDEX(p_bone, skeleton->size);
ERR_FAIL_COND(skeleton->use_2d);
@@ -2037,7 +2037,7 @@ void MeshStorage::skeleton_bone_set_transform(RID p_skeleton, int p_bone, const
Transform3D MeshStorage::skeleton_bone_get_transform(RID p_skeleton, int p_bone) const {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, Transform3D());
+ ERR_FAIL_NULL_V(skeleton, Transform3D());
ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform3D());
ERR_FAIL_COND_V(skeleton->use_2d, Transform3D());
@@ -2064,7 +2064,7 @@ Transform3D MeshStorage::skeleton_bone_get_transform(RID p_skeleton, int p_bone)
void MeshStorage::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, const Transform2D &p_transform) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
ERR_FAIL_INDEX(p_bone, skeleton->size);
ERR_FAIL_COND(!skeleton->use_2d);
@@ -2085,7 +2085,7 @@ void MeshStorage::skeleton_bone_set_transform_2d(RID p_skeleton, int p_bone, con
Transform2D MeshStorage::skeleton_bone_get_transform_2d(RID p_skeleton, int p_bone) const {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND_V(!skeleton, Transform2D());
+ ERR_FAIL_NULL_V(skeleton, Transform2D());
ERR_FAIL_INDEX_V(p_bone, skeleton->size, Transform2D());
ERR_FAIL_COND_V(!skeleton->use_2d, Transform2D());
@@ -2127,7 +2127,7 @@ void MeshStorage::_update_dirty_skeletons() {
void MeshStorage::skeleton_update_dependency(RID p_skeleton, DependencyTracker *p_instance) {
Skeleton *skeleton = skeleton_owner.get_or_null(p_skeleton);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
p_instance->update_dependency(&skeleton->dependency);
}
diff --git a/drivers/gles3/storage/mesh_storage.h b/drivers/gles3/storage/mesh_storage.h
index f9122771f9..09212e4b5c 100644
--- a/drivers/gles3/storage/mesh_storage.h
+++ b/drivers/gles3/storage/mesh_storage.h
@@ -40,12 +40,7 @@
#include "servers/rendering/storage/mesh_storage.h"
#include "servers/rendering/storage/utilities.h"
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
+#include "platform_gl.h"
namespace GLES3 {
@@ -302,7 +297,7 @@ public:
_FORCE_INLINE_ const RID *mesh_get_surface_count_and_materials(RID p_mesh, uint32_t &r_surface_count) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, nullptr);
+ ERR_FAIL_NULL_V(mesh, nullptr);
r_surface_count = mesh->surface_count;
if (r_surface_count == 0) {
return nullptr;
@@ -319,7 +314,7 @@ public:
_FORCE_INLINE_ void *mesh_get_surface(RID p_mesh, uint32_t p_surface_index) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, nullptr);
+ ERR_FAIL_NULL_V(mesh, nullptr);
ERR_FAIL_UNSIGNED_INDEX_V(p_surface_index, mesh->surface_count, nullptr);
return mesh->surfaces[p_surface_index];
@@ -327,7 +322,7 @@ public:
_FORCE_INLINE_ RID mesh_get_shadow_mesh(RID p_mesh) {
Mesh *mesh = mesh_owner.get_or_null(p_mesh);
- ERR_FAIL_COND_V(!mesh, RID());
+ ERR_FAIL_NULL_V(mesh, RID());
return mesh->shadow_mesh;
}
@@ -349,7 +344,7 @@ public:
_FORCE_INLINE_ uint32_t mesh_surface_get_lod(void *p_surface, float p_model_scale, float p_distance_threshold, float p_mesh_lod_threshold, uint32_t &r_index_count) const {
Mesh::Surface *s = reinterpret_cast<Mesh::Surface *>(p_surface);
- ERR_FAIL_COND_V(!s, 0);
+ ERR_FAIL_NULL_V(s, 0);
int32_t current_lod = -1;
r_index_count = s->index_count;
@@ -431,7 +426,7 @@ public:
// Doing so would allow us to avoid specifying multimesh buffer pointers every frame and may improve performance.
_FORCE_INLINE_ void mesh_instance_surface_get_vertex_arrays_and_format(RID p_mesh_instance, uint32_t p_surface_index, uint32_t p_input_mask, GLuint &r_vertex_array_gl) {
MeshInstance *mi = mesh_instance_owner.get_or_null(p_mesh_instance);
- ERR_FAIL_COND(!mi);
+ ERR_FAIL_NULL(mi);
Mesh *mesh = mi->mesh;
ERR_FAIL_UNSIGNED_INDEX(p_surface_index, mesh->surface_count);
diff --git a/drivers/gles3/storage/particles_storage.cpp b/drivers/gles3/storage/particles_storage.cpp
index b7ebe055f5..0a6f02511c 100644
--- a/drivers/gles3/storage/particles_storage.cpp
+++ b/drivers/gles3/storage/particles_storage.cpp
@@ -107,7 +107,7 @@ void ParticlesStorage::particles_free(RID p_rid) {
void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_mode) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
if (particles->mode == p_mode) {
return;
}
@@ -119,7 +119,7 @@ void ParticlesStorage::particles_set_mode(RID p_particles, RS::ParticlesMode p_m
void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->emitting = p_emitting;
}
@@ -127,7 +127,7 @@ void ParticlesStorage::particles_set_emitting(RID p_particles, bool p_emitting)
bool ParticlesStorage::particles_get_emitting(RID p_particles) {
ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, false);
+ ERR_FAIL_NULL_V(particles, false);
return particles->emitting;
}
@@ -172,7 +172,7 @@ void ParticlesStorage::_particles_free_data(Particles *particles) {
void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
if (particles->amount == p_amount) {
return;
@@ -192,48 +192,48 @@ void ParticlesStorage::particles_set_amount(RID p_particles, int p_amount) {
void ParticlesStorage::particles_set_lifetime(RID p_particles, double p_lifetime) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->lifetime = p_lifetime;
}
void ParticlesStorage::particles_set_one_shot(RID p_particles, bool p_one_shot) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->one_shot = p_one_shot;
}
void ParticlesStorage::particles_set_pre_process_time(RID p_particles, double p_time) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->pre_process_time = p_time;
}
void ParticlesStorage::particles_set_explosiveness_ratio(RID p_particles, real_t p_ratio) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->explosiveness = p_ratio;
}
void ParticlesStorage::particles_set_randomness_ratio(RID p_particles, real_t p_ratio) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->randomness = p_ratio;
}
void ParticlesStorage::particles_set_custom_aabb(RID p_particles, const AABB &p_aabb) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->custom_aabb = p_aabb;
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void ParticlesStorage::particles_set_speed_scale(RID p_particles, double p_scale) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->speed_scale = p_scale;
}
void ParticlesStorage::particles_set_use_local_coordinates(RID p_particles, bool p_enable) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->use_local_coords = p_enable;
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
@@ -241,7 +241,7 @@ void ParticlesStorage::particles_set_use_local_coordinates(RID p_particles, bool
void ParticlesStorage::particles_set_fixed_fps(RID p_particles, int p_fps) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->fixed_fps = p_fps;
@@ -257,14 +257,14 @@ void ParticlesStorage::particles_set_fixed_fps(RID p_particles, int p_fps) {
void ParticlesStorage::particles_set_interpolate(RID p_particles, bool p_enable) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->interpolate = p_enable;
}
void ParticlesStorage::particles_set_fractional_delta(RID p_particles, bool p_enable) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->fractional_delta = p_enable;
}
@@ -283,21 +283,21 @@ void ParticlesStorage::particles_set_trail_bind_poses(RID p_particles, const Vec
void ParticlesStorage::particles_set_collision_base_size(RID p_particles, real_t p_size) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->collision_base_size = p_size;
}
void ParticlesStorage::particles_set_transform_align(RID p_particles, RS::ParticlesTransformAlign p_transform_align) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->transform_align = p_transform_align;
}
void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_material) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->process_material = p_material;
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES); //the instance buffer may have changed
@@ -305,28 +305,28 @@ void ParticlesStorage::particles_set_process_material(RID p_particles, RID p_mat
RID ParticlesStorage::particles_get_process_material(RID p_particles) const {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, RID());
+ ERR_FAIL_NULL_V(particles, RID());
return particles->process_material;
}
void ParticlesStorage::particles_set_draw_order(RID p_particles, RS::ParticlesDrawOrder p_order) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->draw_order = p_order;
}
void ParticlesStorage::particles_set_draw_passes(RID p_particles, int p_passes) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->draw_passes.resize(p_passes);
}
void ParticlesStorage::particles_set_draw_pass_mesh(RID p_particles, int p_pass, RID p_mesh) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
ERR_FAIL_INDEX(p_pass, particles->draw_passes.size());
particles->draw_passes.write[p_pass] = p_mesh;
particles->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_PARTICLES);
@@ -334,7 +334,7 @@ void ParticlesStorage::particles_set_draw_pass_mesh(RID p_particles, int p_pass,
void ParticlesStorage::particles_restart(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->restart_request = true;
}
@@ -351,7 +351,7 @@ void ParticlesStorage::particles_emit(RID p_particles, const Transform3D &p_tran
void ParticlesStorage::particles_request_process(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
if (!particles->dirty) {
particles->dirty = true;
@@ -366,7 +366,7 @@ AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) {
}
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, AABB());
+ ERR_FAIL_NULL_V(particles, AABB());
int total_amount = particles->amount;
@@ -419,28 +419,28 @@ AABB ParticlesStorage::particles_get_current_aabb(RID p_particles) {
AABB ParticlesStorage::particles_get_aabb(RID p_particles) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, AABB());
+ ERR_FAIL_NULL_V(particles, AABB());
return particles->custom_aabb;
}
void ParticlesStorage::particles_set_emission_transform(RID p_particles, const Transform3D &p_transform) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->emission_transform = p_transform;
}
int ParticlesStorage::particles_get_draw_passes(RID p_particles) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, 0);
+ ERR_FAIL_NULL_V(particles, 0);
return particles->draw_passes.size();
}
RID ParticlesStorage::particles_get_draw_pass_mesh(RID p_particles, int p_pass) const {
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, RID());
+ ERR_FAIL_NULL_V(particles, RID());
ERR_FAIL_INDEX_V(p_pass, particles->draw_passes.size(), RID());
return particles->draw_passes[p_pass];
@@ -448,19 +448,19 @@ RID ParticlesStorage::particles_get_draw_pass_mesh(RID p_particles, int p_pass)
void ParticlesStorage::particles_add_collision(RID p_particles, RID p_particles_collision_instance) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->collisions.insert(p_particles_collision_instance);
}
void ParticlesStorage::particles_remove_collision(RID p_particles, RID p_particles_collision_instance) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->collisions.erase(p_particles_collision_instance);
}
void ParticlesStorage::particles_set_canvas_sdf_collision(RID p_particles, bool p_enable, const Transform2D &p_xform, const Rect2 &p_to_screen, GLuint p_texture) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
particles->has_sdf_collision = p_enable;
particles->sdf_collision_transform = p_xform;
particles->sdf_collision_to_screen = p_to_screen;
@@ -694,7 +694,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
m = static_cast<ParticleProcessMaterialData *>(material_storage->material_get_data(particles_shader.default_material, RS::SHADER_PARTICLES));
}
- ERR_FAIL_COND(!m);
+ ERR_FAIL_NULL(m);
ParticlesShaderGLES3::ShaderVariant variant = ParticlesShaderGLES3::MODE_DEFAULT;
@@ -745,7 +745,7 @@ void ParticlesStorage::_particles_process(Particles *p_particles, double p_delta
void ParticlesStorage::particles_set_view_axis(RID p_particles, const Vector3 &p_axis, const Vector3 &p_up_axis) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND(!particles);
+ ERR_FAIL_NULL(particles);
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) {
return;
@@ -1163,7 +1163,7 @@ Dependency *ParticlesStorage::particles_get_dependency(RID p_particles) const {
bool ParticlesStorage::particles_is_inactive(RID p_particles) const {
ERR_FAIL_COND_V_MSG(RSG::threaded, false, "This function should never be used with threaded rendering, as it stalls the renderer.");
const Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, false);
+ ERR_FAIL_NULL_V(particles, false);
return !particles->emitting && particles->inactive;
}
@@ -1191,7 +1191,7 @@ void ParticlesStorage::particles_collision_free(RID p_rid) {
GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_particles_collision) const {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, 0);
+ ERR_FAIL_NULL_V(particles_collision, 0);
ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, 0);
if (particles_collision->heightfield_texture == 0) {
@@ -1240,7 +1240,7 @@ GLuint ParticlesStorage::particles_collision_get_heightfield_framebuffer(RID p_p
void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_collision, RS::ParticlesCollisionType p_type) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
if (p_type == particles_collision->type) {
return;
@@ -1259,13 +1259,13 @@ void ParticlesStorage::particles_collision_set_collision_type(RID p_particles_co
void ParticlesStorage::particles_collision_set_cull_mask(RID p_particles_collision, uint32_t p_cull_mask) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->cull_mask = p_cull_mask;
}
void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_collision, real_t p_radius) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->radius = p_radius;
particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
@@ -1273,7 +1273,7 @@ void ParticlesStorage::particles_collision_set_sphere_radius(RID p_particles_col
void ParticlesStorage::particles_collision_set_box_extents(RID p_particles_collision, const Vector3 &p_extents) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->extents = p_extents;
particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
@@ -1281,21 +1281,21 @@ void ParticlesStorage::particles_collision_set_box_extents(RID p_particles_colli
void ParticlesStorage::particles_collision_set_attractor_strength(RID p_particles_collision, real_t p_strength) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->attractor_strength = p_strength;
}
void ParticlesStorage::particles_collision_set_attractor_directionality(RID p_particles_collision, real_t p_directionality) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->attractor_directionality = p_directionality;
}
void ParticlesStorage::particles_collision_set_attractor_attenuation(RID p_particles_collision, real_t p_curve) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->attractor_attenuation = p_curve;
}
@@ -1306,13 +1306,13 @@ void ParticlesStorage::particles_collision_set_field_texture(RID p_particles_col
void ParticlesStorage::particles_collision_height_field_update(RID p_particles_collision) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
particles_collision->dependency.changed_notify(Dependency::DEPENDENCY_CHANGED_AABB);
}
void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_particles_collision, RS::ParticlesCollisionHeightfieldResolution p_resolution) {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND(!particles_collision);
+ ERR_FAIL_NULL(particles_collision);
ERR_FAIL_INDEX(p_resolution, RS::PARTICLES_COLLISION_HEIGHTFIELD_RESOLUTION_MAX);
if (particles_collision->heightfield_resolution == p_resolution) {
@@ -1331,7 +1331,7 @@ void ParticlesStorage::particles_collision_set_height_field_resolution(RID p_par
AABB ParticlesStorage::particles_collision_get_aabb(RID p_particles_collision) const {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, AABB());
+ ERR_FAIL_NULL_V(particles_collision, AABB());
switch (particles_collision->type) {
case RS::PARTICLES_COLLISION_TYPE_SPHERE_ATTRACT:
@@ -1352,13 +1352,13 @@ AABB ParticlesStorage::particles_collision_get_aabb(RID p_particles_collision) c
Vector3 ParticlesStorage::particles_collision_get_extents(RID p_particles_collision) const {
const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, Vector3());
+ ERR_FAIL_NULL_V(particles_collision, Vector3());
return particles_collision->extents;
}
bool ParticlesStorage::particles_collision_is_heightfield(RID p_particles_collision) const {
const ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, false);
+ ERR_FAIL_NULL_V(particles_collision, false);
return particles_collision->type == RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE;
}
@@ -1383,13 +1383,13 @@ void ParticlesStorage::particles_collision_instance_free(RID p_rid) {
void ParticlesStorage::particles_collision_instance_set_transform(RID p_collision_instance, const Transform3D &p_transform) {
ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
- ERR_FAIL_COND(!pci);
+ ERR_FAIL_NULL(pci);
pci->transform = p_transform;
}
void ParticlesStorage::particles_collision_instance_set_active(RID p_collision_instance, bool p_active) {
ParticlesCollisionInstance *pci = particles_collision_instance_owner.get_or_null(p_collision_instance);
- ERR_FAIL_COND(!pci);
+ ERR_FAIL_NULL(pci);
pci->active = p_active;
}
diff --git a/drivers/gles3/storage/particles_storage.h b/drivers/gles3/storage/particles_storage.h
index 0e84c2ca8f..5146dc5329 100644
--- a/drivers/gles3/storage/particles_storage.h
+++ b/drivers/gles3/storage/particles_storage.h
@@ -40,12 +40,7 @@
#include "servers/rendering/storage/particles_storage.h"
#include "servers/rendering/storage/utilities.h"
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
+#include "platform_gl.h"
namespace GLES3 {
@@ -367,13 +362,13 @@ public:
_FORCE_INLINE_ RS::ParticlesMode particles_get_mode(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, RS::PARTICLES_MODE_2D);
+ ERR_FAIL_NULL_V(particles, RS::PARTICLES_MODE_2D);
return particles->mode;
}
_FORCE_INLINE_ uint32_t particles_get_amount(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, 0);
+ ERR_FAIL_NULL_V(particles, 0);
return particles->amount;
}
@@ -389,14 +384,14 @@ public:
_FORCE_INLINE_ bool particles_has_collision(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, 0);
+ ERR_FAIL_NULL_V(particles, 0);
return particles->has_collision_cache;
}
_FORCE_INLINE_ uint32_t particles_is_using_local_coords(RID p_particles) {
Particles *particles = particles_owner.get_or_null(p_particles);
- ERR_FAIL_COND_V(!particles, false);
+ ERR_FAIL_NULL_V(particles, false);
return particles->use_local_coords;
}
@@ -427,7 +422,7 @@ public:
_FORCE_INLINE_ Size2i particles_collision_get_heightfield_size(RID p_particles_collision) const {
ParticlesCollision *particles_collision = particles_collision_owner.get_or_null(p_particles_collision);
- ERR_FAIL_COND_V(!particles_collision, Size2i());
+ ERR_FAIL_NULL_V(particles_collision, Size2i());
ERR_FAIL_COND_V(particles_collision->type != RS::PARTICLES_COLLISION_TYPE_HEIGHTFIELD_COLLIDE, Size2i());
return particles_collision->heightfield_fb_size;
diff --git a/drivers/gles3/storage/render_scene_buffers_gles3.h b/drivers/gles3/storage/render_scene_buffers_gles3.h
index aa98797ed1..543e1aeb15 100644
--- a/drivers/gles3/storage/render_scene_buffers_gles3.h
+++ b/drivers/gles3/storage/render_scene_buffers_gles3.h
@@ -35,12 +35,7 @@
#include "servers/rendering/storage/render_scene_buffers.h"
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
+#include "platform_gl.h"
class RenderSceneBuffersGLES3 : public RenderSceneBuffers {
GDCLASS(RenderSceneBuffersGLES3, RenderSceneBuffers);
diff --git a/drivers/gles3/storage/texture_storage.cpp b/drivers/gles3/storage/texture_storage.cpp
index a3f230f9e2..6ccd4246e6 100644
--- a/drivers/gles3/storage/texture_storage.cpp
+++ b/drivers/gles3/storage/texture_storage.cpp
@@ -31,8 +31,10 @@
#ifdef GLES3_ENABLED
#include "texture_storage.h"
+
+#include "../effects/copy_effects.h"
+#include "../rasterizer_gles3.h"
#include "config.h"
-#include "drivers/gles3/effects/copy_effects.h"
#include "utilities.h"
#ifdef ANDROID_ENABLED
@@ -216,9 +218,11 @@ TextureStorage::TextureStorage() {
sdf_shader.shader_version = sdf_shader.shader.version_create();
}
-#ifdef GLES_OVER_GL
- glEnable(GL_PROGRAM_POINT_SIZE);
-#endif
+#ifdef GL_API_ENABLED
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ glEnable(GL_PROGRAM_POINT_SIZE);
+ }
+#endif // GL_API_ENABLED
}
TextureStorage::~TextureStorage() {
@@ -309,26 +313,26 @@ Ref<Image> TextureStorage::_get_gl_image_and_format(const Ref<Image> &p_image, I
switch (p_format) {
case Image::FORMAT_L8: {
-#ifdef GLES_OVER_GL
- r_gl_internal_format = GL_R8;
- r_gl_format = GL_RED;
- r_gl_type = GL_UNSIGNED_BYTE;
-#else
- r_gl_internal_format = GL_LUMINANCE;
- r_gl_format = GL_LUMINANCE;
- r_gl_type = GL_UNSIGNED_BYTE;
-#endif
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ r_gl_internal_format = GL_R8;
+ r_gl_format = GL_RED;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ } else {
+ r_gl_internal_format = GL_LUMINANCE;
+ r_gl_format = GL_LUMINANCE;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ }
} break;
case Image::FORMAT_LA8: {
-#ifdef GLES_OVER_GL
- r_gl_internal_format = GL_RG8;
- r_gl_format = GL_RG;
- r_gl_type = GL_UNSIGNED_BYTE;
-#else
- r_gl_internal_format = GL_LUMINANCE_ALPHA;
- r_gl_format = GL_LUMINANCE_ALPHA;
- r_gl_type = GL_UNSIGNED_BYTE;
-#endif
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ r_gl_internal_format = GL_RG8;
+ r_gl_format = GL_RG;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ } else {
+ r_gl_internal_format = GL_LUMINANCE_ALPHA;
+ r_gl_format = GL_LUMINANCE_ALPHA;
+ r_gl_type = GL_UNSIGNED_BYTE;
+ }
} break;
case Image::FORMAT_R8: {
r_gl_internal_format = GL_R8;
@@ -702,7 +706,7 @@ RID TextureStorage::texture_allocate() {
void TextureStorage::texture_free(RID p_texture) {
Texture *t = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!t);
+ ERR_FAIL_NULL(t);
ERR_FAIL_COND(t->is_render_target);
if (t->canvas_texture) {
@@ -816,7 +820,7 @@ void TextureStorage::texture_3d_initialize(RID p_texture, Image::Format, int p_w
// Note: p_base is the root and p_texture is the proxy.
void TextureStorage::texture_proxy_initialize(RID p_texture, RID p_base) {
Texture *texture = texture_owner.get_or_null(p_base);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
Texture proxy_tex;
proxy_tex.copy_from(*texture);
proxy_tex.proxy_to = p_base;
@@ -860,7 +864,7 @@ void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image,
texture_set_data(p_texture, p_image, p_layer);
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
GLES3::Utilities::get_singleton()->texture_resize_data(tex->tex_id, tex->total_data_size);
#ifdef TOOLS_ENABLED
@@ -870,15 +874,15 @@ void TextureStorage::texture_2d_update(RID p_texture, const Ref<Image> &p_image,
void TextureStorage::texture_proxy_update(RID p_texture, RID p_proxy_to) {
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex);
+ ERR_FAIL_NULL(tex);
ERR_FAIL_COND(!tex->is_proxy);
Texture *proxy_to = texture_owner.get_or_null(p_proxy_to);
- ERR_FAIL_COND(!proxy_to);
+ ERR_FAIL_NULL(proxy_to);
ERR_FAIL_COND(proxy_to->is_proxy);
if (tex->proxy_to.is_valid()) {
Texture *prev_tex = texture_owner.get_or_null(tex->proxy_to);
- ERR_FAIL_COND(!prev_tex);
+ ERR_FAIL_NULL(prev_tex);
prev_tex->proxies.erase(p_texture);
}
@@ -938,7 +942,7 @@ void TextureStorage::texture_3d_placeholder_initialize(RID p_texture) {
Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, Ref<Image>());
+ ERR_FAIL_NULL_V(texture, Ref<Image>());
#ifdef TOOLS_ENABLED
if (texture->image_cache_2d.is_valid() && !texture->is_render_target) {
@@ -946,105 +950,109 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
}
#endif
-#ifdef GLES_OVER_GL
- // OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
- // It also allows for reading compressed textures, mipmaps, and more formats.
- Vector<uint8_t> data;
+ Ref<Image> image;
+#ifdef GL_API_ENABLED
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ // OpenGL 3.3 supports glGetTexImage which is faster and simpler than glReadPixels.
+ // It also allows for reading compressed textures, mipmaps, and more formats.
+ Vector<uint8_t> data;
- int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->real_format, texture->mipmaps > 1);
+ int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, texture->real_format, texture->mipmaps > 1);
- data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
- uint8_t *w = data.ptrw();
+ data.resize(data_size * 2); // Add some memory at the end, just in case for buggy drivers.
+ uint8_t *w = data.ptrw();
- glActiveTexture(GL_TEXTURE0);
+ glActiveTexture(GL_TEXTURE0);
- glBindTexture(texture->target, texture->tex_id);
+ glBindTexture(texture->target, texture->tex_id);
- glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
+ glBindBuffer(GL_PIXEL_PACK_BUFFER, 0);
- for (int i = 0; i < texture->mipmaps; i++) {
- int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, texture->real_format, i);
+ for (int i = 0; i < texture->mipmaps; i++) {
+ int ofs = Image::get_image_mipmap_offset(texture->alloc_width, texture->alloc_height, texture->real_format, i);
- if (texture->compressed) {
- glPixelStorei(GL_PACK_ALIGNMENT, 4);
- glGetCompressedTexImage(texture->target, i, &w[ofs]);
+ if (texture->compressed) {
+ glPixelStorei(GL_PACK_ALIGNMENT, 4);
+ glGetCompressedTexImage(texture->target, i, &w[ofs]);
- } else {
- glPixelStorei(GL_PACK_ALIGNMENT, 1);
+ } else {
+ glPixelStorei(GL_PACK_ALIGNMENT, 1);
- glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &w[ofs]);
+ glGetTexImage(texture->target, i, texture->gl_format_cache, texture->gl_type_cache, &w[ofs]);
+ }
}
- }
- data.resize(data_size);
+ data.resize(data_size);
- ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
- Ref<Image> image = Image::create_from_data(texture->width, texture->height, texture->mipmaps > 1, texture->real_format, data);
- ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
- if (texture->format != texture->real_format) {
- image->convert(texture->format);
+ ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
+ image = Image::create_from_data(texture->width, texture->height, texture->mipmaps > 1, texture->real_format, data);
+ ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
+ if (texture->format != texture->real_format) {
+ image->convert(texture->format);
+ }
}
-#else
-
- Vector<uint8_t> data;
+#endif // GL_API_ENABLED
+#ifdef GLES_API_ENABLED
+ if (!RasterizerGLES3::is_gles_over_gl()) {
+ Vector<uint8_t> data;
- // On web and mobile we always read an RGBA8 image with no mipmaps.
- int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false);
+ // On web and mobile we always read an RGBA8 image with no mipmaps.
+ int data_size = Image::get_image_data_size(texture->alloc_width, texture->alloc_height, Image::FORMAT_RGBA8, false);
- data.resize(data_size * 2); //add some memory at the end, just in case for buggy drivers
- uint8_t *w = data.ptrw();
+ data.resize(data_size * 2); // Add some memory at the end, just in case for buggy drivers.
+ uint8_t *w = data.ptrw();
- GLuint temp_framebuffer;
- glGenFramebuffers(1, &temp_framebuffer);
+ GLuint temp_framebuffer;
+ glGenFramebuffers(1, &temp_framebuffer);
- GLuint temp_color_texture;
- glGenTextures(1, &temp_color_texture);
+ GLuint temp_color_texture;
+ glGenTextures(1, &temp_color_texture);
- glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, temp_framebuffer);
- glBindTexture(GL_TEXTURE_2D, temp_color_texture);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
-
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0);
+ glBindTexture(GL_TEXTURE_2D, temp_color_texture);
+ glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, texture->alloc_width, texture->alloc_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, NULL);
- glDepthMask(GL_FALSE);
- glDisable(GL_DEPTH_TEST);
- glDisable(GL_CULL_FACE);
- glDisable(GL_BLEND);
- glDepthFunc(GL_LEQUAL);
- glColorMask(1, 1, 1, 1);
- glActiveTexture(GL_TEXTURE0);
- glBindTexture(GL_TEXTURE_2D, texture->tex_id);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
+ glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
+ glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, temp_color_texture, 0);
+
+ glDepthMask(GL_FALSE);
+ glDisable(GL_DEPTH_TEST);
+ glDisable(GL_CULL_FACE);
+ glDisable(GL_BLEND);
+ glDepthFunc(GL_LEQUAL);
+ glColorMask(1, 1, 1, 1);
+ glActiveTexture(GL_TEXTURE0);
+ glBindTexture(GL_TEXTURE_2D, texture->tex_id);
- glViewport(0, 0, texture->alloc_width, texture->alloc_height);
- glClearColor(0.0, 0.0, 0.0, 0.0);
- glClear(GL_COLOR_BUFFER_BIT);
+ glViewport(0, 0, texture->alloc_width, texture->alloc_height);
+ glClearColor(0.0, 0.0, 0.0, 0.0);
+ glClear(GL_COLOR_BUFFER_BIT);
- CopyEffects::get_singleton()->copy_to_rect(Rect2i(0, 0, 1.0, 1.0));
+ CopyEffects::get_singleton()->copy_to_rect(Rect2i(0, 0, 1.0, 1.0));
- glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]);
+ glReadPixels(0, 0, texture->alloc_width, texture->alloc_height, GL_RGBA, GL_UNSIGNED_BYTE, &w[0]);
- glBindFramebuffer(GL_FRAMEBUFFER, 0);
- glDeleteTextures(1, &temp_color_texture);
- glDeleteFramebuffers(1, &temp_framebuffer);
+ glBindFramebuffer(GL_FRAMEBUFFER, 0);
+ glDeleteTextures(1, &temp_color_texture);
+ glDeleteFramebuffers(1, &temp_framebuffer);
- data.resize(data_size);
+ data.resize(data_size);
- ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
- Ref<Image> image = Image::create_from_data(texture->width, texture->height, false, Image::FORMAT_RGBA8, data);
- ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
+ ERR_FAIL_COND_V(data.size() == 0, Ref<Image>());
+ image = Image::create_from_data(texture->width, texture->height, false, Image::FORMAT_RGBA8, data);
+ ERR_FAIL_COND_V(image->is_empty(), Ref<Image>());
- if (texture->format != Image::FORMAT_RGBA8) {
- image->convert(texture->format);
- }
+ if (texture->format != Image::FORMAT_RGBA8) {
+ image->convert(texture->format);
+ }
- if (texture->mipmaps > 1) {
- image->generate_mipmaps();
+ if (texture->mipmaps > 1) {
+ image->generate_mipmaps();
+ }
}
-
-#endif
+#endif // GLES_API_ENABLED
#ifdef TOOLS_ENABLED
if (Engine::get_singleton()->is_editor_hint() && !texture->is_render_target) {
@@ -1057,10 +1065,10 @@ Ref<Image> TextureStorage::texture_2d_get(RID p_texture) const {
void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
Texture *tex_to = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!tex_to);
+ ERR_FAIL_NULL(tex_to);
ERR_FAIL_COND(tex_to->is_proxy); //can't replace proxy
Texture *tex_from = texture_owner.get_or_null(p_by_texture);
- ERR_FAIL_COND(!tex_from);
+ ERR_FAIL_NULL(tex_from);
ERR_FAIL_COND(tex_from->is_proxy); //can't replace proxy
if (tex_to == tex_from) {
@@ -1103,7 +1111,7 @@ void TextureStorage::texture_replace(RID p_texture, RID p_by_texture) {
void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p_height) {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
ERR_FAIL_COND(texture->is_render_target);
ERR_FAIL_COND(p_width <= 0 || p_width > 16384);
@@ -1115,21 +1123,21 @@ void TextureStorage::texture_set_size_override(RID p_texture, int p_width, int p
void TextureStorage::texture_set_path(RID p_texture, const String &p_path) {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
texture->path = p_path;
}
String TextureStorage::texture_get_path(RID p_texture) const {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, "");
+ ERR_FAIL_NULL_V(texture, "");
return texture->path;
}
void TextureStorage::texture_set_detect_3d_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
texture->detect_3d_callback = p_callback;
texture->detect_3d_callback_ud = p_userdata;
@@ -1140,7 +1148,7 @@ void TextureStorage::texture_set_detect_srgb_callback(RID p_texture, RS::Texture
void TextureStorage::texture_set_detect_normal_callback(RID p_texture, RS::TextureDetectCallback p_callback, void *p_userdata) {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
texture->detect_normal_callback = p_callback;
texture->detect_normal_callback_ud = p_userdata;
@@ -1148,7 +1156,7 @@ void TextureStorage::texture_set_detect_normal_callback(RID p_texture, RS::Textu
void TextureStorage::texture_set_detect_roughness_callback(RID p_texture, RS::TextureDetectRoughnessCallback p_callback, void *p_userdata) {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
texture->detect_roughness_callback = p_callback;
texture->detect_roughness_callback_ud = p_userdata;
@@ -1176,14 +1184,14 @@ void TextureStorage::texture_debug_usage(List<RS::TextureInfo> *r_info) {
void TextureStorage::texture_set_force_redraw_if_visible(RID p_texture, bool p_enable) {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
texture->redraw_if_visible = p_enable;
}
Size2 TextureStorage::texture_size_with_proxy(RID p_texture) {
const Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, Size2());
+ ERR_FAIL_NULL_V(texture, Size2());
if (texture->is_proxy) {
const Texture *proxy = texture_owner.get_or_null(texture->proxy_to);
return Size2(proxy->width, proxy->height);
@@ -1201,7 +1209,7 @@ RID TextureStorage::texture_get_rd_texture(RID p_texture, bool p_srgb) const {
uint64_t TextureStorage::texture_get_native_handle(RID p_texture, bool p_srgb) const {
const Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, 0);
+ ERR_FAIL_NULL_V(texture, 0);
return texture->tex_id;
}
@@ -1213,7 +1221,7 @@ void TextureStorage::texture_set_data(RID p_texture, const Ref<Image> &p_image,
void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image, int p_layer, bool initialize) {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
if (texture->target == GL_TEXTURE_3D) {
// Target is set to a 3D texture or array texture, exit early to avoid spamming errors
return;
@@ -1254,21 +1262,32 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image,
#ifndef WEB_ENABLED
switch (texture->format) {
-#ifdef GLES_OVER_GL
case Image::FORMAT_L8: {
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ONE);
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ONE);
+ } else {
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
+ }
} break;
case Image::FORMAT_LA8: {
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
- glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_GREEN);
+ } else {
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_R, GL_RED);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_G, GL_GREEN);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_B, GL_BLUE);
+ glTexParameteri(texture->target, GL_TEXTURE_SWIZZLE_A, GL_ALPHA);
+ }
} break;
-#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);
@@ -1346,7 +1365,7 @@ void TextureStorage::_texture_set_data(RID p_texture, const Ref<Image> &p_image,
Image::Format TextureStorage::texture_get_format(RID p_texture) const {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, Image::FORMAT_L8);
+ ERR_FAIL_NULL_V(texture, Image::FORMAT_L8);
return texture->format;
}
@@ -1354,7 +1373,7 @@ Image::Format TextureStorage::texture_get_format(RID p_texture) const {
uint32_t TextureStorage::texture_get_texid(RID p_texture) const {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, 0);
+ ERR_FAIL_NULL_V(texture, 0);
return texture->tex_id;
}
@@ -1362,7 +1381,7 @@ uint32_t TextureStorage::texture_get_texid(RID p_texture) const {
uint32_t TextureStorage::texture_get_width(RID p_texture) const {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, 0);
+ ERR_FAIL_NULL_V(texture, 0);
return texture->width;
}
@@ -1370,7 +1389,7 @@ uint32_t TextureStorage::texture_get_width(RID p_texture) const {
uint32_t TextureStorage::texture_get_height(RID p_texture) const {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, 0);
+ ERR_FAIL_NULL_V(texture, 0);
return texture->height;
}
@@ -1378,7 +1397,7 @@ uint32_t TextureStorage::texture_get_height(RID p_texture) const {
uint32_t TextureStorage::texture_get_depth(RID p_texture) const {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, 0);
+ ERR_FAIL_NULL_V(texture, 0);
return texture->depth;
}
@@ -1386,7 +1405,7 @@ uint32_t TextureStorage::texture_get_depth(RID p_texture) const {
void TextureStorage::texture_bind(RID p_texture, uint32_t p_texture_no) {
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
glActiveTexture(GL_TEXTURE0 + p_texture_no);
glBindTexture(texture->target, texture->tex_id);
@@ -1408,7 +1427,7 @@ void TextureStorage::texture_add_to_texture_atlas(RID p_texture) {
void TextureStorage::texture_remove_from_texture_atlas(RID p_texture) {
TextureAtlas::Texture *t = texture_atlas.textures.getptr(p_texture);
- ERR_FAIL_COND(!t);
+ ERR_FAIL_NULL(t);
t->users--;
if (t->users == 0) {
texture_atlas.textures.erase(p_texture);
@@ -1684,13 +1703,13 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
// color
if (rt->overridden.color.is_valid()) {
texture = get_texture(rt->overridden.color);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
rt->color = texture->tex_id;
rt->size = Size2i(texture->width, texture->height);
} else {
texture = get_texture(rt->texture);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
glGenTextures(1, &rt->color);
glBindTexture(texture_target, rt->color);
@@ -1719,7 +1738,7 @@ void TextureStorage::_update_render_target(RenderTarget *rt) {
// depth
if (rt->overridden.depth.is_valid()) {
texture = get_texture(rt->overridden.depth);
- ERR_FAIL_COND(!texture);
+ ERR_FAIL_NULL(texture);
rt->depth = texture->tex_id;
} else {
@@ -2021,21 +2040,21 @@ void TextureStorage::render_target_free(RID p_rid) {
void TextureStorage::render_target_set_position(RID p_render_target, int p_x, int p_y) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->position = Point2i(p_x, p_y);
}
Point2i TextureStorage::render_target_get_position(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Point2i());
+ ERR_FAIL_NULL_V(rt, Point2i());
return rt->position;
};
void TextureStorage::render_target_set_size(RID p_render_target, int p_width, int p_height, uint32_t p_view_count) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (p_width == rt->size.x && p_height == rt->size.y && p_view_count == rt->view_count) {
return;
@@ -2055,14 +2074,14 @@ void TextureStorage::render_target_set_size(RID p_render_target, int p_width, in
// TODO: convert to Size2i internally
Size2i TextureStorage::render_target_get_size(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Size2i());
+ ERR_FAIL_NULL_V(rt, Size2i());
return rt->size;
}
void TextureStorage::render_target_set_override(RID p_render_target, RID p_color_texture, RID p_depth_texture, RID p_velocity_texture) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
ERR_FAIL_COND(rt->direct_to_screen);
rt->overridden.velocity = p_velocity_texture;
@@ -2118,28 +2137,28 @@ void TextureStorage::render_target_set_override(RID p_render_target, RID p_color
RID TextureStorage::render_target_get_override_color(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->overridden.color;
}
RID TextureStorage::render_target_get_override_depth(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->overridden.depth;
}
RID TextureStorage::render_target_get_override_velocity(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
return rt->overridden.velocity;
}
RID TextureStorage::render_target_get_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RID());
+ ERR_FAIL_NULL_V(rt, RID());
if (rt->overridden.color.is_valid()) {
return rt->overridden.color;
@@ -2150,7 +2169,7 @@ RID TextureStorage::render_target_get_texture(RID p_render_target) {
void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_transparent) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->is_transparent = p_transparent;
@@ -2162,14 +2181,14 @@ void TextureStorage::render_target_set_transparent(RID p_render_target, bool p_t
bool TextureStorage::render_target_get_transparent(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->is_transparent;
}
void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, bool p_direct_to_screen) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (p_direct_to_screen == rt->direct_to_screen) {
return;
@@ -2188,28 +2207,28 @@ void TextureStorage::render_target_set_direct_to_screen(RID p_render_target, boo
bool TextureStorage::render_target_get_direct_to_screen(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->direct_to_screen;
}
bool TextureStorage::render_target_was_used(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->used_in_frame;
}
void TextureStorage::render_target_clear_used(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->used_in_frame = false;
}
void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSAA p_msaa) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (p_msaa == rt->msaa) {
return;
}
@@ -2223,38 +2242,38 @@ void TextureStorage::render_target_set_msaa(RID p_render_target, RS::ViewportMSA
RS::ViewportMSAA TextureStorage::render_target_get_msaa(RID p_render_target) const {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, RS::VIEWPORT_MSAA_DISABLED);
+ ERR_FAIL_NULL_V(rt, RS::VIEWPORT_MSAA_DISABLED);
return rt->msaa;
}
void TextureStorage::render_target_request_clear(RID p_render_target, const Color &p_clear_color) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->clear_requested = true;
rt->clear_color = p_clear_color;
}
bool TextureStorage::render_target_is_clear_requested(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->clear_requested;
}
Color TextureStorage::render_target_get_clear_request_color(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Color());
+ ERR_FAIL_NULL_V(rt, Color());
return rt->clear_color;
}
void TextureStorage::render_target_disable_clear_request(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->clear_requested = false;
}
void TextureStorage::render_target_do_clear_request(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (!rt->clear_requested) {
return;
}
@@ -2267,7 +2286,7 @@ void TextureStorage::render_target_do_clear_request(RID p_render_target) {
void TextureStorage::render_target_set_sdf_size_and_scale(RID p_render_target, RS::ViewportSDFOversize p_size, RS::ViewportSDFScale p_scale) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (rt->sdf_oversize == p_size && rt->sdf_scale == p_scale) {
return;
}
@@ -2309,28 +2328,28 @@ Rect2i TextureStorage::_render_target_get_sdf_rect(const RenderTarget *rt) const
Rect2i TextureStorage::render_target_get_sdf_rect(RID p_render_target) const {
const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, Rect2i());
+ ERR_FAIL_NULL_V(rt, Rect2i());
return _render_target_get_sdf_rect(rt);
}
void TextureStorage::render_target_mark_sdf_enabled(RID p_render_target, bool p_enabled) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
rt->sdf_enabled = p_enabled;
}
bool TextureStorage::render_target_is_sdf_enabled(RID p_render_target) const {
const RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, false);
+ ERR_FAIL_NULL_V(rt, false);
return rt->sdf_enabled;
}
GLuint TextureStorage::render_target_get_sdf_texture(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, 0);
+ ERR_FAIL_NULL_V(rt, 0);
if (rt->sdf_texture_read == 0) {
Texture *texture = texture_owner.get_or_null(default_gl_textures[DEFAULT_GL_TEXTURE_BLACK]);
return texture->tex_id;
@@ -2431,7 +2450,7 @@ void TextureStorage::_render_target_clear_sdf(RenderTarget *rt) {
GLuint TextureStorage::render_target_get_sdf_framebuffer(RID p_render_target) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND_V(!rt, 0);
+ ERR_FAIL_NULL_V(rt, 0);
if (rt->sdf_texture_write_fb == 0) {
_render_target_allocate_sdf(rt);
@@ -2443,7 +2462,7 @@ void TextureStorage::render_target_sdf_process(RID p_render_target) {
CopyEffects *copy_effects = CopyEffects::get_singleton();
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
ERR_FAIL_COND(rt->sdf_texture_write_fb == 0);
Rect2i r = _render_target_get_sdf_rect(rt);
@@ -2553,7 +2572,7 @@ void TextureStorage::render_target_sdf_process(RID p_render_target) {
void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, const Rect2i &p_region, bool p_gen_mipmaps) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
ERR_FAIL_COND(rt->direct_to_screen);
if (rt->backbuffer_fbo == 0) {
@@ -2587,7 +2606,7 @@ void TextureStorage::render_target_copy_to_back_buffer(RID p_render_target, cons
void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const Rect2i &p_region, const Color &p_color) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
ERR_FAIL_COND(rt->direct_to_screen);
if (rt->backbuffer_fbo == 0) {
@@ -2612,7 +2631,7 @@ void TextureStorage::render_target_clear_back_buffer(RID p_render_target, const
void TextureStorage::render_target_gen_back_buffer_mipmaps(RID p_render_target, const Rect2i &p_region) {
RenderTarget *rt = render_target_owner.get_or_null(p_render_target);
- ERR_FAIL_COND(!rt);
+ ERR_FAIL_NULL(rt);
if (rt->backbuffer_fbo == 0) {
_create_render_target_backbuffer(rt);
diff --git a/drivers/gles3/storage/texture_storage.h b/drivers/gles3/storage/texture_storage.h
index c25dbef288..87a07ebb36 100644
--- a/drivers/gles3/storage/texture_storage.h
+++ b/drivers/gles3/storage/texture_storage.h
@@ -33,6 +33,8 @@
#ifdef GLES3_ENABLED
+#include "platform_gl.h"
+
#include "config.h"
#include "core/os/os.h"
#include "core/templates/rid_owner.h"
@@ -41,14 +43,6 @@
#include "drivers/gles3/shaders/canvas_sdf.glsl.gen.h"
-// This must come first to avoid windows.h mess
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
-
namespace GLES3 {
#define _GL_TEXTURE_MAX_ANISOTROPY_EXT 0x84FE
@@ -118,10 +112,6 @@ namespace GLES3 {
#define _EXT_TEXTURE_CUBE_MAP_SEAMLESS 0x884F
-#ifndef GLES_OVER_GL
-#define glClearDepth glClearDepthf
-#endif //!GLES_OVER_GL
-
enum DefaultGLTexture {
DEFAULT_GL_TEXTURE_WHITE,
DEFAULT_GL_TEXTURE_BLACK,
@@ -679,7 +669,7 @@ public:
};
inline String TextureStorage::get_framebuffer_error(GLenum p_status) {
-#if defined(DEBUG_ENABLED) && defined(GLES_OVER_GL)
+#if defined(DEBUG_ENABLED) && defined(GL_API_ENABLED)
if (p_status == GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT) {
return "GL_FRAMEBUFFER_INCOMPLETE_ATTACHMENT";
} else if (p_status == GL_FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT) {
diff --git a/drivers/gles3/storage/utilities.cpp b/drivers/gles3/storage/utilities.cpp
index 3e6e72edad..07df445018 100644
--- a/drivers/gles3/storage/utilities.cpp
+++ b/drivers/gles3/storage/utilities.cpp
@@ -31,6 +31,8 @@
#ifdef GLES3_ENABLED
#include "utilities.h"
+
+#include "../rasterizer_gles3.h"
#include "config.h"
#include "light_storage.h"
#include "material_storage.h"
@@ -253,9 +255,11 @@ void Utilities::capture_timestamps_begin() {
void Utilities::capture_timestamp(const String &p_name) {
ERR_FAIL_COND(frames[frame].timestamp_count >= max_timestamp_query_elements);
-#ifdef GLES_OVER_GL
- glQueryCounter(frames[frame].queries[frames[frame].timestamp_count], GL_TIMESTAMP);
-#endif
+#ifdef GL_API_ENABLED
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ glQueryCounter(frames[frame].queries[frames[frame].timestamp_count], GL_TIMESTAMP);
+ }
+#endif // GL_API_ENABLED
frames[frame].timestamp_names[frames[frame].timestamp_count] = p_name;
frames[frame].timestamp_cpu_values[frames[frame].timestamp_count] = OS::get_singleton()->get_ticks_usec();
@@ -265,13 +269,15 @@ void Utilities::capture_timestamp(const String &p_name) {
void Utilities::_capture_timestamps_begin() {
// frame is incremented at the end of the frame so this gives us the queries for frame - 2. By then they should be ready.
if (frames[frame].timestamp_count) {
-#ifdef GLES_OVER_GL
- for (uint32_t i = 0; i < frames[frame].timestamp_count; i++) {
- uint64_t temp = 0;
- glGetQueryObjectui64v(frames[frame].queries[i], GL_QUERY_RESULT, &temp);
- frames[frame].timestamp_result_values[i] = temp;
+#ifdef GL_API_ENABLED
+ if (RasterizerGLES3::is_gles_over_gl()) {
+ for (uint32_t i = 0; i < frames[frame].timestamp_count; i++) {
+ uint64_t temp = 0;
+ glGetQueryObjectui64v(frames[frame].queries[i], GL_QUERY_RESULT, &temp);
+ frames[frame].timestamp_result_values[i] = temp;
+ }
}
-#endif
+#endif // GL_API_ENABLED
SWAP(frames[frame].timestamp_names, frames[frame].timestamp_result_names);
SWAP(frames[frame].timestamp_cpu_values, frames[frame].timestamp_cpu_result_values);
}
diff --git a/drivers/gles3/storage/utilities.h b/drivers/gles3/storage/utilities.h
index 243342014b..76e4d510de 100644
--- a/drivers/gles3/storage/utilities.h
+++ b/drivers/gles3/storage/utilities.h
@@ -35,12 +35,7 @@
#include "servers/rendering/storage/utilities.h"
-#include "platform_config.h"
-#ifndef OPENGL_INCLUDE_H
-#include <GLES3/gl3.h>
-#else
-#include OPENGL_INCLUDE_H
-#endif
+#include "platform_gl.h"
namespace GLES3 {
diff --git a/drivers/pulseaudio/audio_driver_pulseaudio.cpp b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
index 76b1781dd5..20382e7f7c 100644
--- a/drivers/pulseaudio/audio_driver_pulseaudio.cpp
+++ b/drivers/pulseaudio/audio_driver_pulseaudio.cpp
@@ -107,7 +107,7 @@ void AudioDriverPulseAudio::pa_source_info_cb(pa_context *c, const pa_source_inf
}
void AudioDriverPulseAudio::pa_server_info_cb(pa_context *c, const pa_server_info *i, void *userdata) {
- ERR_FAIL_COND_MSG(!i, "PulseAudio server info is null.");
+ ERR_FAIL_NULL_MSG(i, "PulseAudio server info is null.");
AudioDriverPulseAudio *ad = static_cast<AudioDriverPulseAudio *>(userdata);
ad->default_input_device = i->default_source_name;
@@ -308,7 +308,7 @@ Error AudioDriverPulseAudio::init() {
mix_rate = _get_configured_mix_rate();
pa_ml = pa_mainloop_new();
- ERR_FAIL_COND_V(pa_ml == nullptr, ERR_CANT_OPEN);
+ ERR_FAIL_NULL_V(pa_ml, ERR_CANT_OPEN);
String context_name;
if (Engine::get_singleton()->is_editor_hint()) {
@@ -321,7 +321,7 @@ Error AudioDriverPulseAudio::init() {
}
pa_ctx = pa_context_new(pa_mainloop_get_api(pa_ml), context_name.utf8().ptr());
- ERR_FAIL_COND_V(pa_ctx == nullptr, ERR_CANT_OPEN);
+ ERR_FAIL_NULL_V(pa_ctx, ERR_CANT_OPEN);
pa_ready = 0;
pa_context_set_state_callback(pa_ctx, pa_state_cb, (void *)this);
diff --git a/drivers/unix/file_access_unix.cpp b/drivers/unix/file_access_unix.cpp
index 3b15cf60f7..d28e0e70b8 100644
--- a/drivers/unix/file_access_unix.cpp
+++ b/drivers/unix/file_access_unix.cpp
@@ -53,7 +53,7 @@
#endif
void FileAccessUnix::check_errors() const {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
if (feof(f)) {
last_error = ERR_FILE_EOF;
@@ -185,7 +185,7 @@ String FileAccessUnix::get_path_absolute() const {
}
void FileAccessUnix::seek(uint64_t p_position) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
last_error = OK;
if (fseeko(f, p_position, SEEK_SET)) {
@@ -194,7 +194,7 @@ void FileAccessUnix::seek(uint64_t p_position) {
}
void FileAccessUnix::seek_end(int64_t p_position) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
if (fseeko(f, p_position, SEEK_END)) {
check_errors();
@@ -202,7 +202,7 @@ void FileAccessUnix::seek_end(int64_t p_position) {
}
uint64_t FileAccessUnix::get_position() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
+ ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use.");
int64_t pos = ftello(f);
if (pos < 0) {
@@ -213,7 +213,7 @@ uint64_t FileAccessUnix::get_position() const {
}
uint64_t FileAccessUnix::get_length() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
+ ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use.");
int64_t pos = ftello(f);
ERR_FAIL_COND_V(pos < 0, 0);
@@ -230,7 +230,7 @@ bool FileAccessUnix::eof_reached() const {
}
uint8_t FileAccessUnix::get_8() const {
- ERR_FAIL_COND_V_MSG(!f, 0, "File must be opened before use.");
+ ERR_FAIL_NULL_V_MSG(f, 0, "File must be opened before use.");
uint8_t b;
if (fread(&b, 1, 1, f) == 0) {
check_errors();
@@ -241,7 +241,7 @@ uint8_t FileAccessUnix::get_8() const {
uint64_t FileAccessUnix::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V_MSG(!f, -1, "File must be opened before use.");
+ ERR_FAIL_NULL_V_MSG(f, -1, "File must be opened before use.");
uint64_t read = fread(p_dst, 1, p_length, f);
check_errors();
@@ -253,17 +253,17 @@ Error FileAccessUnix::get_error() const {
}
void FileAccessUnix::flush() {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
fflush(f);
}
void FileAccessUnix::store_8(uint8_t p_dest) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
ERR_FAIL_COND(fwrite(&p_dest, 1, 1, f) != 1);
}
void FileAccessUnix::store_buffer(const uint8_t *p_src, uint64_t p_length) {
- ERR_FAIL_COND_MSG(!f, "File must be opened before use.");
+ ERR_FAIL_NULL_MSG(f, "File must be opened before use.");
ERR_FAIL_COND(!p_src && p_length > 0);
ERR_FAIL_COND(fwrite(p_src, 1, p_length, f) != p_length);
}
diff --git a/drivers/unix/os_unix.cpp b/drivers/unix/os_unix.cpp
index 1ffacdf98d..4d9549c5a6 100644
--- a/drivers/unix/os_unix.cpp
+++ b/drivers/unix/os_unix.cpp
@@ -495,7 +495,7 @@ Error OS_Unix::execute(const String &p_path, const List<String> &p_arguments, St
}
FILE *f = popen(command.utf8().get_data(), "r");
- ERR_FAIL_COND_V_MSG(!f, ERR_CANT_OPEN, "Cannot create pipe from command: " + command);
+ ERR_FAIL_NULL_V_MSG(f, ERR_CANT_OPEN, "Cannot create pipe from command: " + command + ".");
char buf[65535];
while (fgets(buf, 65535, f)) {
if (p_pipe_mutex) {
@@ -647,7 +647,7 @@ Error OS_Unix::open_dynamic_library(const String p_path, void *&p_library_handle
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
- ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
+ ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
if (r_resolved_path != nullptr) {
*r_resolved_path = path;
diff --git a/drivers/vulkan/rendering_device_vulkan.cpp b/drivers/vulkan/rendering_device_vulkan.cpp
index 6e6a2a791a..29841a6be1 100644
--- a/drivers/vulkan/rendering_device_vulkan.cpp
+++ b/drivers/vulkan/rendering_device_vulkan.cpp
@@ -2038,12 +2038,12 @@ RID RenderingDeviceVulkan::texture_create_shared(const TextureView &p_view, RID
_THREAD_SAFE_METHOD_
Texture *src_texture = texture_owner.get_or_null(p_with_texture);
- ERR_FAIL_COND_V(!src_texture, RID());
+ ERR_FAIL_NULL_V(src_texture, RID());
if (src_texture->owner.is_valid()) { // Ahh this is a share.
p_with_texture = src_texture->owner;
src_texture = texture_owner.get_or_null(src_texture->owner);
- ERR_FAIL_COND_V(!src_texture, RID()); // This is a bug.
+ ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.
}
// Create view.
@@ -2313,12 +2313,12 @@ RID RenderingDeviceVulkan::texture_create_shared_from_slice(const TextureView &p
_THREAD_SAFE_METHOD_
Texture *src_texture = texture_owner.get_or_null(p_with_texture);
- ERR_FAIL_COND_V(!src_texture, RID());
+ ERR_FAIL_NULL_V(src_texture, RID());
if (src_texture->owner.is_valid()) { // Ahh this is a share.
p_with_texture = src_texture->owner;
src_texture = texture_owner.get_or_null(src_texture->owner);
- ERR_FAIL_COND_V(!src_texture, RID()); // This is a bug.
+ ERR_FAIL_NULL_V(src_texture, RID()); // This is a bug.
}
ERR_FAIL_COND_V_MSG(p_slice_type == TEXTURE_SLICE_CUBEMAP && (src_texture->type != TEXTURE_TYPE_CUBE && src_texture->type != TEXTURE_TYPE_CUBE_ARRAY), RID(),
@@ -2469,12 +2469,12 @@ Error RenderingDeviceVulkan::_texture_update(RID p_texture, uint32_t p_layer, co
"Updating textures is forbidden during creation of a draw or compute list");
Texture *texture = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!texture, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(texture, ERR_INVALID_PARAMETER);
if (texture->owner != RID()) {
p_texture = texture->owner;
texture = texture_owner.get_or_null(texture->owner);
- ERR_FAIL_COND_V(!texture, ERR_BUG); // This is a bug.
+ ERR_FAIL_NULL_V(texture, ERR_BUG); // This is a bug.
}
ERR_FAIL_COND_V_MSG(texture->bound, ERR_CANT_ACQUIRE_RESOURCE,
@@ -2755,7 +2755,7 @@ Vector<uint8_t> RenderingDeviceVulkan::texture_get_data(RID p_texture, uint32_t
_THREAD_SAFE_METHOD_
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, Vector<uint8_t>());
+ ERR_FAIL_NULL_V(tex, Vector<uint8_t>());
ERR_FAIL_COND_V_MSG(tex->bound, Vector<uint8_t>(),
"Texture can't be retrieved while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to retrieve this texture.");
@@ -2885,7 +2885,7 @@ bool RenderingDeviceVulkan::texture_is_shared(RID p_texture) {
_THREAD_SAFE_METHOD_
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, false);
+ ERR_FAIL_NULL_V(tex, false);
return tex->owner.is_valid();
}
@@ -2897,7 +2897,7 @@ RD::TextureFormat RenderingDeviceVulkan::texture_get_format(RID p_texture) {
_THREAD_SAFE_METHOD_
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, TextureFormat());
+ ERR_FAIL_NULL_V(tex, TextureFormat());
TextureFormat tf;
@@ -2920,7 +2920,7 @@ Size2i RenderingDeviceVulkan::texture_size(RID p_texture) {
_THREAD_SAFE_METHOD_
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, Size2i());
+ ERR_FAIL_NULL_V(tex, Size2i());
return Size2i(tex->width, tex->height);
}
@@ -2928,7 +2928,7 @@ uint64_t RenderingDeviceVulkan::texture_get_native_handle(RID p_texture) {
_THREAD_SAFE_METHOD_
Texture *tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!tex, 0);
+ ERR_FAIL_NULL_V(tex, 0);
return (uint64_t)tex->image;
}
@@ -2937,7 +2937,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_from_texture);
- ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
"Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
@@ -2958,7 +2958,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
ERR_FAIL_COND_V(p_src_layer >= src_layer_count, ERR_INVALID_PARAMETER);
Texture *dst_tex = texture_owner.get_or_null(p_to_texture);
- ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,
"Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
@@ -3112,7 +3112,7 @@ Error RenderingDeviceVulkan::texture_copy(RID p_from_texture, RID p_to_texture,
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = dst_tex->image;
- image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask;
image_memory_barrier.subresourceRange.baseMipLevel = p_src_mipmap;
image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.baseArrayLayer = p_src_layer;
@@ -3136,7 +3136,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_from_texture);
- ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
"Source texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
@@ -3147,7 +3147,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
ERR_FAIL_COND_V_MSG(src_tex->samples == TEXTURE_SAMPLES_1, ERR_INVALID_PARAMETER, "Source texture must be multisampled.");
Texture *dst_tex = texture_owner.get_or_null(p_to_texture);
- ERR_FAIL_COND_V(!dst_tex, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(dst_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(dst_tex->bound, ERR_INVALID_PARAMETER,
"Destination texture can't be copied while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to copy this texture.");
@@ -3294,7 +3294,7 @@ Error RenderingDeviceVulkan::texture_resolve_multisample(RID p_from_texture, RID
image_memory_barrier.srcQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.dstQueueFamilyIndex = VK_QUEUE_FAMILY_IGNORED;
image_memory_barrier.image = dst_tex->image;
- image_memory_barrier.subresourceRange.aspectMask = VK_IMAGE_ASPECT_COLOR_BIT;
+ image_memory_barrier.subresourceRange.aspectMask = dst_tex->read_aspect_mask;
image_memory_barrier.subresourceRange.baseMipLevel = dst_tex->base_mipmap;
image_memory_barrier.subresourceRange.levelCount = 1;
image_memory_barrier.subresourceRange.baseArrayLayer = dst_tex->base_layer;
@@ -3311,7 +3311,7 @@ Error RenderingDeviceVulkan::texture_clear(RID p_texture, const Color &p_color,
_THREAD_SAFE_METHOD_
Texture *src_tex = texture_owner.get_or_null(p_texture);
- ERR_FAIL_COND_V(!src_tex, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(src_tex, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V_MSG(src_tex->bound, ERR_INVALID_PARAMETER,
"Source texture can't be cleared while a draw list that uses it as part of a framebuffer is being created. Ensure the draw list is finalized (and that the color/depth texture using it is not set to `RenderingDevice.FINAL_ACTION_CONTINUE`) to clear this texture.");
@@ -4299,7 +4299,7 @@ RenderingDevice::FramebufferFormatID RenderingDeviceVulkan::framebuffer_get_form
_THREAD_SAFE_METHOD_
Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
- ERR_FAIL_COND_V(!framebuffer, INVALID_ID);
+ ERR_FAIL_NULL_V(framebuffer, INVALID_ID);
return framebuffer->format_id;
}
@@ -4314,7 +4314,7 @@ void RenderingDeviceVulkan::framebuffer_set_invalidation_callback(RID p_framebuf
_THREAD_SAFE_METHOD_
Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
- ERR_FAIL_COND(!framebuffer);
+ ERR_FAIL_NULL(framebuffer);
framebuffer->invalidated_callback = p_callback;
framebuffer->invalidated_callback_userdata = p_userdata;
@@ -4619,7 +4619,7 @@ static VkShaderStageFlagBits shader_stage_masks[RenderingDevice::SHADER_STAGE_MA
String RenderingDeviceVulkan::_shader_uniform_debug(RID p_shader, int p_set) {
String ret;
const Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, String());
+ ERR_FAIL_NULL_V(shader, String());
for (int i = 0; i < shader->sets.size(); i++) {
if (p_set >= 0 && i != p_set) {
continue;
@@ -5212,7 +5212,7 @@ uint32_t RenderingDeviceVulkan::shader_get_vertex_input_attribute_mask(RID p_sha
_THREAD_SAFE_METHOD_
const Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, 0);
+ ERR_FAIL_NULL_V(shader, 0);
return shader->vertex_input_mask;
}
@@ -5429,7 +5429,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
ERR_FAIL_COND_V(p_uniforms.size() == 0, RID());
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, RID());
+ ERR_FAIL_NULL_V(shader, RID());
ERR_FAIL_COND_V_MSG(p_shader_set >= (uint32_t)shader->sets.size() || shader->sets[p_shader_set].uniform_info.size() == 0, RID(),
"Desired set (" + itos(p_shader_set) + ") not used by shader.");
@@ -5498,7 +5498,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j));
- ERR_FAIL_COND_V_MSG(!sampler, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");
+ ERR_FAIL_NULL_V_MSG(sampler, RID(), "Sampler (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid sampler.");
VkDescriptorImageInfo img_info;
img_info.sampler = *sampler;
@@ -5531,10 +5531,10 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j + 0));
- ERR_FAIL_COND_V_MSG(!sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
+ ERR_FAIL_NULL_V_MSG(sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
Texture *texture = texture_owner.get_or_null(uniform.get_id(j + 1));
- ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
+ ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
@@ -5585,7 +5585,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
- ERR_FAIL_COND_V_MSG(!texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
+ ERR_FAIL_NULL_V_MSG(texture, RID(), "Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
"Texture (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") needs the TEXTURE_USAGE_SAMPLING_BIT usage flag set in order to be used as uniform.");
@@ -5636,7 +5636,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
- ERR_FAIL_COND_V_MSG(!texture, RID(),
+ ERR_FAIL_NULL_V_MSG(texture, RID(),
"Image (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_STORAGE_BIT), RID(),
@@ -5682,7 +5682,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j));
- ERR_FAIL_COND_V_MSG(!buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer.");
+ ERR_FAIL_NULL_V_MSG(buffer, RID(), "Texture Buffer (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture buffer.");
buffer_info.push_back(buffer->buffer.buffer_info);
buffer_view.push_back(buffer->view);
@@ -5713,7 +5713,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
for (uint32_t j = 0; j < uniform.get_id_count(); j += 2) {
VkSampler *sampler = sampler_owner.get_or_null(uniform.get_id(j + 0));
- ERR_FAIL_COND_V_MSG(!sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
+ ERR_FAIL_NULL_V_MSG(sampler, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid sampler.");
TextureBuffer *buffer = texture_buffer_owner.get_or_null(uniform.get_id(j + 1));
@@ -5724,7 +5724,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
image_info.push_back(img_info);
- ERR_FAIL_COND_V_MSG(!buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer.");
+ ERR_FAIL_NULL_V_MSG(buffer, RID(), "SamplerBuffer (binding: " + itos(uniform.binding) + ", index " + itos(j + 1) + ") is not a valid texture buffer.");
buffer_info.push_back(buffer->buffer.buffer_info);
buffer_view.push_back(buffer->view);
@@ -5748,7 +5748,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") must provide one ID (" + itos(uniform.get_id_count()) + " provided).");
Buffer *buffer = uniform_buffer_owner.get_or_null(uniform.get_id(0));
- ERR_FAIL_COND_V_MSG(!buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
+ ERR_FAIL_NULL_V_MSG(buffer, RID(), "Uniform buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
ERR_FAIL_COND_V_MSG(buffer->size != (uint32_t)set_uniform.length, RID(),
"Uniform buffer supplied (binding: " + itos(uniform.binding) + ") size (" + itos(buffer->size) + " does not match size of shader uniform: (" + itos(set_uniform.length) + ").");
@@ -5774,7 +5774,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
ERR_FAIL_COND_V_MSG(!(buffer->usage & VK_BUFFER_USAGE_STORAGE_BUFFER_BIT), RID(), "Vertex buffer supplied (binding: " + itos(uniform.binding) + ") was not created with storage flag.");
}
- ERR_FAIL_COND_V_MSG(!buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
+ ERR_FAIL_NULL_V_MSG(buffer, RID(), "Storage buffer supplied (binding: " + itos(uniform.binding) + ") is invalid.");
// If 0, then it's sized on link time.
ERR_FAIL_COND_V_MSG(set_uniform.length > 0 && buffer->size != (uint32_t)set_uniform.length, RID(),
@@ -5803,7 +5803,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
for (uint32_t j = 0; j < uniform.get_id_count(); j++) {
Texture *texture = texture_owner.get_or_null(uniform.get_id(j));
- ERR_FAIL_COND_V_MSG(!texture, RID(),
+ ERR_FAIL_NULL_V_MSG(texture, RID(),
"InputAttachment (binding: " + itos(uniform.binding) + ", index " + itos(j) + ") is not a valid texture.");
ERR_FAIL_COND_V_MSG(!(texture->usage_flags & TEXTURE_USAGE_SAMPLING_BIT), RID(),
@@ -5843,7 +5843,7 @@ RID RenderingDeviceVulkan::uniform_set_create(const Vector<Uniform> &p_uniforms,
// Need a descriptor pool.
DescriptorPool *pool = _descriptor_pool_allocate(pool_key);
- ERR_FAIL_COND_V(!pool, RID());
+ ERR_FAIL_NULL_V(pool, RID());
VkDescriptorSetAllocateInfo descriptor_set_allocate_info;
@@ -5903,7 +5903,7 @@ bool RenderingDeviceVulkan::uniform_set_is_valid(RID p_uniform_set) {
void RenderingDeviceVulkan::uniform_set_set_invalidation_callback(RID p_uniform_set, InvalidationCallback p_callback, void *p_userdata) {
UniformSet *us = uniform_set_owner.get_or_null(p_uniform_set);
- ERR_FAIL_COND(!us);
+ ERR_FAIL_NULL(us);
us->invalidated_callback = p_callback;
us->invalidated_callback_userdata = p_userdata;
}
@@ -5918,7 +5918,7 @@ Error RenderingDeviceVulkan::buffer_copy(RID p_src_buffer, RID p_dst_buffer, uin
// This method assumes the barriers have been pushed prior to being called, therefore no barriers are pushed
// for the source or destination buffers before performing the copy. These masks are effectively ignored.
- VkPipelineShaderStageCreateFlags src_stage_mask = 0;
+ VkPipelineStageFlags src_stage_mask = 0;
VkAccessFlags src_access_mask = 0;
Buffer *src_buffer = _get_buffer_from_owner(p_src_buffer, src_stage_mask, src_access_mask, BARRIER_MASK_NO_BARRIER);
if (!src_buffer) {
@@ -6038,9 +6038,6 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
ERR_FAIL_COND_V_MSG(p_offset + p_size > buffer->size, ERR_INVALID_PARAMETER,
"Attempted to write buffer (" + itos((p_offset + p_size) - buffer->size) + " bytes) past the end.");
- // Should not be needed.
- // _buffer_memory_barrier(buffer->buffer, p_offset, p_size, dst_stage_mask, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_access, VK_ACCESS_TRANSFER_WRITE_BIT, p_post_barrier);
-
vkCmdFillBuffer(frames[frame].draw_command_buffer, buffer->buffer, p_offset, p_size, 0);
#ifdef FORCE_FULL_BARRIER
@@ -6050,7 +6047,7 @@ Error RenderingDeviceVulkan::buffer_clear(RID p_buffer, uint32_t p_offset, uint3
dst_stage_mask = VK_PIPELINE_STAGE_BOTTOM_OF_PIPE_BIT;
}
- _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, dst_stage_mask);
+ _buffer_memory_barrier(buffer->buffer, p_offset, p_size, VK_PIPELINE_STAGE_TRANSFER_BIT, dst_stage_mask, VK_ACCESS_TRANSFER_WRITE_BIT, dst_access, true);
#endif
return OK;
@@ -6118,7 +6115,7 @@ RID RenderingDeviceVulkan::render_pipeline_create(RID p_shader, FramebufferForma
// Needs a shader.
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, RID());
+ ERR_FAIL_NULL_V(shader, RID());
ERR_FAIL_COND_V_MSG(shader->is_compute, RID(),
"Compute shaders can't be used in render pipelines");
@@ -6590,7 +6587,7 @@ RID RenderingDeviceVulkan::compute_pipeline_create(RID p_shader, const Vector<Pi
// Needs a shader.
Shader *shader = shader_owner.get_or_null(p_shader);
- ERR_FAIL_COND_V(!shader, RID());
+ ERR_FAIL_NULL_V(shader, RID());
ERR_FAIL_COND_V_MSG(!shader->is_compute, RID(),
"Non-compute shaders can't be used in compute pipelines");
@@ -7004,7 +7001,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_begin(RID p_framebu
ERR_FAIL_COND_V_MSG(compute_list != nullptr && !compute_list->state.allow_draw_overlap, INVALID_ID, "Only one draw/compute list can be active at the same time.");
Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
- ERR_FAIL_COND_V(!framebuffer, INVALID_ID);
+ ERR_FAIL_NULL_V(framebuffer, INVALID_ID);
Point2i viewport_offset;
Point2i viewport_size = framebuffer->size;
@@ -7112,7 +7109,7 @@ Error RenderingDeviceVulkan::draw_list_begin_split(RID p_framebuffer, uint32_t p
ERR_FAIL_COND_V(p_splits < 1, ERR_INVALID_DECLARATION);
Framebuffer *framebuffer = framebuffer_owner.get_or_null(p_framebuffer);
- ERR_FAIL_COND_V(!framebuffer, ERR_INVALID_DECLARATION);
+ ERR_FAIL_NULL_V(framebuffer, ERR_INVALID_DECLARATION);
Point2i viewport_offset;
Point2i viewport_size = framebuffer->size;
@@ -7242,7 +7239,7 @@ RenderingDeviceVulkan::DrawList *RenderingDeviceVulkan::_get_draw_list_ptr(DrawL
void RenderingDeviceVulkan::draw_list_set_blend_constants(DrawListID p_list, const Color &p_color) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
@@ -7252,13 +7249,13 @@ void RenderingDeviceVulkan::draw_list_set_blend_constants(DrawListID p_list, con
void RenderingDeviceVulkan::draw_list_bind_render_pipeline(DrawListID p_list, RID p_render_pipeline) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
const RenderPipeline *pipeline = render_pipeline_owner.get_or_null(p_render_pipeline);
- ERR_FAIL_COND(!pipeline);
+ ERR_FAIL_NULL(pipeline);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND(pipeline->validation.framebuffer_format != draw_list_framebuffer_format && pipeline->validation.render_pass != draw_list_current_subpass);
#endif
@@ -7326,14 +7323,14 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_
"Attempting to bind a descriptor set (" + itos(p_index) + ") greater than what the hardware supports (" + itos(limits.maxBoundDescriptorSets) + ").");
#endif
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
const UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
- ERR_FAIL_COND(!uniform_set);
+ ERR_FAIL_NULL(uniform_set);
if (p_index > dl->state.set_count) {
dl->state.set_count = p_index;
@@ -7375,13 +7372,13 @@ void RenderingDeviceVulkan::draw_list_bind_uniform_set(DrawListID p_list, RID p_
void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p_vertex_array) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
const VertexArray *vertex_array = vertex_array_owner.get_or_null(p_vertex_array);
- ERR_FAIL_COND(!vertex_array);
+ ERR_FAIL_NULL(vertex_array);
if (dl->state.vertex_array == p_vertex_array) {
return; // Already set.
@@ -7399,13 +7396,13 @@ void RenderingDeviceVulkan::draw_list_bind_vertex_array(DrawListID p_list, RID p
void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_index_array) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
const IndexArray *index_array = index_array_owner.get_or_null(p_index_array);
- ERR_FAIL_COND(!index_array);
+ ERR_FAIL_NULL(index_array);
if (dl->state.index_array == p_index_array) {
return; // Already set.
@@ -7423,7 +7420,7 @@ void RenderingDeviceVulkan::draw_list_bind_index_array(DrawListID p_list, RID p_
void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_width) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
@@ -7433,7 +7430,7 @@ void RenderingDeviceVulkan::draw_list_set_line_width(DrawListID p_list, float p_
void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, const void *p_data, uint32_t p_data_size) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
@@ -7451,7 +7448,7 @@ void RenderingDeviceVulkan::draw_list_set_push_constant(DrawListID p_list, const
void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices, uint32_t p_instances, uint32_t p_procedural_vertices) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
@@ -7557,7 +7554,7 @@ void RenderingDeviceVulkan::draw_list_draw(DrawListID p_list, bool p_use_indices
void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Rect2 &p_rect) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
@@ -7580,7 +7577,7 @@ void RenderingDeviceVulkan::draw_list_enable_scissor(DrawListID p_list, const Re
void RenderingDeviceVulkan::draw_list_disable_scissor(DrawListID p_list) {
DrawList *dl = _get_draw_list_ptr(p_list);
- ERR_FAIL_COND(!dl);
+ ERR_FAIL_NULL(dl);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(!dl->validation.active, "Submitted Draw Lists can no longer be modified.");
#endif
@@ -7599,7 +7596,7 @@ uint32_t RenderingDeviceVulkan::draw_list_get_current_pass() {
RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_switch_to_next_pass() {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(draw_list == nullptr, INVALID_ID);
+ ERR_FAIL_NULL_V(draw_list, INVALID_ID);
ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, INVALID_FORMAT_ID);
draw_list_current_subpass++;
@@ -7615,7 +7612,7 @@ RenderingDevice::DrawListID RenderingDeviceVulkan::draw_list_switch_to_next_pass
}
Error RenderingDeviceVulkan::draw_list_switch_to_next_pass_split(uint32_t p_splits, DrawListID *r_split_ids) {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(draw_list == nullptr, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(draw_list, ERR_INVALID_PARAMETER);
ERR_FAIL_COND_V(draw_list_current_subpass >= draw_list_subpass_count - 1, ERR_INVALID_PARAMETER);
draw_list_current_subpass++;
@@ -7756,7 +7753,7 @@ void RenderingDeviceVulkan::_draw_list_free(Rect2i *r_last_viewport) {
void RenderingDeviceVulkan::draw_list_end(BitField<BarrierMask> p_post_barrier) {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_MSG(!draw_list, "Immediate draw list is already inactive.");
+ ERR_FAIL_NULL_MSG(draw_list, "Immediate draw list is already inactive.");
_draw_list_free();
@@ -7884,12 +7881,12 @@ void RenderingDeviceVulkan::compute_list_bind_compute_pipeline(ComputeListID p_l
// Must be called within a compute list, the class mutex is locked during that time
ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
- ERR_FAIL_COND(!compute_list);
+ ERR_FAIL_NULL(compute_list);
ComputeList *cl = compute_list;
const ComputePipeline *pipeline = compute_pipeline_owner.get_or_null(p_compute_pipeline);
- ERR_FAIL_COND(!pipeline);
+ ERR_FAIL_NULL(pipeline);
if (p_compute_pipeline == cl->state.pipeline) {
return; // Redundant state, return.
@@ -7950,7 +7947,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
// Must be called within a compute list, the class mutex is locked during that time
ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
- ERR_FAIL_COND(!compute_list);
+ ERR_FAIL_NULL(compute_list);
ComputeList *cl = compute_list;
@@ -7964,7 +7961,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
#endif
UniformSet *uniform_set = uniform_set_owner.get_or_null(p_uniform_set);
- ERR_FAIL_COND(!uniform_set);
+ ERR_FAIL_NULL(uniform_set);
if (p_index > cl->state.set_count) {
cl->state.set_count = p_index;
@@ -8104,7 +8101,7 @@ void RenderingDeviceVulkan::compute_list_bind_uniform_set(ComputeListID p_list,
void RenderingDeviceVulkan::compute_list_set_push_constant(ComputeListID p_list, const void *p_data, uint32_t p_data_size) {
ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
- ERR_FAIL_COND(!compute_list);
+ ERR_FAIL_NULL(compute_list);
ComputeList *cl = compute_list;
@@ -8126,7 +8123,7 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
// Must be called within a compute list, the class mutex is locked during that time
ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
- ERR_FAIL_COND(!compute_list);
+ ERR_FAIL_NULL(compute_list);
ComputeList *cl = compute_list;
@@ -8186,7 +8183,7 @@ void RenderingDeviceVulkan::compute_list_dispatch(ComputeListID p_list, uint32_t
void RenderingDeviceVulkan::compute_list_dispatch_threads(ComputeListID p_list, uint32_t p_x_threads, uint32_t p_y_threads, uint32_t p_z_threads) {
ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
- ERR_FAIL_COND(!compute_list);
+ ERR_FAIL_NULL(compute_list);
#ifdef DEBUG_ENABLED
ERR_FAIL_COND_MSG(p_x_threads == 0, "Dispatch amount of X compute threads (" + itos(p_x_threads) + ") is zero.");
@@ -8213,11 +8210,11 @@ void RenderingDeviceVulkan::compute_list_dispatch_threads(ComputeListID p_list,
void RenderingDeviceVulkan::compute_list_dispatch_indirect(ComputeListID p_list, RID p_buffer, uint32_t p_offset) {
ERR_FAIL_COND(p_list != ID_TYPE_COMPUTE_LIST);
- ERR_FAIL_COND(!compute_list);
+ ERR_FAIL_NULL(compute_list);
ComputeList *cl = compute_list;
Buffer *buffer = storage_buffer_owner.get_or_null(p_buffer);
- ERR_FAIL_COND(!buffer);
+ ERR_FAIL_NULL(buffer);
ERR_FAIL_COND_MSG(!(buffer->usage & VK_BUFFER_USAGE_INDIRECT_BUFFER_BIT), "Buffer provided was not created to do indirect dispatch.");
@@ -8276,7 +8273,7 @@ void RenderingDeviceVulkan::compute_list_add_barrier(ComputeListID p_list) {
}
void RenderingDeviceVulkan::_compute_list_add_barrier(BitField<BarrierMask> p_post_barrier, uint32_t p_barrier_flags, uint32_t p_access_flags) {
- ERR_FAIL_COND(!compute_list);
+ ERR_FAIL_NULL(compute_list);
VkImageMemoryBarrier *image_barriers = nullptr;
@@ -8335,7 +8332,7 @@ void RenderingDeviceVulkan::_compute_list_add_barrier(BitField<BarrierMask> p_po
}
void RenderingDeviceVulkan::compute_list_end(BitField<BarrierMask> p_post_barrier) {
- ERR_FAIL_COND(!compute_list);
+ ERR_FAIL_NULL(compute_list);
uint32_t barrier_flags = 0;
uint32_t access_flags = 0;
@@ -8425,7 +8422,7 @@ void RenderingDeviceVulkan::full_barrier() {
#if 0
void RenderingDeviceVulkan::draw_list_render_secondary_to_framebuffer(ID p_framebuffer, ID *p_draw_lists, uint32_t p_draw_list_count, InitialAction p_initial_action, FinalAction p_final_action, const Vector<Variant> &p_clear_colors) {
VkCommandBuffer frame_cmdbuf = frames[frame].frame_buffer;
- ERR_FAIL_COND(!frame_cmdbuf);
+ ERR_FAIL_NULL(frame_cmdbuf);
VkRenderPassBeginInfo render_pass_begin;
render_pass_begin.sType = VK_STRUCTURE_TYPE_RENDER_PASS_BEGIN_INFO;
@@ -9158,7 +9155,7 @@ void RenderingDeviceVulkan::initialize(VulkanContext *p_context, bool p_local_de
VkPipelineCacheCreateInfo cache_info = {};
cache_info.sType = VK_STRUCTURE_TYPE_PIPELINE_CACHE_CREATE_INFO;
cache_info.pNext = nullptr;
- if (context->is_device_extension_enabled(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME)) {
+ if (context->get_pipeline_cache_control_support()) {
cache_info.flags = VK_PIPELINE_CACHE_CREATE_EXTERNALLY_SYNCHRONIZED_BIT;
}
cache_info.initialDataSize = pipelines_cache.buffer.size();
diff --git a/drivers/vulkan/vulkan_context.cpp b/drivers/vulkan/vulkan_context.cpp
index 9f35230eaf..344ea0d324 100644
--- a/drivers/vulkan/vulkan_context.cpp
+++ b/drivers/vulkan/vulkan_context.cpp
@@ -769,6 +769,7 @@ Error VulkanContext::_check_capabilities() {
VkPhysicalDeviceFragmentShadingRateFeaturesKHR vrs_features = {};
VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
VkPhysicalDeviceMultiviewFeatures multiview_features = {};
+ VkPhysicalDevicePipelineCreationCacheControlFeatures pipeline_cache_control_features = {};
if (device_api_version >= VK_API_VERSION_1_2) {
device_features_vk12.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VULKAN_1_2_FEATURES;
@@ -820,6 +821,15 @@ Error VulkanContext::_check_capabilities() {
next = &multiview_features;
}
+ if (is_device_extension_enabled(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME)) {
+ pipeline_cache_control_features = {
+ /*sType*/ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES,
+ /*pNext*/ next,
+ /*pipelineCreationCacheControl*/ false,
+ };
+ next = &pipeline_cache_control_features;
+ }
+
VkPhysicalDeviceFeatures2 device_features;
device_features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
device_features.pNext = next;
@@ -860,6 +870,10 @@ Error VulkanContext::_check_capabilities() {
storage_buffer_capabilities.storage_push_constant_16_is_supported = storage_feature.storagePushConstant16;
storage_buffer_capabilities.storage_input_output_16 = storage_feature.storageInputOutput16;
}
+
+ if (is_device_extension_enabled(VK_EXT_PIPELINE_CREATION_CACHE_CONTROL_EXTENSION_NAME)) {
+ pipeline_cache_control_support = pipeline_cache_control_features.pipelineCreationCacheControl;
+ }
}
// Check extended properties.
@@ -1422,6 +1436,16 @@ Error VulkanContext::_create_device() {
nextptr = &vrs_features;
}
+ VkPhysicalDevicePipelineCreationCacheControlFeatures pipeline_cache_control_features = {};
+ if (pipeline_cache_control_support) {
+ pipeline_cache_control_features.sType =
+ VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PIPELINE_CREATION_CACHE_CONTROL_FEATURES;
+ pipeline_cache_control_features.pNext = nextptr;
+ pipeline_cache_control_features.pipelineCreationCacheControl = pipeline_cache_control_support;
+
+ nextptr = &pipeline_cache_control_features;
+ }
+
VkPhysicalDeviceVulkan11Features vulkan11features = {};
VkPhysicalDevice16BitStorageFeaturesKHR storage_feature = {};
VkPhysicalDeviceMultiviewFeatures multiview_features = {};
diff --git a/drivers/vulkan/vulkan_context.h b/drivers/vulkan/vulkan_context.h
index 9fd2c40a06..ef40aba9e1 100644
--- a/drivers/vulkan/vulkan_context.h
+++ b/drivers/vulkan/vulkan_context.h
@@ -116,6 +116,7 @@ private:
VRSCapabilities vrs_capabilities;
ShaderCapabilities shader_capabilities;
StorageBufferCapabilities storage_buffer_capabilities;
+ bool pipeline_cache_control_support = false;
String device_vendor;
String device_name;
@@ -281,6 +282,7 @@ public:
const ShaderCapabilities &get_shader_capabilities() const { return shader_capabilities; };
const StorageBufferCapabilities &get_storage_buffer_capabilities() const { return storage_buffer_capabilities; };
const VkPhysicalDeviceFeatures &get_physical_device_features() const { return physical_device_features; };
+ bool get_pipeline_cache_control_support() const { return pipeline_cache_control_support; };
VkDevice get_device();
VkPhysicalDevice get_physical_device();
diff --git a/drivers/windows/file_access_windows.cpp b/drivers/windows/file_access_windows.cpp
index da2ce1c208..98b0c358e8 100644
--- a/drivers/windows/file_access_windows.cpp
+++ b/drivers/windows/file_access_windows.cpp
@@ -50,7 +50,7 @@
#endif
void FileAccessWindows::check_errors() const {
- ERR_FAIL_COND(!f);
+ ERR_FAIL_NULL(f);
if (feof(f)) {
last_error = ERR_FILE_EOF;
@@ -223,7 +223,7 @@ bool FileAccessWindows::is_open() const {
}
void FileAccessWindows::seek(uint64_t p_position) {
- ERR_FAIL_COND(!f);
+ ERR_FAIL_NULL(f);
last_error = OK;
if (_fseeki64(f, p_position, SEEK_SET)) {
@@ -233,7 +233,7 @@ void FileAccessWindows::seek(uint64_t p_position) {
}
void FileAccessWindows::seek_end(int64_t p_position) {
- ERR_FAIL_COND(!f);
+ ERR_FAIL_NULL(f);
if (_fseeki64(f, p_position, SEEK_END)) {
check_errors();
@@ -250,7 +250,7 @@ uint64_t FileAccessWindows::get_position() const {
}
uint64_t FileAccessWindows::get_length() const {
- ERR_FAIL_COND_V(!f, 0);
+ ERR_FAIL_NULL_V(f, 0);
uint64_t pos = get_position();
_fseeki64(f, 0, SEEK_END);
@@ -266,7 +266,7 @@ bool FileAccessWindows::eof_reached() const {
}
uint8_t FileAccessWindows::get_8() const {
- ERR_FAIL_COND_V(!f, 0);
+ ERR_FAIL_NULL_V(f, 0);
if (flags == READ_WRITE || flags == WRITE_READ) {
if (prev_op == WRITE) {
@@ -285,7 +285,7 @@ uint8_t FileAccessWindows::get_8() const {
uint64_t FileAccessWindows::get_buffer(uint8_t *p_dst, uint64_t p_length) const {
ERR_FAIL_COND_V(!p_dst && p_length > 0, -1);
- ERR_FAIL_COND_V(!f, -1);
+ ERR_FAIL_NULL_V(f, -1);
if (flags == READ_WRITE || flags == WRITE_READ) {
if (prev_op == WRITE) {
@@ -303,7 +303,7 @@ Error FileAccessWindows::get_error() const {
}
void FileAccessWindows::flush() {
- ERR_FAIL_COND(!f);
+ ERR_FAIL_NULL(f);
fflush(f);
if (prev_op == WRITE) {
@@ -312,7 +312,7 @@ void FileAccessWindows::flush() {
}
void FileAccessWindows::store_8(uint8_t p_dest) {
- ERR_FAIL_COND(!f);
+ ERR_FAIL_NULL(f);
if (flags == READ_WRITE || flags == WRITE_READ) {
if (prev_op == READ) {
@@ -326,7 +326,7 @@ void FileAccessWindows::store_8(uint8_t p_dest) {
}
void FileAccessWindows::store_buffer(const uint8_t *p_src, uint64_t p_length) {
- ERR_FAIL_COND(!f);
+ ERR_FAIL_NULL(f);
ERR_FAIL_COND(!p_src && p_length > 0);
if (flags == READ_WRITE || flags == WRITE_READ) {
diff --git a/editor/animation_track_editor.cpp b/editor/animation_track_editor.cpp
index 77ab709679..5b87dc4f46 100644
--- a/editor/animation_track_editor.cpp
+++ b/editor/animation_track_editor.cpp
@@ -77,10 +77,10 @@ void AnimationTrackKeyEdit::_fix_node_path(Variant &value) {
Node *root = EditorNode::get_singleton()->get_tree()->get_root();
Node *np_node = root->get_node(np);
- ERR_FAIL_COND(!np_node);
+ ERR_FAIL_NULL(np_node);
Node *edited_node = root->get_node(base);
- ERR_FAIL_COND(!edited_node);
+ ERR_FAIL_NULL(edited_node);
value = edited_node->get_path_to(np_node);
}
@@ -136,22 +136,22 @@ bool AnimationTrackKeyEdit::_set(const StringName &p_name, const Variant &p_valu
if (name == "position" || name == "rotation" || name == "scale") {
Variant old = animation->track_get_key_value(track, key);
setting = true;
- String chan;
+ String action_name;
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D:
- chan = "Position3D";
+ action_name = TTR("Animation Change Position3D");
break;
case Animation::TYPE_ROTATION_3D:
- chan = "Rotation3D";
+ action_name = TTR("Animation Change Rotation3D");
break;
case Animation::TYPE_SCALE_3D:
- chan = "Scale3D";
+ action_name = TTR("Animation Change Scale3D");
break;
default: {
}
}
- undo_redo->create_action(vformat(TTR("Animation Change %s"), chan));
+ undo_redo->create_action(action_name);
undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
undo_redo->add_do_method(this, "_update_obj", animation);
@@ -656,10 +656,10 @@ void AnimationMultiTrackKeyEdit::_fix_node_path(Variant &value, NodePath &base)
Node *root = EditorNode::get_singleton()->get_tree()->get_root();
Node *np_node = root->get_node(np);
- ERR_FAIL_COND(!np_node);
+ ERR_FAIL_NULL(np_node);
Node *edited_node = root->get_node(base);
- ERR_FAIL_COND(!edited_node);
+ ERR_FAIL_NULL(edited_node);
value = edited_node->get_path_to(np_node);
}
@@ -730,23 +730,23 @@ bool AnimationMultiTrackKeyEdit::_set(const StringName &p_name, const Variant &p
case Animation::TYPE_SCALE_3D: {
Variant old = animation->track_get_key_value(track, key);
if (!setting) {
- String chan;
+ String action_name;
switch (animation->track_get_type(track)) {
case Animation::TYPE_POSITION_3D:
- chan = "Position3D";
+ action_name = TTR("Animation Multi Change Position3D");
break;
case Animation::TYPE_ROTATION_3D:
- chan = "Rotation3D";
+ action_name = TTR("Animation Multi Change Rotation3D");
break;
case Animation::TYPE_SCALE_3D:
- chan = "Scale3D";
+ action_name = TTR("Animation Multi Change Scale3D");
break;
default: {
}
}
setting = true;
- undo_redo->create_action(vformat(TTR("Animation Multi Change %s"), chan));
+ undo_redo->create_action(action_name);
}
undo_redo->add_do_method(animation.ptr(), "track_set_key_value", track, key, p_value);
undo_redo->add_undo_method(animation.ptr(), "track_set_key_value", track, key, old);
@@ -2177,7 +2177,7 @@ void AnimationTrackEdit::draw_key_link(int p_index, float p_pixels_sec, int p_x,
Variant current = animation->track_get_key_value(get_track(), p_index);
Variant next = animation->track_get_key_value(get_track(), p_index + 1);
- if (current != next) {
+ if (current != next || animation->track_get_type(get_track()) == Animation::TrackType::TYPE_METHOD) {
return;
}
@@ -3703,7 +3703,7 @@ void AnimationTrackEditor::_insert_track(bool p_reset_wanted, bool p_create_bezi
}
void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type, const Variant p_value) {
- ERR_FAIL_COND(!root);
+ ERR_FAIL_NULL(root);
ERR_FAIL_COND_MSG(
(p_type != Animation::TYPE_POSITION_3D && p_type != Animation::TYPE_ROTATION_3D && p_type != Animation::TYPE_SCALE_3D),
"Track type must be Position/Rotation/Scale 3D.");
@@ -3746,7 +3746,7 @@ void AnimationTrackEditor::insert_transform_key(Node3D *p_node, const String &p_
}
bool AnimationTrackEditor::has_track(Node3D *p_node, const String &p_sub, const Animation::TrackType p_type) {
- ERR_FAIL_COND_V(!root, false);
+ ERR_FAIL_NULL_V(root, false);
if (!keying) {
return false;
}
@@ -3802,7 +3802,7 @@ void AnimationTrackEditor::_insert_animation_key(NodePath p_path, const Variant
}
void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_property, const Variant &p_value, bool p_only_if_exists) {
- ERR_FAIL_COND(!root);
+ ERR_FAIL_NULL(root);
// Let's build a node path.
Node *node = p_node;
@@ -3899,7 +3899,7 @@ void AnimationTrackEditor::insert_node_value_key(Node *p_node, const String &p_p
void AnimationTrackEditor::insert_value_key(const String &p_property, const Variant &p_value, bool p_advance) {
EditorSelectionHistory *history = EditorNode::get_singleton()->get_editor_selection_history();
- ERR_FAIL_COND(!root);
+ ERR_FAIL_NULL(root);
ERR_FAIL_COND(history->get_path_size() == 0);
Object *obj = ObjectDB::get_instance(history->get_path_object(0));
ERR_FAIL_COND(!Object::cast_to<Node>(obj));
@@ -4302,7 +4302,7 @@ bool AnimationTrackEditor::is_selection_active() const {
}
bool AnimationTrackEditor::is_snap_enabled() const {
- return snap->is_pressed() ^ Input::get_singleton()->is_key_pressed(Key::CTRL);
+ return snap->is_pressed() ^ Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
}
void AnimationTrackEditor::_update_tracks() {
@@ -4685,9 +4685,9 @@ void AnimationTrackEditor::_dropped_track(int p_from_track, int p_to_track) {
}
void AnimationTrackEditor::_new_track_node_selected(NodePath p_path) {
- ERR_FAIL_COND(!root);
+ ERR_FAIL_NULL(root);
Node *node = get_node(p_path);
- ERR_FAIL_COND(!node);
+ ERR_FAIL_NULL(node);
NodePath path_to = root->get_path_to(node, true);
if (adding_track_type == Animation::TYPE_BLEND_SHAPE && !node->is_class("MeshInstance3D")) {
@@ -6052,7 +6052,7 @@ void AnimationTrackEditor::_edit_menu_pressed(int p_option) {
} break;
case EDIT_BAKE_ANIMATION_CONFIRM: {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Bake Animation as Linear keys."));
+ undo_redo->create_action(TTR("Bake Animation as Linear Keys"));
int track_len = animation->get_track_count();
bool b_trs = bake_trs->is_pressed();
diff --git a/editor/connections_dialog.cpp b/editor/connections_dialog.cpp
index 11fc5efd62..208253d617 100644
--- a/editor/connections_dialog.cpp
+++ b/editor/connections_dialog.cpp
@@ -517,16 +517,41 @@ String ConnectDialog::get_signature(const MethodInfo &p_method, PackedStringArra
}
const PropertyInfo &pi = p_method.arguments[i];
- String tname = "var";
- if (pi.type == Variant::OBJECT && pi.class_name != StringName()) {
- tname = pi.class_name.operator String();
- } else if (pi.type != Variant::NIL) {
- tname = Variant::get_type_name(pi.type);
+ String type_name;
+ switch (pi.type) {
+ case Variant::NIL:
+ type_name = "Variant";
+ break;
+ case Variant::INT:
+ if ((pi.usage & PROPERTY_USAGE_CLASS_IS_ENUM) && pi.class_name != StringName() && !String(pi.class_name).begins_with("res://")) {
+ type_name = pi.class_name;
+ } else {
+ type_name = "int";
+ }
+ break;
+ case Variant::ARRAY:
+ if (pi.hint == PROPERTY_HINT_ARRAY_TYPE && !pi.hint_string.is_empty() && !pi.hint_string.begins_with("res://")) {
+ type_name = "Array[" + pi.hint_string + "]";
+ } else {
+ type_name = "Array";
+ }
+ break;
+ case Variant::OBJECT:
+ if (pi.class_name != StringName()) {
+ type_name = pi.class_name;
+ } else {
+ type_name = "Object";
+ }
+ break;
+ default:
+ type_name = Variant::get_type_name(pi.type);
+ break;
}
- signature.append((pi.name.is_empty() ? String("arg " + itos(i)) : pi.name) + ": " + tname);
+ String arg_name = pi.name.is_empty() ? "arg" + itos(i) : pi.name;
+ signature.append(arg_name + ": " + type_name);
if (r_arg_names) {
- r_arg_names->push_back(pi.name + ":" + tname);
+ r_arg_names->push_back(arg_name + ":" + type_name);
}
}
@@ -858,7 +883,7 @@ void ConnectionsDock::_filter_changed(const String &p_text) {
void ConnectionsDock::_make_or_edit_connection() {
NodePath dst_path = connect_dialog->get_dst_path();
Node *target = selected_node->get_node(dst_path);
- ERR_FAIL_COND(!target);
+ ERR_FAIL_NULL(target);
ConnectDialog::ConnectionData cd;
cd.source = connect_dialog->get_source();
@@ -1066,7 +1091,7 @@ void ConnectionsDock::_open_connection_dialog(TreeItem &p_item) {
*/
void ConnectionsDock::_open_edit_connection_dialog(TreeItem &p_item) {
TreeItem *signal_item = p_item.get_parent();
- ERR_FAIL_COND(!signal_item);
+ ERR_FAIL_NULL(signal_item);
Connection connection = p_item.get_metadata(0);
ConnectDialog::ConnectionData cd = connection;
@@ -1213,6 +1238,11 @@ void ConnectionsDock::_rmb_pressed(const Ref<InputEvent> &p_event) {
return;
}
+ if (item->is_selectable(0)) {
+ // Update selection now, before `about_to_popup` signal. Needed for SIGNAL and CONNECTION context menus.
+ tree->set_selected(item);
+ }
+
Vector2 screen_position = tree->get_screen_position() + mb_event->get_position();
switch (_get_item_type(*item)) {
diff --git a/editor/create_dialog.cpp b/editor/create_dialog.cpp
index a8a2ac0c20..26c89b0989 100644
--- a/editor/create_dialog.cpp
+++ b/editor/create_dialog.cpp
@@ -136,6 +136,10 @@ bool CreateDialog::_should_hide_type(const String &p_type) const {
return true; // Wrong inheritance.
}
+ if (!ClassDB::is_class_exposed(p_type)) {
+ return true; // Unexposed types.
+ }
+
for (const StringName &E : type_blacklist) {
if (ClassDB::is_parent_class(p_type, E)) {
return true; // Parent type is blacklisted.
@@ -450,16 +454,10 @@ void CreateDialog::_sbox_input(const Ref<InputEvent> &p_ie) {
}
}
-void CreateDialog::_update_theme() {
- search_box->set_right_icon(search_options->get_editor_theme_icon(SNAME("Search")));
- favorite->set_icon(search_options->get_editor_theme_icon(SNAME("Favorites")));
-}
-
void CreateDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
connect("confirmed", callable_mp(this, &CreateDialog::_confirmed));
- _update_theme();
} break;
case NOTIFICATION_EXIT_TREE: {
@@ -481,7 +479,8 @@ void CreateDialog::_notification(int p_what) {
favorites->add_theme_constant_override("icon_max_width", icon_width);
recent->set_fixed_icon_size(Size2(icon_width, icon_width));
- _update_theme();
+ search_box->set_right_icon(get_editor_theme_icon(SNAME("Search")));
+ favorite->set_icon(get_editor_theme_icon(SNAME("Favorites")));
} break;
}
}
diff --git a/editor/create_dialog.h b/editor/create_dialog.h
index 37579812cf..694efd1ee1 100644
--- a/editor/create_dialog.h
+++ b/editor/create_dialog.h
@@ -102,8 +102,6 @@ class CreateDialog : public ConfirmationDialog {
bool _is_class_disabled_by_feature_profile(const StringName &p_class) const;
void _load_favorites_and_history();
- void _update_theme();
-
protected:
void _notification(int p_what);
static void _bind_methods();
diff --git a/editor/debugger/editor_debugger_node.cpp b/editor/debugger/editor_debugger_node.cpp
index 99c66261e4..a327fd778b 100644
--- a/editor/debugger/editor_debugger_node.cpp
+++ b/editor/debugger/editor_debugger_node.cpp
@@ -51,7 +51,7 @@ template <typename Func>
void _for_all(TabContainer *p_node, const Func &p_func) {
for (int i = 0; i < p_node->get_tab_count(); i++) {
ScriptEditorDebugger *dbg = Object::cast_to<ScriptEditorDebugger>(p_node->get_tab_control(i));
- ERR_FAIL_COND(!dbg);
+ ERR_FAIL_NULL(dbg);
p_func(dbg);
}
}
@@ -63,8 +63,8 @@ EditorDebuggerNode::EditorDebuggerNode() {
singleton = this;
}
- add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_LEFT));
- add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_RIGHT));
+ add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_LEFT));
+ add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_RIGHT));
tabs = memnew(TabContainer);
tabs->set_tabs_visible(false);
@@ -119,7 +119,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
if (tabs->get_tab_count() > 1) {
node->clear_style();
tabs->set_tabs_visible(true);
- tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles)));
+ tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles)));
}
if (!debugger_plugins.is_empty()) {
@@ -133,7 +133,7 @@ ScriptEditorDebugger *EditorDebuggerNode::_add_debugger() {
void EditorDebuggerNode::_stack_frame_selected(int p_debugger) {
const ScriptEditorDebugger *dbg = get_debugger(p_debugger);
- ERR_FAIL_COND(!dbg);
+ ERR_FAIL_NULL(dbg);
if (dbg != get_current_debugger()) {
return;
}
@@ -284,10 +284,10 @@ void EditorDebuggerNode::_notification(int p_what) {
switch (p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
if (tabs->get_tab_count() > 1) {
- add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_LEFT));
- add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_RIGHT));
+ add_theme_constant_override("margin_left", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_LEFT));
+ add_theme_constant_override("margin_right", -EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("BottomPanelDebuggerOverride"), EditorStringName(EditorStyles))->get_margin(SIDE_RIGHT));
- tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles)));
+ tabs->add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("DebuggerPanel"), EditorStringName(EditorStyles)));
}
} break;
@@ -405,7 +405,7 @@ void EditorDebuggerNode::_update_errors() {
void EditorDebuggerNode::_debugger_stopped(int p_id) {
ScriptEditorDebugger *dbg = get_debugger(p_id);
- ERR_FAIL_COND(!dbg);
+ ERR_FAIL_NULL(dbg);
bool found = false;
_for_all(tabs, [&](ScriptEditorDebugger *p_debugger) {
@@ -603,7 +603,7 @@ void EditorDebuggerNode::_remote_tree_button_pressed(Object *p_item, int p_colum
}
TreeItem *item = Object::cast_to<TreeItem>(p_item);
- ERR_FAIL_COND(!item);
+ ERR_FAIL_NULL(item);
if (p_id == EditorDebuggerTree::BUTTON_SUBSCENE) {
remote_scene_tree->emit_signal(SNAME("open"), item->get_meta("scene_file_path"));
diff --git a/editor/debugger/editor_debugger_tree.cpp b/editor/debugger/editor_debugger_tree.cpp
index 2e24a233a1..6305b7435a 100644
--- a/editor/debugger/editor_debugger_tree.cpp
+++ b/editor/debugger/editor_debugger_tree.cpp
@@ -300,7 +300,7 @@ String EditorDebuggerTree::get_selected_path() {
}
String EditorDebuggerTree::_get_path(TreeItem *p_item) {
- ERR_FAIL_COND_V(!p_item, "");
+ ERR_FAIL_NULL_V(p_item, "");
if (p_item->get_parent() == nullptr) {
return "/root";
diff --git a/editor/debugger/editor_performance_profiler.cpp b/editor/debugger/editor_performance_profiler.cpp
index e6e9d4e33d..e93369179c 100644
--- a/editor/debugger/editor_performance_profiler.cpp
+++ b/editor/debugger/editor_performance_profiler.cpp
@@ -47,7 +47,7 @@ EditorPerformanceProfiler::Monitor::Monitor(String p_name, String p_base, int p_
}
void EditorPerformanceProfiler::Monitor::update_value(float p_value) {
- ERR_FAIL_COND(!item);
+ ERR_FAIL_NULL(item);
String label = EditorPerformanceProfiler::_create_label(p_value, type);
String tooltip = label;
switch (type) {
diff --git a/editor/editor_audio_buses.cpp b/editor/editor_audio_buses.cpp
index 8b60ac405a..109a10750f 100644
--- a/editor/editor_audio_buses.cpp
+++ b/editor/editor_audio_buses.cpp
@@ -298,8 +298,6 @@ void EditorAudioBus::_name_changed(const String &p_new_name) {
StringName current = AudioServer::get_singleton()->get_bus_name(get_index());
ur->create_action(TTR("Rename Audio Bus"));
- ur->add_do_method(buses, "_set_renaming_buses", true);
- ur->add_undo_method(buses, "_set_renaming_buses", true);
ur->add_do_method(AudioServer::get_singleton(), "set_bus_name", get_index(), attempt);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_name", get_index(), current);
@@ -317,8 +315,6 @@ void EditorAudioBus::_name_changed(const String &p_new_name) {
ur->add_do_method(buses, "_update_sends");
ur->add_undo_method(buses, "_update_sends");
- ur->add_do_method(buses, "_set_renaming_buses", false);
- ur->add_undo_method(buses, "_set_renaming_buses", false);
ur->commit_action();
updating_bus = false;
@@ -333,7 +329,7 @@ void EditorAudioBus::_volume_changed(float p_normalized) {
const float p_db = this->_normalized_volume_to_scaled_db(p_normalized);
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
// Snap the value when holding Ctrl for easier editing.
// To do so, it needs to be converted back to normalized volume (as the slider uses that unit).
slider->set_value(_scaled_db_to_normalized_volume(Math::round(p_db)));
@@ -393,7 +389,7 @@ float EditorAudioBus::_scaled_db_to_normalized_volume(float db) {
void EditorAudioBus::_show_value(float slider_value) {
float db;
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
// Display the correct (snapped) value when holding Ctrl
db = Math::round(_normalized_volume_to_scaled_db(slider_value));
} else {
@@ -545,9 +541,9 @@ void EditorAudioBus::_effect_add(int p_which) {
StringName name = effect_options->get_item_metadata(p_which);
Object *fx = ClassDB::instantiate(name);
- ERR_FAIL_COND(!fx);
+ ERR_FAIL_NULL(fx);
AudioEffect *afx = Object::cast_to<AudioEffect>(fx);
- ERR_FAIL_COND(!afx);
+ ERR_FAIL_NULL(afx);
Ref<AudioEffect> afxr = Ref<AudioEffect>(afx);
afxr->set_name(effect_options->get_item_text(p_which));
@@ -1011,18 +1007,7 @@ void EditorAudioBusDrop::_bind_methods() {
EditorAudioBusDrop::EditorAudioBusDrop() {
}
-void EditorAudioBuses::_set_renaming_buses(bool p_renaming) {
- renaming_buses = p_renaming;
-}
-
-void EditorAudioBuses::_update_buses() {
- if (renaming_buses) {
- // This case will be handled more gracefully, no need to trigger a full rebuild.
- // This is possibly a mistake in the AudioServer, which fires bus_layout_changed
- // on a rename. This may not be intended, but no way to tell at the moment.
- return;
- }
-
+void EditorAudioBuses::_rebuild_buses() {
for (int i = bus_hb->get_child_count() - 1; i >= 0; i--) {
EditorAudioBus *audio_bus = Object::cast_to<EditorAudioBus>(bus_hb->get_child(i));
if (audio_bus) {
@@ -1063,7 +1048,7 @@ void EditorAudioBuses::_notification(int p_what) {
} break;
case NOTIFICATION_READY: {
- _update_buses();
+ _rebuild_buses();
} break;
case NOTIFICATION_DRAG_END: {
@@ -1102,8 +1087,6 @@ void EditorAudioBuses::_add_bus() {
ur->create_action(TTR("Add Audio Bus"));
ur->add_do_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count() + 1);
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_count", AudioServer::get_singleton()->get_bus_count());
- ur->add_do_method(this, "_update_buses");
- ur->add_undo_method(this, "_update_buses");
ur->commit_action();
}
@@ -1144,8 +1127,6 @@ void EditorAudioBuses::_delete_bus(Object *p_which) {
ur->add_undo_method(AudioServer::get_singleton(), "add_bus_effect", index, AudioServer::get_singleton()->get_bus_effect(index, i));
ur->add_undo_method(AudioServer::get_singleton(), "set_bus_effect_enabled", index, i, AudioServer::get_singleton()->is_bus_effect_enabled(index, i));
}
- ur->add_do_method(this, "_update_buses");
- ur->add_undo_method(this, "_update_buses");
ur->commit_action();
}
@@ -1165,8 +1146,6 @@ void EditorAudioBuses::_duplicate_bus(int p_which) {
ur->add_do_method(AudioServer::get_singleton(), "set_bus_effect_enabled", add_at_pos, i, AudioServer::get_singleton()->is_bus_effect_enabled(p_which, i));
}
ur->add_undo_method(AudioServer::get_singleton(), "remove_bus", add_at_pos);
- ur->add_do_method(this, "_update_buses");
- ur->add_undo_method(this, "_update_buses");
ur->commit_action();
}
@@ -1178,8 +1157,8 @@ void EditorAudioBuses::_reset_bus_volume(Object *p_which) {
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));
- ur->add_do_method(this, "_update_buses");
- ur->add_undo_method(this, "_update_buses");
+ ur->add_do_method(this, "_update_bus", index);
+ ur->add_undo_method(this, "_update_bus", index);
ur->commit_action();
}
@@ -1202,8 +1181,6 @@ void EditorAudioBuses::_drop_at_index(int p_bus, int p_index) {
int real_index = p_index > p_bus ? p_index - 1 : p_index;
ur->add_undo_method(AudioServer::get_singleton(), "move_bus", real_index, real_bus);
- ur->add_do_method(this, "_update_buses");
- ur->add_undo_method(this, "_update_buses");
ur->commit_action();
}
@@ -1252,7 +1229,7 @@ void EditorAudioBuses::_load_default_layout() {
edited_path = layout_path;
file->set_text(String(TTR("Layout:")) + " " + layout_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
- _update_buses();
+ _rebuild_buses();
EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
@@ -1268,7 +1245,7 @@ void EditorAudioBuses::_file_dialog_callback(const String &p_string) {
edited_path = p_string;
file->set_text(String(TTR("Layout:")) + " " + p_string.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
- _update_buses();
+ _rebuild_buses();
EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
@@ -1288,15 +1265,13 @@ 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();
+ _rebuild_buses();
EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
}
void EditorAudioBuses::_bind_methods() {
- ClassDB::bind_method("_set_renaming_buses", &EditorAudioBuses::_set_renaming_buses);
- ClassDB::bind_method("_update_buses", &EditorAudioBuses::_update_buses);
ClassDB::bind_method("_update_bus", &EditorAudioBuses::_update_bus);
ClassDB::bind_method("_update_sends", &EditorAudioBuses::_update_sends);
ClassDB::bind_method("_select_layout", &EditorAudioBuses::_select_layout);
@@ -1373,7 +1348,7 @@ EditorAudioBuses::EditorAudioBuses() {
add_child(file_dialog);
file_dialog->connect("file_selected", callable_mp(this, &EditorAudioBuses::_file_dialog_callback));
- AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &EditorAudioBuses::_update_buses));
+ AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &EditorAudioBuses::_rebuild_buses));
set_process(true);
}
@@ -1390,7 +1365,7 @@ void EditorAudioBuses::open_layout(const String &p_path) {
edited_path = p_path;
file->set_text(p_path.get_file());
AudioServer::get_singleton()->set_bus_layout(state);
- _update_buses();
+ _rebuild_buses();
EditorUndoRedoManager::get_singleton()->clear_history(true, EditorUndoRedoManager::GLOBAL_HISTORY);
call_deferred(SNAME("_select_layout"));
}
diff --git a/editor/editor_audio_buses.h b/editor/editor_audio_buses.h
index 51f858dd11..99e3214781 100644
--- a/editor/editor_audio_buses.h
+++ b/editor/editor_audio_buses.h
@@ -172,14 +172,11 @@ class EditorAudioBuses : public VBoxContainer {
Timer *save_timer = nullptr;
String edited_path;
- bool renaming_buses = false;
- void _set_renaming_buses(bool p_renaming);
-
- void _add_bus();
- void _update_buses();
+ void _rebuild_buses();
void _update_bus(int p_index);
void _update_sends();
+ void _add_bus();
void _delete_bus(Object *p_which);
void _duplicate_bus(int p_which);
void _reset_bus_volume(Object *p_which);
diff --git a/editor/editor_autoload_settings.cpp b/editor/editor_autoload_settings.cpp
index 57172142e3..6658669d66 100644
--- a/editor/editor_autoload_settings.cpp
+++ b/editor/editor_autoload_settings.cpp
@@ -425,14 +425,14 @@ Node *EditorAutoloadSettings::_create_autoload(const String &p_path) {
Object *obj = ClassDB::instantiate(ibt);
- ERR_FAIL_COND_V_MSG(!obj, nullptr, vformat("Cannot instance script for Autoload, expected 'Node' inheritance, got: %s.", ibt));
+ ERR_FAIL_NULL_V_MSG(obj, nullptr, vformat("Cannot instance script for Autoload, expected 'Node' inheritance, got: %s.", ibt));
n = Object::cast_to<Node>(obj);
n->set_script(scr);
}
}
- ERR_FAIL_COND_V_MSG(!n, nullptr, vformat("Path in Autoload not a node or script: %s.", p_path));
+ ERR_FAIL_NULL_V_MSG(n, nullptr, vformat("Path in Autoload not a node or script: %s.", p_path));
return n;
}
@@ -882,7 +882,7 @@ EditorAutoloadSettings::EditorAutoloadSettings() {
error_message = memnew(Label);
error_message->hide();
error_message->set_horizontal_alignment(HORIZONTAL_ALIGNMENT_RIGHT);
- error_message->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
+ error_message->add_theme_color_override("font_color", EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor)));
add_child(error_message);
Label *l = memnew(Label);
diff --git a/editor/editor_command_palette.cpp b/editor/editor_command_palette.cpp
index 168fe5a7ac..18a251a306 100644
--- a/editor/editor_command_palette.cpp
+++ b/editor/editor_command_palette.cpp
@@ -357,3 +357,13 @@ Ref<Shortcut> ED_SHORTCUT_AND_COMMAND(const String &p_path, const String &p_name
EditorCommandPalette::get_singleton()->add_shortcut_command(p_command_name, p_path, shortcut);
return shortcut;
}
+
+Ref<Shortcut> ED_SHORTCUT_ARRAY_AND_COMMAND(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes, String p_command_name) {
+ if (p_command_name.is_empty()) {
+ p_command_name = p_name;
+ }
+
+ Ref<Shortcut> shortcut = ED_SHORTCUT_ARRAY(p_path, p_name, p_keycodes);
+ EditorCommandPalette::get_singleton()->add_shortcut_command(p_command_name, p_path, shortcut);
+ return shortcut;
+}
diff --git a/editor/editor_command_palette.h b/editor/editor_command_palette.h
index 7eb9ff7404..b34c4ddf97 100644
--- a/editor/editor_command_palette.h
+++ b/editor/editor_command_palette.h
@@ -105,5 +105,6 @@ public:
};
Ref<Shortcut> ED_SHORTCUT_AND_COMMAND(const String &p_path, const String &p_name, Key p_keycode = Key::NONE, String p_command = "");
+Ref<Shortcut> ED_SHORTCUT_ARRAY_AND_COMMAND(const String &p_path, const String &p_name, const PackedInt32Array &p_keycodes, String p_command = "");
#endif // EDITOR_COMMAND_PALETTE_H
diff --git a/editor/editor_data.cpp b/editor/editor_data.cpp
index d8749aa290..e4f198a529 100644
--- a/editor/editor_data.cpp
+++ b/editor/editor_data.cpp
@@ -106,7 +106,7 @@ void EditorSelectionHistory::cleanup_history() {
void EditorSelectionHistory::add_object(ObjectID p_object, const String &p_property, bool p_inspector_only) {
Object *obj = ObjectDB::get_instance(p_object);
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
RefCounted *r = Object::cast_to<RefCounted>(obj);
_Object o;
if (r) {
@@ -700,7 +700,7 @@ bool EditorData::check_and_update_scene(int p_idx) {
ERR_FAIL_COND_V(err != OK, false);
ep.step(TTR("Updating scene..."), 1);
Node *new_scene = pscene->instantiate(PackedScene::GEN_EDIT_STATE_MAIN);
- ERR_FAIL_COND_V(!new_scene, false);
+ ERR_FAIL_NULL_V(new_scene, false);
// Transfer selection.
List<Node *> new_selection;
diff --git a/editor/editor_inspector.cpp b/editor/editor_inspector.cpp
index 3aba59246f..3fa3768d4b 100644
--- a/editor/editor_inspector.cpp
+++ b/editor/editor_inspector.cpp
@@ -1897,7 +1897,7 @@ void EditorInspectorArray::_move_element(int p_element_index, int p_to_pos) {
void EditorInspectorArray::_clear_array() {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(vformat(TTR("Clear property array with prefix %s."), array_element_prefix));
+ undo_redo->create_action(vformat(TTR("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.
@@ -1950,7 +1950,7 @@ void EditorInspectorArray::_resize_array(int p_size) {
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(vformat(TTR("Resize property array with prefix %s."), array_element_prefix));
+ undo_redo->create_action(vformat(TTR("Resize Property Array with Prefix %s"), array_element_prefix));
if (p_size > count) {
if (mode == MODE_USE_MOVE_ARRAY_ELEMENT_FUNCTION) {
for (int i = count; i < p_size; i++) {
@@ -3856,7 +3856,8 @@ void EditorInspector::_multiple_properties_changed(Vector<String> p_paths, Array
names += p_paths[i];
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Set Multiple:") + " " + names, UndoRedo::MERGE_ENDS);
+ // TRANSLATORS: This is describing a change to multiple properties at once. The parameter is a list of property names.
+ undo_redo->create_action(vformat(TTR("Set Multiple: %s"), names), UndoRedo::MERGE_ENDS);
for (int i = 0; i < p_paths.size(); i++) {
_edit_set(p_paths[i], p_values[i], false, "");
if (restart_request_props.has(p_paths[i])) {
@@ -3954,7 +3955,7 @@ void EditorInspector::_property_pinned(const String &p_path, bool p_pinned) {
}
Node *node = Object::cast_to<Node>(object);
- ERR_FAIL_COND(!node);
+ ERR_FAIL_NULL(node);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(vformat(p_pinned ? TTR("Pinned %s") : TTR("Unpinned %s"), p_path));
diff --git a/editor/editor_interface.cpp b/editor/editor_interface.cpp
index 94040d4ca0..cb8f910074 100644
--- a/editor/editor_interface.cpp
+++ b/editor/editor_interface.cpp
@@ -45,6 +45,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/control.h"
#include "scene/main/window.h"
+#include "scene/resources/theme.h"
EditorInterface *EditorInterface::singleton = nullptr;
@@ -196,6 +197,10 @@ bool EditorInterface::is_plugin_enabled(const String &p_plugin) const {
// Editor GUI.
+Ref<Theme> EditorInterface::get_editor_theme() const {
+ return EditorNode::get_singleton()->get_editor_theme();
+}
+
Control *EditorInterface::get_base_control() const {
return EditorNode::get_singleton()->get_gui_base();
}
@@ -405,6 +410,7 @@ void EditorInterface::_bind_methods() {
// Editor GUI.
+ ClassDB::bind_method(D_METHOD("get_editor_theme"), &EditorInterface::get_editor_theme);
ClassDB::bind_method(D_METHOD("get_base_control"), &EditorInterface::get_base_control);
ClassDB::bind_method(D_METHOD("get_editor_main_screen"), &EditorInterface::get_editor_main_screen);
ClassDB::bind_method(D_METHOD("get_script_editor"), &EditorInterface::get_script_editor);
@@ -474,7 +480,7 @@ void EditorInterface::create() {
}
void EditorInterface::free() {
- ERR_FAIL_COND(singleton == nullptr);
+ ERR_FAIL_NULL(singleton);
memdelete(singleton);
}
diff --git a/editor/editor_interface.h b/editor/editor_interface.h
index 2ac1336202..932b18070c 100644
--- a/editor/editor_interface.h
+++ b/editor/editor_interface.h
@@ -50,6 +50,7 @@ class Mesh;
class Node;
class ScriptEditor;
class Texture2D;
+class Theme;
class VBoxContainer;
class Window;
@@ -84,11 +85,10 @@ public:
void set_plugin_enabled(const String &p_plugin, bool p_enabled);
bool is_plugin_enabled(const String &p_plugin) const;
- void add_editor_plugin(EditorPlugin *p_plugin);
- void remove_editor_plugin(EditorPlugin *p_plugin);
-
// Editor GUI.
+ Ref<Theme> get_editor_theme() const;
+
Control *get_base_control() const;
VBoxContainer *get_editor_main_screen() const;
ScriptEditor *get_script_editor() const;
diff --git a/editor/editor_node.cpp b/editor/editor_node.cpp
index 6dc8d4e152..223e50f557 100644
--- a/editor/editor_node.cpp
+++ b/editor/editor_node.cpp
@@ -493,7 +493,6 @@ void EditorNode::_update_theme(bool p_skip_creation) {
scene_root_parent->add_theme_style_override("panel", theme->get_stylebox(SNAME("Content"), EditorStringName(EditorStyles)));
bottom_panel->add_theme_style_override("panel", theme->get_stylebox(SNAME("BottomPanel"), EditorStringName(EditorStyles)));
main_menu->add_theme_style_override("hover", theme->get_stylebox(SNAME("MenuHover"), EditorStringName(EditorStyles)));
- prev_scene->set_icon(theme->get_icon(SNAME("PrevScene"), EditorStringName(EditorIcons)));
distraction_free->set_icon(theme->get_icon(SNAME("DistractionFree"), EditorStringName(EditorIcons)));
bottom_panel_raise->set_icon(theme->get_icon(SNAME("ExpandBottomDock"), EditorStringName(EditorIcons)));
@@ -2004,7 +2003,7 @@ void EditorNode::_dialog_action(String p_file) {
saving_resource = Ref<Resource>();
ObjectID current_id = editor_history.get_current();
Object *current_obj = current_id.is_valid() ? ObjectDB::get_instance(current_id) : nullptr;
- ERR_FAIL_COND(!current_obj);
+ ERR_FAIL_NULL(current_obj);
current_obj->notify_property_list_changed();
} break;
case SETTINGS_LAYOUT_SAVE: {
@@ -2282,7 +2281,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
if (is_resource) {
Resource *current_res = Object::cast_to<Resource>(current_obj);
- ERR_FAIL_COND(!current_res);
+ ERR_FAIL_NULL(current_res);
InspectorDock::get_inspector_singleton()->edit(current_res);
SceneTreeDock::get_singleton()->set_selected(nullptr);
@@ -2316,7 +2315,7 @@ void EditorNode::_edit_current(bool p_skip_foreign) {
}
} else if (is_node) {
Node *current_node = Object::cast_to<Node>(current_obj);
- ERR_FAIL_COND(!current_node);
+ ERR_FAIL_NULL(current_node);
InspectorDock::get_inspector_singleton()->edit(current_node);
if (current_node->is_inside_tree()) {
@@ -2951,9 +2950,9 @@ void EditorNode::_screenshot(bool p_use_utc) {
void EditorNode::_save_screenshot(NodePath p_path) {
Control *editor_main_screen = EditorInterface::get_singleton()->get_editor_main_screen();
- ERR_FAIL_COND_MSG(!editor_main_screen, "Cannot get the editor main screen control.");
+ ERR_FAIL_NULL_MSG(editor_main_screen, "Cannot get the editor main screen control.");
Viewport *viewport = editor_main_screen->get_viewport();
- ERR_FAIL_COND_MSG(!viewport, "Cannot get a viewport from the editor main screen.");
+ ERR_FAIL_NULL_MSG(viewport, "Cannot get a viewport from the editor main screen.");
Ref<ViewportTexture> texture = viewport->get_texture();
ERR_FAIL_COND_MSG(texture.is_null(), "Cannot get a viewport texture from the editor main screen.");
Ref<Image> img = texture->get_image();
@@ -3137,7 +3136,7 @@ void EditorNode::editor_select(int p_which) {
selecting = false;
EditorPlugin *new_editor = editor_table[p_which];
- ERR_FAIL_COND(!new_editor);
+ ERR_FAIL_NULL(new_editor);
if (editor_plugin_screen == new_editor) {
return;
@@ -3782,7 +3781,6 @@ Error EditorNode::load_scene(const String &p_scene, bool p_ignore_broken_deps, b
editor_folding.save_scene_folding(new_scene, lpath);
}
- prev_scene->set_disabled(previous_scenes.size() == 0);
opening_prev = false;
EditorDebuggerNode::get_singleton()->update_live_edit_root();
@@ -4171,7 +4169,7 @@ void EditorNode::stop_child_process(OS::ProcessID p_pid) {
}
Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) const {
- ERR_FAIL_COND_V(!p_object, nullptr);
+ ERR_FAIL_NULL_V(p_object, nullptr);
Ref<Script> scr = p_object->get_script();
@@ -4203,7 +4201,7 @@ Ref<Script> EditorNode::get_object_custom_type_base(const Object *p_object) cons
}
StringName EditorNode::get_object_custom_type_name(const Object *p_object) const {
- ERR_FAIL_COND_V(!p_object, StringName());
+ ERR_FAIL_NULL_V(p_object, StringName());
Ref<Script> scr = p_object->get_script();
if (scr.is_null() && Object::cast_to<Script>(p_object)) {
@@ -4343,7 +4341,7 @@ Ref<Texture2D> EditorNode::get_class_icon(const String &p_class, const String &p
}
bool EditorNode::is_object_of_custom_type(const Object *p_object, const StringName &p_class) {
- ERR_FAIL_COND_V(!p_object, false);
+ ERR_FAIL_NULL_V(p_object, false);
Ref<Script> scr = p_object->get_script();
if (scr.is_null() && Object::cast_to<Script>(p_object)) {
@@ -4633,7 +4631,7 @@ void EditorNode::_dock_make_selected_float() {
}
void EditorNode::_dock_make_float(Control *p_dock, int p_slot_index, bool p_show_window) {
- ERR_FAIL_COND(!p_dock);
+ ERR_FAIL_NULL(p_dock);
Size2 borders = Size2(4, 4) * EDSCALE;
// Remember size and position before removing it from the main window.
@@ -5812,7 +5810,7 @@ void EditorNode::remove_control_from_dock(Control *p_control) {
}
}
- ERR_FAIL_COND_MSG(!dock, "Control was not in dock.");
+ ERR_FAIL_NULL_MSG(dock, "Control was not in dock.");
dock->remove_child(p_control);
_update_dock_slots_visibility();
@@ -6209,7 +6207,7 @@ void EditorNode::reload_instances_with_path_in_edited_scenes(const String &p_ins
instantiated_node = current_packed_scene->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE);
}
- ERR_FAIL_COND(!instantiated_node);
+ ERR_FAIL_NULL(instantiated_node);
bool original_node_is_displayed_folded = original_node->is_displayed_folded();
bool original_node_scene_instance_load_placeholder = original_node->get_scene_instance_load_placeholder();
@@ -7153,15 +7151,6 @@ EditorNode::EditorNode() {
main_menu->add_child(file_menu);
main_menu->set_menu_tooltip(0, TTR("Operations with scene files."));
- prev_scene = memnew(Button);
- prev_scene->set_flat(true);
- prev_scene->set_tooltip_text(TTR("Go to previously opened scene."));
- prev_scene->set_disabled(true);
- prev_scene->connect("pressed", callable_mp(this, &EditorNode::_menu_option).bind(FILE_OPEN_PREV));
- gui_base->add_child(prev_scene);
- prev_scene->set_position(Point2(3, 24));
- prev_scene->hide();
-
accept = memnew(AcceptDialog);
accept->set_unparent_when_invisible(true);
@@ -7237,8 +7226,8 @@ EditorNode::EditorNode() {
file_menu->add_separator();
- file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN);
- ED_SHORTCUT_OVERRIDE("editor/quick_open", "macos", KeyModifierMask::META + KeyModifierMask::CTRL + Key::O);
+ file_menu->add_shortcut(ED_SHORTCUT_ARRAY_AND_COMMAND("editor/quick_open", TTR("Quick Open..."), { int32_t(KeyModifierMask::SHIFT + KeyModifierMask::ALT + Key::O), int32_t(KeyModifierMask::CMD_OR_CTRL + Key::P) }), FILE_QUICK_OPEN);
+ ED_SHORTCUT_OVERRIDE_ARRAY("editor/quick_open", "macos", { int32_t(KeyModifierMask::META + KeyModifierMask::CTRL + Key::O), int32_t(KeyModifierMask::CMD_OR_CTRL + Key::P) });
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_scene", TTR("Quick Open Scene..."), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::SHIFT + Key::O), FILE_QUICK_OPEN_SCENE);
file_menu->add_shortcut(ED_SHORTCUT_AND_COMMAND("editor/quick_open_script", TTR("Quick Open Script..."), KeyModifierMask::CMD_OR_CTRL + KeyModifierMask::ALT + Key::O), FILE_QUICK_OPEN_SCRIPT);
diff --git a/editor/editor_node.h b/editor/editor_node.h
index a83570b2ea..5ecb3186e1 100644
--- a/editor/editor_node.h
+++ b/editor/editor_node.h
@@ -348,7 +348,6 @@ private:
PopupMenu *tool_menu = nullptr;
PopupMenu *export_as_menu = nullptr;
Button *export_button = nullptr;
- Button *prev_scene = nullptr;
Button *search_button = nullptr;
TextureProgressBar *audio_vu = nullptr;
diff --git a/editor/editor_paths.cpp b/editor/editor_paths.cpp
index 610f66cff9..801c81efa8 100644
--- a/editor/editor_paths.cpp
+++ b/editor/editor_paths.cpp
@@ -95,7 +95,7 @@ void EditorPaths::create() {
}
void EditorPaths::free() {
- ERR_FAIL_COND(singleton == nullptr);
+ ERR_FAIL_NULL(singleton);
memdelete(singleton);
}
diff --git a/editor/editor_plugin_settings.cpp b/editor/editor_plugin_settings.cpp
index 167a151419..ef8730cabf 100644
--- a/editor/editor_plugin_settings.cpp
+++ b/editor/editor_plugin_settings.cpp
@@ -137,7 +137,7 @@ void EditorPluginSettings::_plugin_activity_changed() {
}
TreeItem *ti = plugin_list->get_edited();
- ERR_FAIL_COND(!ti);
+ ERR_FAIL_NULL(ti);
bool active = ti->is_checked(3);
String name = ti->get_metadata(0);
diff --git a/editor/editor_properties.cpp b/editor/editor_properties.cpp
index 2a82b2cde4..7a6cae7248 100644
--- a/editor/editor_properties.cpp
+++ b/editor/editor_properties.cpp
@@ -2786,7 +2786,7 @@ void EditorPropertyNodePath::_node_selected(const NodePath &p_path) {
if (!base_node && Object::cast_to<RefCounted>(get_edited_object())) {
Node *to_node = get_node(p_path);
- ERR_FAIL_COND(!to_node);
+ ERR_FAIL_NULL(to_node);
path = get_tree()->get_edited_scene_root()->get_path_to(to_node);
}
@@ -2899,7 +2899,7 @@ void EditorPropertyNodePath::update_property() {
}
Node *target_node = base_node->get_node(p);
- ERR_FAIL_COND(!target_node);
+ ERR_FAIL_NULL(target_node);
if (String(target_node->get_name()).contains("@")) {
assign->set_icon(Ref<Texture2D>());
diff --git a/editor/editor_properties_array_dict.cpp b/editor/editor_properties_array_dict.cpp
index 61c6c0bcdb..950a1e1c4d 100644
--- a/editor/editor_properties_array_dict.cpp
+++ b/editor/editor_properties_array_dict.cpp
@@ -1111,7 +1111,7 @@ void EditorPropertyDictionary::update_property() {
}
}
- ERR_FAIL_COND(!prop);
+ ERR_FAIL_NULL(prop);
prop->set_read_only(is_read_only());
diff --git a/editor/editor_settings.cpp b/editor/editor_settings.cpp
index e042d8570f..2c93cc68b0 100644
--- a/editor/editor_settings.cpp
+++ b/editor/editor_settings.cpp
@@ -528,10 +528,10 @@ void EditorSettings::_load_defaults(Ref<ConfigFile> p_extra_config) {
// FileSystem
EDITOR_SETTING(Variant::INT, PROPERTY_HINT_RANGE, "docks/filesystem/thumbnail_size", 64, "32,128,16")
_initial_set("docks/filesystem/always_show_folders", true);
- _initial_set("docks/filesystem/textfile_extensions", "txt,md,cfg,ini,log,json,yml,yaml,toml");
+ _initial_set("docks/filesystem/textfile_extensions", "txt,md,cfg,ini,log,json,yml,yaml,toml,xml");
// Property editor
- _initial_set("docks/property_editor/auto_refresh_interval", 0.2); //update 5 times per second by default
+ EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "docks/property_editor/auto_refresh_interval", 0.2, "0.01,1,0.001"); // Update 5 times per second by default.
EDITOR_SETTING(Variant::FLOAT, PROPERTY_HINT_RANGE, "docks/property_editor/subresource_hue_tint", 0.75, "0,1,0.01")
/* Text editor */
@@ -848,6 +848,7 @@ void EditorSettings::_load_godot2_text_editor_theme() {
_initial_set("text_editor/theme/highlighting/breakpoint_color", Color(0.9, 0.29, 0.3));
_initial_set("text_editor/theme/highlighting/executing_line_color", Color(0.98, 0.89, 0.27));
_initial_set("text_editor/theme/highlighting/code_folding_color", Color(0.8, 0.8, 0.8, 0.8));
+ _initial_set("text_editor/theme/highlighting/folded_code_region_color", Color(0.68, 0.46, 0.77, 0.2));
_initial_set("text_editor/theme/highlighting/search_result_color", Color(0.05, 0.25, 0.05, 1));
_initial_set("text_editor/theme/highlighting/search_result_border_color", Color(0.41, 0.61, 0.91, 0.38));
}
diff --git a/editor/editor_settings_dialog.cpp b/editor/editor_settings_dialog.cpp
index 85b59663c3..a5e70c5b6c 100644
--- a/editor/editor_settings_dialog.cpp
+++ b/editor/editor_settings_dialog.cpp
@@ -234,7 +234,7 @@ void EditorSettingsDialog::_update_builtin_action(const String &p_name, const Ar
Array old_input_array = EditorSettings::get_singleton()->get_builtin_action_overrides(p_name);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Edit Built-in Action") + " '" + p_name + "'");
+ undo_redo->create_action(vformat(TTR("Edit Built-in Action: %s"), 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");
undo_redo->add_do_method(EditorSettings::get_singleton(), "set_builtin_action_override", p_name, p_events);
@@ -250,7 +250,7 @@ void EditorSettingsDialog::_update_shortcut_events(const String &p_path, const A
Ref<Shortcut> current_sc = EditorSettings::get_singleton()->get_shortcut(p_path);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Edit Shortcut") + " '" + p_path + "'");
+ undo_redo->create_action(vformat(TTR("Edit Shortcut: %s"), 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());
undo_redo->add_do_method(EditorSettings::get_singleton(), "mark_setting_changed", "shortcuts");
@@ -500,7 +500,7 @@ void EditorSettingsDialog::_shortcut_button_pressed(Object *p_item, int p_column
return;
}
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
- ERR_FAIL_COND_MSG(!ti, "Object passed is not a TreeItem");
+ ERR_FAIL_NULL_MSG(ti, "Object passed is not a TreeItem.");
ShortcutButton button_idx = (ShortcutButton)p_idx;
diff --git a/editor/editor_themes.cpp b/editor/editor_themes.cpp
index 311e532e63..98f0f70101 100644
--- a/editor/editor_themes.cpp
+++ b/editor/editor_themes.cpp
@@ -41,6 +41,7 @@
#include "scene/resources/style_box_flat.h"
#include "scene/resources/style_box_line.h"
#include "scene/resources/style_box_texture.h"
+#include "scene/theme/theme_db.h"
#include "modules/modules_enabled.gen.h" // For svg.
#ifdef MODULE_SVG_ENABLED
@@ -208,10 +209,109 @@ void EditorColorMap::create() {
add_conversion_exception("GuiSpace");
add_conversion_exception("CodeFoldedRightArrow");
add_conversion_exception("CodeFoldDownArrow");
+ add_conversion_exception("CodeRegionFoldedRightArrow");
+ add_conversion_exception("CodeRegionFoldDownArrow");
add_conversion_exception("TextEditorPlay");
add_conversion_exception("Breakpoint");
}
+Vector<StringName> EditorTheme::editor_theme_types;
+
+// TODO: Refactor these and corresponding Theme methods to use the bool get_xxx(r_value) pattern internally.
+
+// Keep in sync with Theme::get_color.
+Color EditorTheme::get_color(const StringName &p_name, const StringName &p_theme_type) const {
+ if (color_map.has(p_theme_type) && color_map[p_theme_type].has(p_name)) {
+ return color_map[p_theme_type][p_name];
+ } else {
+ if (editor_theme_types.has(p_theme_type)) {
+ WARN_PRINT(vformat("Trying to access a non-existing editor theme color '%s' in '%s'.", p_name, p_theme_type));
+ }
+ return Color();
+ }
+}
+
+// Keep in sync with Theme::get_constant.
+int EditorTheme::get_constant(const StringName &p_name, const StringName &p_theme_type) const {
+ if (constant_map.has(p_theme_type) && constant_map[p_theme_type].has(p_name)) {
+ return constant_map[p_theme_type][p_name];
+ } else {
+ if (editor_theme_types.has(p_theme_type)) {
+ WARN_PRINT(vformat("Trying to access a non-existing editor theme constant '%s' in '%s'.", p_name, p_theme_type));
+ }
+ return 0;
+ }
+}
+
+// Keep in sync with Theme::get_font.
+Ref<Font> EditorTheme::get_font(const StringName &p_name, const StringName &p_theme_type) const {
+ if (font_map.has(p_theme_type) && font_map[p_theme_type].has(p_name) && font_map[p_theme_type][p_name].is_valid()) {
+ return font_map[p_theme_type][p_name];
+ } else if (has_default_font()) {
+ if (editor_theme_types.has(p_theme_type)) {
+ WARN_PRINT(vformat("Trying to access a non-existing editor theme font '%s' in '%s'.", p_name, p_theme_type));
+ }
+ return default_font;
+ } else {
+ if (editor_theme_types.has(p_theme_type)) {
+ WARN_PRINT(vformat("Trying to access a non-existing editor theme font '%s' in '%s'.", p_name, p_theme_type));
+ }
+ return ThemeDB::get_singleton()->get_fallback_font();
+ }
+}
+
+// Keep in sync with Theme::get_font_size.
+int EditorTheme::get_font_size(const StringName &p_name, const StringName &p_theme_type) const {
+ if (font_size_map.has(p_theme_type) && font_size_map[p_theme_type].has(p_name) && (font_size_map[p_theme_type][p_name] > 0)) {
+ return font_size_map[p_theme_type][p_name];
+ } else if (has_default_font_size()) {
+ if (editor_theme_types.has(p_theme_type)) {
+ WARN_PRINT(vformat("Trying to access a non-existing editor theme font size '%s' in '%s'.", p_name, p_theme_type));
+ }
+ return default_font_size;
+ } else {
+ if (editor_theme_types.has(p_theme_type)) {
+ WARN_PRINT(vformat("Trying to access a non-existing editor theme font size '%s' in '%s'.", p_name, p_theme_type));
+ }
+ return ThemeDB::get_singleton()->get_fallback_font_size();
+ }
+}
+
+// Keep in sync with Theme::get_icon.
+Ref<Texture2D> EditorTheme::get_icon(const StringName &p_name, const StringName &p_theme_type) const {
+ if (icon_map.has(p_theme_type) && icon_map[p_theme_type].has(p_name) && icon_map[p_theme_type][p_name].is_valid()) {
+ return icon_map[p_theme_type][p_name];
+ } else {
+ if (editor_theme_types.has(p_theme_type)) {
+ WARN_PRINT(vformat("Trying to access a non-existing editor theme icon '%s' in '%s'.", p_name, p_theme_type));
+ }
+ return ThemeDB::get_singleton()->get_fallback_icon();
+ }
+}
+
+// Keep in sync with Theme::get_stylebox.
+Ref<StyleBox> EditorTheme::get_stylebox(const StringName &p_name, const StringName &p_theme_type) const {
+ if (style_map.has(p_theme_type) && style_map[p_theme_type].has(p_name) && style_map[p_theme_type][p_name].is_valid()) {
+ return style_map[p_theme_type][p_name];
+ } else {
+ if (editor_theme_types.has(p_theme_type)) {
+ WARN_PRINT(vformat("Trying to access a non-existing editor theme stylebox '%s' in '%s'.", p_name, p_theme_type));
+ }
+ return ThemeDB::get_singleton()->get_fallback_stylebox();
+ }
+}
+
+EditorTheme::EditorTheme() {
+ if (editor_theme_types.is_empty()) {
+ editor_theme_types.append(EditorStringName(Editor));
+ editor_theme_types.append(EditorStringName(EditorFonts));
+ editor_theme_types.append(EditorStringName(EditorIcons));
+ editor_theme_types.append(EditorStringName(EditorStyles));
+ }
+}
+
+// Editor theme generatior.
+
static Ref<StyleBoxTexture> make_stylebox(Ref<Texture2D> p_texture, float p_left, float p_top, float p_right, float p_bottom, float p_margin_left = -1, float p_margin_top = -1, float p_margin_right = -1, float p_margin_bottom = -1, bool p_draw_center = true) {
Ref<StyleBoxTexture> style(memnew(StyleBoxTexture));
style->set_texture(p_texture);
@@ -428,7 +528,7 @@ void editor_register_and_generate_icons(Ref<Theme> p_theme, bool p_dark_theme, f
Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
OS::get_singleton()->benchmark_begin_measure("create_editor_theme");
- Ref<Theme> theme = Ref<Theme>(memnew(Theme));
+ Ref<EditorTheme> theme = memnew(EditorTheme);
// Controls may rely on the scale for their internal drawing logic.
theme->set_default_base_scale(EDSCALE);
@@ -844,13 +944,12 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
// even though it may not be immediately obvious at first.
Ref<StyleBoxFlat> toolbar_stylebox = memnew(StyleBoxFlat);
toolbar_stylebox->set_bg_color(accent_color * Color(1, 1, 1, 0.1));
- toolbar_stylebox->set_corner_radius(CORNER_TOP_LEFT, corner_radius * EDSCALE);
- toolbar_stylebox->set_corner_radius(CORNER_TOP_RIGHT, corner_radius * EDSCALE);
toolbar_stylebox->set_anti_aliased(false);
// Add an underline to the StyleBox, but prevent its minimum vertical size from changing.
toolbar_stylebox->set_border_color(accent_color);
toolbar_stylebox->set_border_width(SIDE_BOTTOM, Math::round(2 * EDSCALE));
toolbar_stylebox->set_content_margin(SIDE_BOTTOM, 0);
+ toolbar_stylebox->set_expand_margin_all(2 * EDSCALE);
theme->set_stylebox("ContextualToolbar", EditorStringName(EditorStyles), toolbar_stylebox);
// Script Editor
@@ -2088,6 +2187,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
const Color breakpoint_color = dark_theme ? error_color : Color(1, 0.27, 0.2, 1);
const Color executing_line_color = Color(0.98, 0.89, 0.27);
const Color code_folding_color = alpha3;
+ const Color folded_code_region_color = Color(0.68, 0.46, 0.77, 0.2);
const Color search_result_color = alpha1;
const Color search_result_border_color = dark_theme ? Color(0.41, 0.61, 0.91, 0.38) : Color(0, 0.4, 1, 0.38);
@@ -2128,6 +2228,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
setting->set_initial_value("text_editor/theme/highlighting/breakpoint_color", breakpoint_color, true);
setting->set_initial_value("text_editor/theme/highlighting/executing_line_color", executing_line_color, true);
setting->set_initial_value("text_editor/theme/highlighting/code_folding_color", code_folding_color, true);
+ setting->set_initial_value("text_editor/theme/highlighting/folded_code_region_color", folded_code_region_color, true);
setting->set_initial_value("text_editor/theme/highlighting/search_result_color", search_result_color, true);
setting->set_initial_value("text_editor/theme/highlighting/search_result_border_color", search_result_border_color, true);
} else if (text_editor_color_theme == "Godot 2") {
@@ -2147,6 +2248,8 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_icon("space", "CodeEdit", theme->get_icon(SNAME("GuiSpace"), EditorStringName(EditorIcons)));
theme->set_icon("folded", "CodeEdit", theme->get_icon(SNAME("CodeFoldedRightArrow"), EditorStringName(EditorIcons)));
theme->set_icon("can_fold", "CodeEdit", theme->get_icon(SNAME("CodeFoldDownArrow"), EditorStringName(EditorIcons)));
+ theme->set_icon("folded_code_region", "CodeEdit", theme->get_icon(SNAME("CodeRegionFoldedRightArrow"), EditorStringName(EditorIcons)));
+ theme->set_icon("can_fold_code_region", "CodeEdit", theme->get_icon(SNAME("CodeRegionFoldDownArrow"), EditorStringName(EditorIcons)));
theme->set_icon("executing_line", "CodeEdit", theme->get_icon(SNAME("TextEditorPlay"), EditorStringName(EditorIcons)));
theme->set_icon("breakpoint", "CodeEdit", theme->get_icon(SNAME("Breakpoint"), EditorStringName(EditorIcons)));
@@ -2172,6 +2275,7 @@ Ref<Theme> create_editor_theme(const Ref<Theme> p_theme) {
theme->set_color("breakpoint_color", "CodeEdit", EDITOR_GET("text_editor/theme/highlighting/breakpoint_color"));
theme->set_color("executing_line_color", "CodeEdit", EDITOR_GET("text_editor/theme/highlighting/executing_line_color"));
theme->set_color("code_folding_color", "CodeEdit", EDITOR_GET("text_editor/theme/highlighting/code_folding_color"));
+ theme->set_color("folded_code_region_color", "CodeEdit", EDITOR_GET("text_editor/theme/highlighting/folded_code_region_color"));
theme->set_color("search_result_color", "CodeEdit", EDITOR_GET("text_editor/theme/highlighting/search_result_color"));
theme->set_color("search_result_border_color", "CodeEdit", EDITOR_GET("text_editor/theme/highlighting/search_result_border_color"));
diff --git a/editor/editor_themes.h b/editor/editor_themes.h
index 5949c17201..7ca0050103 100644
--- a/editor/editor_themes.h
+++ b/editor/editor_themes.h
@@ -53,6 +53,22 @@ public:
static HashSet<StringName> &get_color_conversion_exceptions() { return color_conversion_exceptions; };
};
+class EditorTheme : public Theme {
+ GDCLASS(EditorTheme, Theme);
+
+ static Vector<StringName> editor_theme_types;
+
+public:
+ virtual Color get_color(const StringName &p_name, const StringName &p_theme_type) const override;
+ virtual int get_constant(const StringName &p_name, const StringName &p_theme_type) const override;
+ virtual Ref<Font> get_font(const StringName &p_name, const StringName &p_theme_type) const override;
+ virtual int get_font_size(const StringName &p_name, const StringName &p_theme_type) const override;
+ virtual Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_theme_type) const override;
+ virtual Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_theme_type) const override;
+
+ EditorTheme();
+};
+
Ref<Theme> create_editor_theme(Ref<Theme> p_theme = nullptr);
Ref<Theme> create_custom_theme(Ref<Theme> p_theme = nullptr);
diff --git a/editor/export/editor_export_platform.cpp b/editor/export/editor_export_platform.cpp
index d65f10c441..b3fefaafc6 100644
--- a/editor/export/editor_export_platform.cpp
+++ b/editor/export/editor_export_platform.cpp
@@ -73,12 +73,12 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
p_log->add_text(" - ");
if (p_err == OK) {
if (get_worst_message_type() >= EditorExportPlatform::EXPORT_MESSAGE_WARNING) {
- p_log->add_image(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusWarning")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_CENTER);
+ p_log->add_image(p_log->get_editor_theme_icon(SNAME("StatusWarning")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_CENTER);
p_log->add_text(" ");
p_log->add_text(TTR("Completed with warnings."));
has_messages = true;
} else {
- p_log->add_image(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusSuccess")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_CENTER);
+ p_log->add_image(p_log->get_editor_theme_icon(SNAME("StatusSuccess")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_CENTER);
p_log->add_text(" ");
p_log->add_text(TTR("Completed successfully."));
if (msg_count > 0) {
@@ -86,7 +86,7 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
}
}
} else {
- p_log->add_image(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusError")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_CENTER);
+ p_log->add_image(p_log->get_editor_theme_icon(SNAME("StatusError")), 16 * EDSCALE, 16 * EDSCALE, Color(1.0, 1.0, 1.0), INLINE_ALIGNMENT_CENTER);
p_log->add_text(" ");
p_log->add_text(TTR("Failed."));
has_messages = true;
@@ -99,20 +99,20 @@ bool EditorExportPlatform::fill_log_messages(RichTextLabel *p_log, Error p_err)
p_log->set_table_column_expand(1, true);
for (int m = 0; m < msg_count; m++) {
EditorExportPlatform::ExportMessage msg = get_message(m);
- Color color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label"));
+ Color color = p_log->get_theme_color(SNAME("font_color"), SNAME("Label"));
Ref<Texture> icon;
switch (msg.msg_type) {
case EditorExportPlatform::EXPORT_MESSAGE_INFO: {
- color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.6);
+ color = p_log->get_theme_color(SNAME("font_color"), EditorStringName(Editor)) * Color(1, 1, 1, 0.6);
} break;
case EditorExportPlatform::EXPORT_MESSAGE_WARNING: {
- icon = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Warning"));
- color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
+ icon = p_log->get_editor_theme_icon(SNAME("Warning"));
+ color = p_log->get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
} break;
case EditorExportPlatform::EXPORT_MESSAGE_ERROR: {
- icon = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Error"));
- color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor));
+ icon = p_log->get_editor_theme_icon(SNAME("Error"));
+ color = p_log->get_theme_color(SNAME("error_color"), EditorStringName(Editor));
} break;
default:
break;
@@ -756,7 +756,7 @@ String EditorExportPlatform::_export_customize(const String &p_path, LocalVector
Ref<PackedScene> ps = ResourceLoader::load(p_path, "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE);
ERR_FAIL_COND_V(ps.is_null(), p_path);
Node *node = ps->instantiate(PackedScene::GEN_EDIT_STATE_INSTANCE); // Make sure the child scene root gets the correct inheritance chain.
- ERR_FAIL_COND_V(node == nullptr, p_path);
+ ERR_FAIL_NULL_V(node, p_path);
if (!customize_scenes_plugins.is_empty()) {
for (Ref<EditorExportPlugin> &plugin : customize_scenes_plugins) {
Node *customized = plugin->_customize_scene(node, p_path);
diff --git a/editor/export/project_export.cpp b/editor/export/project_export.cpp
index 24a9e2ae36..58e4dc1069 100644
--- a/editor/export/project_export.cpp
+++ b/editor/export/project_export.cpp
@@ -1328,7 +1328,7 @@ ProjectExportDialog::ProjectExportDialog() {
script_key->connect("text_changed", callable_mp(this, &ProjectExportDialog::_script_encryption_key_changed));
script_key_error = memnew(Label);
script_key_error->set_text(String::utf8("• ") + TTR("Invalid Encryption Key (must be 64 hexadecimal characters long)"));
- script_key_error->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
+ script_key_error->add_theme_color_override("font_color", EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor)));
sec_vb->add_margin_child(TTR("Encryption Key (256-bits as hexadecimal):"), script_key);
sec_vb->add_child(script_key_error);
sections->add_child(sec_vb);
@@ -1413,12 +1413,12 @@ ProjectExportDialog::ProjectExportDialog() {
export_error = memnew(Label);
main_vb->add_child(export_error);
export_error->hide();
- export_error->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
+ export_error->add_theme_color_override("font_color", EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor)));
export_warning = memnew(Label);
main_vb->add_child(export_warning);
export_warning->hide();
- export_warning->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
+ export_warning->add_theme_color_override("font_color", EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor)));
export_templates_error = memnew(HBoxContainer);
main_vb->add_child(export_templates_error);
@@ -1426,7 +1426,7 @@ ProjectExportDialog::ProjectExportDialog() {
Label *export_error2 = memnew(Label);
export_templates_error->add_child(export_error2);
- export_error2->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
+ export_error2->add_theme_color_override("font_color", EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor)));
export_error2->set_text(String::utf8("• ") + TTR("Export templates for this platform are missing:") + " ");
result_dialog = memnew(AcceptDialog);
diff --git a/editor/filesystem_dock.cpp b/editor/filesystem_dock.cpp
index cef5cdb4a9..338376c724 100644
--- a/editor/filesystem_dock.cpp
+++ b/editor/filesystem_dock.cpp
@@ -1363,7 +1363,7 @@ void FileSystemDock::_get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Ve
}
}
-void FileSystemDock::_find_remaps(EditorFileSystemDirectory *p_efsd, const HashMap<String, String> &r_renames, Vector<String> &r_to_remaps) const {
+void FileSystemDock::_find_remaps(EditorFileSystemDirectory *p_efsd, const Vector<String> &r_renames, Vector<String> &r_to_remaps) const {
for (int i = 0; i < p_efsd->get_subdir_count(); i++) {
_find_remaps(p_efsd->get_subdir(i), r_renames, r_to_remaps);
}
@@ -1533,7 +1533,12 @@ void FileSystemDock::_try_duplicate_item(const FileOrFolder &p_item, const Strin
}
}
-void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, String> &p_renames) const {
+void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const {
+ // Update the paths in ResourceUID, so that UIDs remain valid.
+ for (const KeyValue<String, ResourceUID::ID> &pair : p_uids) {
+ ResourceUID::get_singleton()->set_id(pair.value, p_renames[pair.key]);
+ }
+
// Rename all resources loaded, be it subresources or actual resources.
List<Ref<Resource>> cached;
ResourceCache::get_cached_resources(&cached);
@@ -1553,50 +1558,30 @@ void FileSystemDock::_update_resource_paths_after_move(const HashMap<String, Str
r->set_path(base_path + extra_path);
}
-
- for (int i = 0; i < EditorNode::get_editor_data().get_edited_scene_count(); i++) {
- String file_path;
- if (i == EditorNode::get_editor_data().get_edited_scene()) {
- if (!get_tree()->get_edited_scene_root()) {
- continue;
- }
-
- file_path = get_tree()->get_edited_scene_root()->get_scene_file_path();
- } else {
- file_path = EditorNode::get_editor_data().get_scene_path(i);
- }
-
- if (p_renames.has(file_path)) {
- file_path = p_renames[file_path];
- }
-
- if (i == EditorNode::get_editor_data().get_edited_scene()) {
- get_tree()->get_edited_scene_root()->set_scene_file_path(file_path);
- } else {
- EditorNode::get_editor_data().set_scene_path(i, file_path);
- }
- }
}
-void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames) const {
+void FileSystemDock::_update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_remaps) const {
// The following code assumes that the following holds:
// 1) EditorFileSystem contains the old paths/folder structure from before the rename/move.
// 2) ResourceLoader can use the new paths without needing to call rescan.
- Vector<String> remaps;
- _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), p_renames, remaps);
- for (int i = 0; i < remaps.size(); ++i) {
+ List<String> scenes_to_reload;
+ for (int i = 0; i < p_remaps.size(); ++i) {
// Because we haven't called a rescan yet the found remap might still be an old path itself.
- String file = p_renames.has(remaps[i]) ? p_renames[remaps[i]] : remaps[i];
+ String file = p_renames.has(p_remaps[i]) ? p_renames[p_remaps[i]] : p_remaps[i];
print_verbose("Remapping dependencies for: " + file);
Error err = ResourceLoader::rename_dependencies(file, p_renames);
if (err == OK) {
if (ResourceLoader::get_resource_type(file) == "PackedScene") {
- callable_mp(EditorNode::get_singleton(), &EditorNode::reload_scene).bind(file).call_deferred();
+ scenes_to_reload.push_back(file);
}
} else {
- EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies:") + "\n" + remaps[i] + "\n");
+ EditorNode::get_singleton()->add_io_error(TTR("Unable to update dependencies:") + "\n" + p_remaps[i] + "\n");
}
}
+
+ for (const String &E : scenes_to_reload) {
+ EditorNode::get_singleton()->reload_scene(E);
+ }
}
void FileSystemDock::_update_project_settings_after_move(const HashMap<String, String> &p_renames, const HashMap<String, String> &p_folders_renames) {
@@ -1678,21 +1663,6 @@ void FileSystemDock::_update_favorites_list_after_move(const HashMap<String, Str
EditorSettings::get_singleton()->set_favorites(new_favorites);
}
-void FileSystemDock::_save_scenes_after_move(const HashMap<String, String> &p_renames) const {
- Vector<String> remaps;
- _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), p_renames, remaps);
- Vector<String> new_filenames;
-
- for (int i = 0; i < remaps.size(); ++i) {
- String file = p_renames.has(remaps[i]) ? p_renames[remaps[i]] : remaps[i];
- if (ResourceLoader::get_resource_type(file) == "PackedScene") {
- new_filenames.push_back(file);
- }
- }
-
- EditorNode::get_singleton()->save_scene_list(new_filenames);
-}
-
void FileSystemDock::_make_scene_confirm() {
const String scene_path = make_scene_dialog->get_scene_path();
@@ -1801,14 +1771,18 @@ void FileSystemDock::_rename_operation_confirm() {
return;
}
+ Vector<String> old_paths;
+ HashMap<String, ResourceUID::ID> uids;
+ Vector<String> remaps;
+ _before_move(old_paths, uids, remaps);
+
HashMap<String, String> file_renames;
HashMap<String, String> folder_renames;
_try_move_item(to_rename, new_path, file_renames, folder_renames);
int current_tab = EditorSceneTabs::get_singleton()->get_current_tab();
- _save_scenes_after_move(file_renames); // save scenes before updating
- _update_dependencies_after_move(file_renames);
- _update_resource_paths_after_move(file_renames);
+ _update_resource_paths_after_move(file_renames, uids);
+ _update_dependencies_after_move(file_renames, remaps);
_update_project_settings_after_move(file_renames, folder_renames);
_update_favorites_list_after_move(file_renames, folder_renames);
@@ -1817,9 +1791,6 @@ void FileSystemDock::_rename_operation_confirm() {
print_verbose("FileSystem: calling rescan.");
_rescan();
- print_verbose("FileSystem: saving moved scenes.");
- _save_scenes_after_move(file_renames);
-
current_path = new_path;
current_path_line_edit->set_text(current_path);
}
@@ -1937,6 +1908,11 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop
}
}
+ Vector<String> old_paths;
+ HashMap<String, ResourceUID::ID> uids;
+ Vector<String> remaps;
+ _before_move(old_paths, uids, remaps);
+
bool is_moved = false;
HashMap<String, String> file_renames;
HashMap<String, String> folder_renames;
@@ -1957,9 +1933,8 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop
if (is_moved) {
int current_tab = EditorSceneTabs::get_singleton()->get_current_tab();
- _save_scenes_after_move(file_renames); // Save scenes before updating.
- _update_dependencies_after_move(file_renames);
- _update_resource_paths_after_move(file_renames);
+ _update_resource_paths_after_move(file_renames, uids);
+ _update_dependencies_after_move(file_renames, remaps);
_update_project_settings_after_move(file_renames, folder_renames);
_update_favorites_list_after_move(file_renames, folder_renames);
@@ -1968,15 +1943,28 @@ void FileSystemDock::_move_operation_confirm(const String &p_to_path, bool p_cop
print_verbose("FileSystem: calling rescan.");
_rescan();
- print_verbose("FileSystem: saving moved scenes.");
- _save_scenes_after_move(file_renames);
-
current_path = p_to_path;
current_path_line_edit->set_text(current_path);
}
}
}
+void FileSystemDock::_before_move(Vector<String> &r_old_paths, HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_remaps) const {
+ for (int i = 0; i < to_move.size(); i++) {
+ r_old_paths.push_back(to_move[i].path);
+ ResourceUID::ID uid = ResourceLoader::get_resource_uid(to_move[i].path);
+ if (uid != ResourceUID::INVALID_ID) {
+ r_uids[to_move[i].path] = uid;
+ }
+ }
+
+ _find_remaps(EditorFileSystem::get_singleton()->get_filesystem(), r_old_paths, r_remaps);
+
+ // Open scenes with dependencies on the ones about to be moved will be reloaded,
+ // so save them first to prevent losing unsaved changes.
+ EditorNode::get_singleton()->save_scene_list(r_remaps);
+}
+
Vector<String> FileSystemDock::_tree_get_selected(bool remove_self_inclusion) const {
// Build a list of selected items with the active one at the first position.
Vector<String> selected_strings;
@@ -2361,7 +2349,7 @@ void FileSystemDock::_resource_created() {
ERR_FAIL_COND(!c);
Resource *r = Object::cast_to<Resource>(c);
- ERR_FAIL_COND(!r);
+ ERR_FAIL_NULL(r);
PackedScene *scene = Object::cast_to<PackedScene>(r);
if (scene) {
@@ -2694,7 +2682,7 @@ void FileSystemDock::drop_data_fw(const Point2 &p_point, const Variant &p_data,
}
}
if (!to_move.is_empty()) {
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
_move_operation_confirm(to_dir, true);
} else {
_move_operation_confirm(to_dir);
@@ -2925,7 +2913,7 @@ void FileSystemDock::_file_and_folders_fill_popup(PopupMenu *p_popup, Vector<Str
p_popup->add_child(folder_colors_menu);
p_popup->add_submenu_item(TTR("Set Folder Color..."), "FolderColor");
- p_popup->set_item_icon(-1, get_editor_theme_icon(SNAME("CanvasItem")));
+ p_popup->set_item_icon(-1, get_editor_theme_icon(SNAME("Paint")));
folder_colors_menu->add_icon_item(get_editor_theme_icon(SNAME("Folder")), TTR("Default (Reset)"));
folder_colors_menu->set_item_icon_modulate(0, get_theme_color(SNAME("folder_icon_color"), SNAME("FileDialog")));
diff --git a/editor/filesystem_dock.h b/editor/filesystem_dock.h
index 93720692fb..e900ac0037 100644
--- a/editor/filesystem_dock.h
+++ b/editor/filesystem_dock.h
@@ -262,12 +262,12 @@ private:
void _update_import_dock();
void _get_all_items_in_dir(EditorFileSystemDirectory *p_efsd, Vector<String> &r_files, Vector<String> &r_folders) const;
- void _find_remaps(EditorFileSystemDirectory *p_efsd, const HashMap<String, String> &r_renames, Vector<String> &r_to_remaps) const;
+ void _find_remaps(EditorFileSystemDirectory *p_efsd, const Vector<String> &r_renames, Vector<String> &r_to_remaps) const;
void _try_move_item(const FileOrFolder &p_item, const String &p_new_path, HashMap<String, String> &p_file_renames, HashMap<String, String> &p_folder_renames);
void _try_duplicate_item(const FileOrFolder &p_item, const String &p_new_path) const;
- void _update_dependencies_after_move(const HashMap<String, String> &p_renames) const;
- void _update_resource_paths_after_move(const HashMap<String, String> &p_renames) const;
- void _save_scenes_after_move(const HashMap<String, String> &p_renames) const;
+ void _before_move(Vector<String> &r_old_paths, HashMap<String, ResourceUID::ID> &r_uids, Vector<String> &r_remaps) const;
+ void _update_dependencies_after_move(const HashMap<String, String> &p_renames, const Vector<String> &p_remaps) const;
+ void _update_resource_paths_after_move(const HashMap<String, String> &p_renames, const HashMap<String, ResourceUID::ID> &p_uids) const;
void _update_favorites_list_after_move(const HashMap<String, String> &p_files_renames, const HashMap<String, String> &p_folders_renames) const;
void _update_project_settings_after_move(const HashMap<String, String> &p_renames, const HashMap<String, String> &p_folders_renames);
String _get_unique_name(const FileOrFolder &p_entry, const String &p_at_path);
diff --git a/editor/find_in_files.cpp b/editor/find_in_files.cpp
index 3e580e5f08..5506f4a6bc 100644
--- a/editor/find_in_files.cpp
+++ b/editor/find_in_files.cpp
@@ -501,8 +501,8 @@ void FindInFilesDialog::custom_action(const String &p_action) {
}
void FindInFilesDialog::_on_search_text_modified(String text) {
- ERR_FAIL_COND(!_find_button);
- ERR_FAIL_COND(!_replace_button);
+ ERR_FAIL_NULL(_find_button);
+ ERR_FAIL_NULL(_replace_button);
_find_button->set_disabled(get_search_text().is_empty());
_replace_button->set_disabled(get_search_text().is_empty());
diff --git a/editor/gui/editor_run_bar.cpp b/editor/gui/editor_run_bar.cpp
index 4dfe40f0ad..497c92d951 100644
--- a/editor/gui/editor_run_bar.cpp
+++ b/editor/gui/editor_run_bar.cpp
@@ -220,7 +220,7 @@ void EditorRunBar::_run_scene(const String &p_scene_path) {
return;
}
- run_filename = GLOBAL_DEF_BASIC("application/run/main_scene", "");
+ run_filename = GLOBAL_GET("application/run/main_scene");
} break;
}
diff --git a/editor/gui/editor_spin_slider.cpp b/editor/gui/editor_spin_slider.cpp
index fa94a107f0..c59822ba55 100644
--- a/editor/gui/editor_spin_slider.cpp
+++ b/editor/gui/editor_spin_slider.cpp
@@ -212,7 +212,7 @@ void EditorSpinSlider::_value_input_gui_input(const Ref<InputEvent> &p_event) {
}
}
- if (k->is_ctrl_pressed()) {
+ if (k->is_command_or_control_pressed()) {
step *= 100.0;
} else if (k->is_shift_pressed()) {
step *= 10.0;
diff --git a/editor/gui/editor_toaster.cpp b/editor/gui/editor_toaster.cpp
index 6a415c18da..0d468bc0a3 100644
--- a/editor/gui/editor_toaster.cpp
+++ b/editor/gui/editor_toaster.cpp
@@ -456,7 +456,7 @@ void EditorToaster::_popup_str(String p_message, Severity p_severity, String p_t
// Retrieve the label back, then update the text.
Label *message_label = toasts[control].message_label;
- ERR_FAIL_COND(!message_label);
+ ERR_FAIL_NULL(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());
diff --git a/editor/gui/scene_tree_editor.cpp b/editor/gui/scene_tree_editor.cpp
index 8e08528f19..f483539ba2 100644
--- a/editor/gui/scene_tree_editor.cpp
+++ b/editor/gui/scene_tree_editor.cpp
@@ -66,12 +66,12 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
}
TreeItem *item = Object::cast_to<TreeItem>(p_item);
- ERR_FAIL_COND(!item);
+ ERR_FAIL_NULL(item);
NodePath np = item->get_metadata(0);
Node *n = get_node(np);
- ERR_FAIL_COND(!n);
+ ERR_FAIL_NULL(n);
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
if (p_id == BUTTON_SUBSCENE) {
@@ -94,7 +94,7 @@ void SceneTreeEditor::_cell_button_pressed(Object *p_item, int p_column, int p_i
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() > 1 && selection.find(n) != nullptr) {
for (Node *nv : selection) {
- ERR_FAIL_COND(!nv);
+ ERR_FAIL_NULL(nv);
if (nv == n) {
continue;
}
@@ -826,7 +826,7 @@ void SceneTreeEditor::_tree_changed() {
void SceneTreeEditor::_selected_changed() {
TreeItem *s = tree->get_selected();
- ERR_FAIL_COND(!s);
+ ERR_FAIL_NULL(s);
NodePath np = s->get_metadata(0);
Node *n = get_node(np);
@@ -852,7 +852,7 @@ void SceneTreeEditor::_deselect_items() {
void SceneTreeEditor::_cell_multi_selected(Object *p_object, int p_cell, bool p_selected) {
TreeItem *item = Object::cast_to<TreeItem>(p_object);
- ERR_FAIL_COND(!item);
+ ERR_FAIL_NULL(item);
if (!item->is_visible()) {
return;
@@ -980,7 +980,7 @@ void SceneTreeEditor::set_selected(Node *p_node, bool p_emit_selected) {
void SceneTreeEditor::_rename_node(Node *p_node, const String &p_name) {
TreeItem *item = _find(tree->get_root(), p_node->get_path());
- ERR_FAIL_COND(!item);
+ ERR_FAIL_NULL(item);
String new_name = p_name.validate_node_name();
if (new_name != p_name) {
@@ -1060,10 +1060,10 @@ void SceneTreeEditor::_rename_node(Node *p_node, const String &p_name) {
void SceneTreeEditor::_renamed() {
TreeItem *which = tree->get_edited();
- ERR_FAIL_COND(!which);
+ ERR_FAIL_NULL(which);
NodePath np = which->get_metadata(0);
Node *n = get_node(np);
- ERR_FAIL_COND(!n);
+ ERR_FAIL_NULL(n);
String new_name = which->get_text(0);
@@ -1131,7 +1131,7 @@ void SceneTreeEditor::set_editor_selection(EditorSelection *p_selection) {
}
void SceneTreeEditor::_update_selection(TreeItem *item) {
- ERR_FAIL_COND(!item);
+ ERR_FAIL_NULL(item);
NodePath np = item->get_metadata(0);
@@ -1196,7 +1196,7 @@ void SceneTreeEditor::_cell_collapsed(Object *p_obj) {
NodePath np = ti->get_metadata(0);
Node *n = get_node(np);
- ERR_FAIL_COND(!n);
+ ERR_FAIL_NULL(n);
n->set_display_folded(collapsed);
}
diff --git a/editor/icons/AABB.svg b/editor/icons/AABB.svg
index 7db093cc0d..94bf00d7bf 100644
--- a/editor/icons/AABB.svg
+++ b/editor/icons/AABB.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 1a3 3 0 0 0 -3 3 3 3 0 0 0 .77734 2.0117 3 3 0 0 0 -2.7773 2.9883 3 3 0 0 0 3 3h2v-5h2v-6h-2zm6 0v5.1738a3 3 0 0 0 -1-.17383v-2h-2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2h-2zm-6 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm8 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm-10 3v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm7 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#ee5677"/><path d="m8 4v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm-5 2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6zm0 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm7 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#fff" fill-opacity=".23529"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M5 1a3 3 0 0 0-2.223 5.012A3 3 0 0 0 3 12h2V7h2V1H5zm6 0v5.174A3 3 0 0 0 10 6V4H8v8h2a3 3 0 0 0 3-3 3 3 0 0 0 0-6V1h-2zM5 3v2a1 1 0 0 1 0-2zm8 2a1 1 0 0 1 0 2zM3 8v2a1 1 0 0 1 0-2zm7 0a1 1 0 0 1 0 2z" fill="#ee5677"/><path d="M8 4v8h2a3 3 0 0 0 0-6V4zM3 6a3 3 0 0 0 0 6h2V6zm0 2v2a1 1 0 0 1 0-2zm7 0a1 1 0 0 1 0 2z" fill="#fff" fill-opacity=".235"/></svg>
diff --git a/editor/icons/Array.svg b/editor/icons/Array.svg
index 068007bb29..fbf0df8f68 100644
--- a/editor/icons/Array.svg
+++ b/editor/icons/Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6zm6 0a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2zm4 0a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2zm-10 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#e0e0e0"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4 4a3 3 0 0 0 0 6h2V4zm6 0a3 3 0 0 0-3 3v3h2V7a1 1 0 0 1 1-1h1V4zm4 0a3 3 0 0 0-3 3v3h2V7a1 1 0 0 1 1-1h1V4zM4 6v2a1 1 0 0 1 0-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Basis.svg b/editor/icons/Basis.svg
index e425cf3bcd..6754da4213 100644
--- a/editor/icons/Basis.svg
+++ b/editor/icons/Basis.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm10 0v2h2v-2zm-3 2a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v2h2a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2zm7 0a2 2 0 0 0 -1.7324 1 2 2 0 0 0 0 2 2 2 0 0 0 1.7324 1h-2v-2h-2v4h4a2 2 0 0 0 1.7324-1 2 2 0 0 0 0-2 2 2 0 0 0 -1.7324-1h2v-2zm-12 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#e1ec41"/><path d="m10 2v2h2v-2zm0 4v4h2v-4z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 2v8h2a3 3 0 0 0 0-6V2zm10 0v2h2V2zM7 4a2 2 0 0 0 0 4H5v2h2a2 2 0 0 0 0-4h2V4zm7 0a2 2 0 0 0 0 4h-2V6h-2v4h4a2 2 0 0 0 0-4h2V4zM2 6a1 1 0 0 1 1 1 1 1 0 0 1-1 1z" fill="#e1ec41"/><path d="M10 2v2h2V2zm0 4v4h2V6z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/CanvasTexture.svg b/editor/icons/CanvasTexture.svg
new file mode 100644
index 0000000000..8734da3ee8
--- /dev/null
+++ b/editor/icons/CanvasTexture.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v8.5c1.5.5 1-1 2-1V3h10v2.2a2.415 2.415 0 0 1 2 .5V2a1 1 0 0 0-1-1zm1.36 10.18c-.283.169-.516.466-.645.865-.416 1.277-2.417-.94-.946 2.009.465.931 1.912 1.202 2.835.723a1.922 1.922 0 0 0 .83-2.555c-.578-1.158-1.45-1.411-2.074-1.041zm2.222-.7 1.272 2.495 7.069-3.602a1.415 1.415 0 0 0-1.259-2.534zM9 5v1H8v1H6v1H5v1H4v1h.25L11 6.527V6h-1V5z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/CheckBox.svg b/editor/icons/CheckBox.svg
index 32eaf2d212..cbe203c797 100644
--- a/editor/icons/CheckBox.svg
+++ b/editor/icons/CheckBox.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2c-1.1046 0-2 .89543-2 2v9c0 1.1046.89543 2 2 2h9c1.1046 0 2-.89543 2-2v-4.9277l-2 2v2.9277h-9v-9h6.5859l2-2zm9.3633 2.0508-4.9492 4.9492-1.4141-1.4141-1.4141 1.4141 2.8281 2.8281 6.3633-6.3633z" fill="#8eef97"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 2a2 2 0 0 0-2 2v9a2 2 0 0 0 2 2h9a2 2 0 0 0 2-2V8l-2 2v3H3V4h7l2-2zm9.363 2.05L7.414 9 6 7.586 4.586 9l2.828 2.828 6.363-6.363z" fill="#8eef97"/></svg>
diff --git a/editor/icons/CodeRegionFoldDownArrow.svg b/editor/icons/CodeRegionFoldDownArrow.svg
new file mode 100644
index 0000000000..3bc4f3f73b
--- /dev/null
+++ b/editor/icons/CodeRegionFoldDownArrow.svg
@@ -0,0 +1 @@
+<svg height="12" width="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H6V2a1 1 0 0 0-1-1zm1 5a1 1 0 0 1 1.414-1.414L6 6.172l1.586-1.586A1 1 0 0 1 9 6L6.707 8.293a1 1 0 0 1-1.414 0Z" fill="#fff"/></svg> \ No newline at end of file
diff --git a/editor/icons/CodeRegionFoldedRightArrow.svg b/editor/icons/CodeRegionFoldedRightArrow.svg
new file mode 100644
index 0000000000..a9b81d54f3
--- /dev/null
+++ b/editor/icons/CodeRegionFoldedRightArrow.svg
@@ -0,0 +1 @@
+<svg height="12" width="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H6V2a1 1 0 0 0-1-1zm3.5 8a1 1 0 0 1-1.414-1.414L5.672 6 4.086 4.414A1 1 0 0 1 5.5 3l2.293 2.293a1 1 0 0 1 0 1.414Z" fill="#fff"/></svg> \ No newline at end of file
diff --git a/editor/icons/Color.svg b/editor/icons/Color.svg
index 5c6fca1876..a03753989f 100644
--- a/editor/icons/Color.svg
+++ b/editor/icons/Color.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2z" fill="#ff5f5f"/><path d="m14 4a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#5fb2ff"/><path d="m6 2v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-5z" fill="#5fff97"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4 4a3 3 0 0 0 0 6h1V8H4a1 1 0 0 1 0-2h1V4z" fill="#ff5f5f"/><path d="M6 2v5a3 3 0 0 0 3 3h1V8H9a1 1 0 0 1-1-1V2z" fill="#5fff97"/><path d="M14 4a3 3 0 0 0-3 3v3h2V7a1 1 0 0 1 1-1h1V4z" fill="#5fb2ff"/></svg>
diff --git a/editor/icons/CurveTexture.svg b/editor/icons/CurveTexture.svg
index a5524f145c..b9838ebc36 100644
--- a/editor/icons/CurveTexture.svg
+++ b/editor/icons/CurveTexture.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v9.16A3 3 0 0 1 2 11h1V3h10v1.135a3 3 0 0 1 2 0V2a1 1 0 0 0-1-1zm7 4v1H8v1H6v1H5v1H4v1h4.39c1.113-.567 1.968-1.454 2.61-3.473V6h-1V5H9zm4.039 1.727c-.927 3.246-2.636 4.682-4.652 5.466C6.37 12.978 4 13 2 13a1 1 0 1 0 0 2c2 0 4.63.024 7.113-.941 2.484-.966 4.775-3.03 5.848-6.784a1 1 0 0 0-1.922-.548z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v9.16A3 3 0 0 1 2 11h1V3h10v1.135a3 3 0 0 1 2 0V2a1 1 0 0 0-1-1zm7 4v1H8v1H6v1H5v1H4v1h4.39c1.113-.567 1.968-1.454 2.61-3.473V6h-1V5zm4.039 1.727c-.927 3.246-2.636 4.682-4.652 5.466C6.37 12.978 4 13 2 13a1 1 0 1 0 0 2c2 0 4.63.024 7.113-.941 2.484-.966 4.775-3.03 5.848-6.784a1 1 0 0 0-1.922-.548z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Dictionary.svg b/editor/icons/Dictionary.svg
index 0284e847d9..98c9384184 100644
--- a/editor/icons/Dictionary.svg
+++ b/editor/icons/Dictionary.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2v2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-8zm3 0v2h2v-2zm7 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-2 2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2zm-3 3v-1h-2v4h2zm-5-1v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#54ed9e"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 2v2a3 3 0 0 0 0 6h2V2zm3 0v2h2V2zm7 0v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2zm-2 2a3 3 0 0 0 0 6h1V8h-1a1 1 0 0 1 0-2h1V4zM8 7V6H6v4h2zM3 6v2a1 1 0 0 1 0-2z" fill="#54ed9e"/></svg>
diff --git a/editor/icons/GizmoCPUParticles3D.svg b/editor/icons/GizmoCPUParticles3D.svg
index 3dae7ade80..b67aa0eaed 100644
--- a/editor/icons/GizmoCPUParticles3D.svg
+++ b/editor/icons/GizmoCPUParticles3D.svg
@@ -1 +1 @@
-<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M36.688 4a6.112 6.112 0 0 0-6.112 6.112v4.8h-9.6a6.112 6.112 0 0 0-6.112 6.112v9.6h-4.8a6.112 6.112 0 0 0-6.112 6.112v3.2a6.112 6.112 0 0 0 6.112 6.112h4.8v36h-4.8a6.112 6.112 0 0 0-6.112 6.112v3.2a6.112 6.112 0 0 0 6.112 6.112h4.8v9.6a6.112 6.112 0 0 0 6.112 6.112h9.6v4.8a6.112 6.112 0 0 0 6.112 6.112h3.2A6.112 6.112 0 0 0 46 117.984v-4.8h36v4.8a6.112 6.112 0 0 0 6.112 6.112h3.2a6.112 6.112 0 0 0 6.112-6.112v-4.8h9.6a6.112 6.112 0 0 0 6.112-6.112v-9.6h4.8a6.112 6.112 0 0 0 6.112-6.112v-3.2a6.112 6.112 0 0 0-6.112-6.112h-4.8v-36h4.8a6.112 6.112 0 0 0 6.112-6.112v-3.2a6.112 6.112 0 0 0-6.112-6.112h-4.8v-9.6a6.112 6.112 0 0 0-6.112-6.104h-9.6v-4.8a6.112 6.112 0 0 0-6.112-6.112h-3.2A6.112 6.112 0 0 0 82 10.12v4.8H46v-4.8a6.112 6.112 0 0 0-6.112-6.112z" fill="#f7f5cf" stroke="#b3b3b3" stroke-width="3"/><path d="M88 82a18 18 0 0 0 2.484-35.814 27 30 0 0 0-52.944 0 18 18 0 0 0 2.484 35.802zm-48 6a6 6 0 0 0 0 12 6 6 0 0 0 0-12zm48 0a6 6 0 0 0 0 12 6 6 0 0 0 0-12zm-24 6a6 6 0 0 0 0 12 6 6 0 0 0 0-12z" fill="#b3b3b3"/></svg>
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M36.688 4a6.112 6.112 0 0 0-6.112 6.112v4.8h-9.6a6.112 6.112 0 0 0-6.112 6.112v9.6h-4.8a6.112 6.112 0 0 0-6.112 6.112v3.2a6.112 6.112 0 0 0 6.112 6.112h4.8v36h-4.8a6.112 6.112 0 0 0-6.112 6.112v3.2a6.112 6.112 0 0 0 6.112 6.112h4.8v9.6a6.112 6.112 0 0 0 6.112 6.112h9.6v4.8a6.112 6.112 0 0 0 6.112 6.112h3.2A6.112 6.112 0 0 0 46 117.984v-4.8h36v4.8a6.112 6.112 0 0 0 6.112 6.112h3.2a6.112 6.112 0 0 0 6.112-6.112v-4.8h9.6a6.112 6.112 0 0 0 6.112-6.112v-9.6h4.8a6.112 6.112 0 0 0 6.112-6.112v-3.2a6.112 6.112 0 0 0-6.112-6.112h-4.8v-36h4.8a6.112 6.112 0 0 0 6.112-6.112v-3.2a6.112 6.112 0 0 0-6.112-6.112h-4.8v-9.6a6.112 6.112 0 0 0-6.112-6.104h-9.6v-4.8a6.112 6.112 0 0 0-6.112-6.112h-3.2A6.112 6.112 0 0 0 82 10.12v4.8H46v-4.8a6.112 6.112 0 0 0-6.112-6.112z" stroke="#000" stroke-width="8" stroke-opacity=".3"/><path d="M36.688 4a6.112 6.112 0 0 0-6.112 6.112v4.8h-9.6a6.112 6.112 0 0 0-6.112 6.112v9.6h-4.8a6.112 6.112 0 0 0-6.112 6.112v3.2a6.112 6.112 0 0 0 6.112 6.112h4.8v36h-4.8a6.112 6.112 0 0 0-6.112 6.112v3.2a6.112 6.112 0 0 0 6.112 6.112h4.8v9.6a6.112 6.112 0 0 0 6.112 6.112h9.6v4.8a6.112 6.112 0 0 0 6.112 6.112h3.2A6.112 6.112 0 0 0 46 117.984v-4.8h36v4.8a6.112 6.112 0 0 0 6.112 6.112h3.2a6.112 6.112 0 0 0 6.112-6.112v-4.8h9.6a6.112 6.112 0 0 0 6.112-6.112v-9.6h4.8a6.112 6.112 0 0 0 6.112-6.112v-3.2a6.112 6.112 0 0 0-6.112-6.112h-4.8v-36h4.8a6.112 6.112 0 0 0 6.112-6.112v-3.2a6.112 6.112 0 0 0-6.112-6.112h-4.8v-9.6a6.112 6.112 0 0 0-6.112-6.104h-9.6v-4.8a6.112 6.112 0 0 0-6.112-6.112h-3.2A6.112 6.112 0 0 0 82 10.12v4.8H46v-4.8a6.112 6.112 0 0 0-6.112-6.112z" fill="#f7f5cf"/><path d="M88 82a18 18 0 0 0 2.484-35.814 27 30 0 0 0-52.944 0 18 18 0 0 0 2.484 35.802zm-48 6a6 6 0 0 0 0 12 6 6 0 0 0 0-12zm48 0a6 6 0 0 0 0 12 6 6 0 0 0 0-12zm-24 6a6 6 0 0 0 0 12 6 6 0 0 0 0-12z" fill="#e1b44c"/></svg>
diff --git a/editor/icons/GizmoDecal.svg b/editor/icons/GizmoDecal.svg
new file mode 100644
index 0000000000..bd3b3f608f
--- /dev/null
+++ b/editor/icons/GizmoDecal.svg
@@ -0,0 +1 @@
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><circle cx="64" cy="64" fill="none" stroke="#000" stroke-width="8" stroke-opacity=".3" r="48"/><path d="M111.313 55.934a48 48 0 1 0-71.28 49.528z" fill="#f7f5cf"/><path d="M111.313 55.934a48 48 0 0 0-71.28 49.528z" fill="#e1b44c"/><path d="M40.033 105.462a48 48 0 0 0 71.28-49.528z" fill="#f7f5cf" fill-opacity=".4"/></svg>
diff --git a/editor/icons/GizmoFogVolume.svg b/editor/icons/GizmoFogVolume.svg
new file mode 100644
index 0000000000..6a3423b1a2
--- /dev/null
+++ b/editor/icons/GizmoFogVolume.svg
@@ -0,0 +1 @@
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M20 68S8 68 8 56s16-12 16-12 0-32 28-32 28 24 28 24 10.08-16 24-8 4 24 4 24 12 0 12 8-8 8-8 8zm16 8a4 4 0 0 0 0 8h64a4 4 0 0 0 0-8zm-8 16a4 4 0 0 0 0 8h40a4 4 0 0 0 0-8zm56 0a4 4 0 0 0 0 8h20a4 4 0 0 0 0-8zm-40 16a4 4 0 0 0 0 8h40a4 4 0 0 0 0-8z" stroke="#000" stroke-width="8" stroke-opacity=".3"/><path d="M20 68S8 68 8 56s16-12 16-12 0-32 28-32 28 24 28 24 10.08-16 24-8 4 24 4 24 12 0 12 8-8 8-8 8zm16 8a4 4 0 0 0 0 8h64a4 4 0 0 0 0-8zm-8 16a4 4 0 0 0 0 8h40a4 4 0 0 0 0-8zm56 0a4 4 0 0 0 0 8h20a4 4 0 0 0 0-8zm-40 16a4 4 0 0 0 0 8h40a4 4 0 0 0 0-8z" fill="#f7f5cf"/></svg>
diff --git a/editor/icons/GizmoLightmapProbe.svg b/editor/icons/GizmoLightmapProbe.svg
new file mode 100644
index 0000000000..7259a7c184
--- /dev/null
+++ b/editor/icons/GizmoLightmapProbe.svg
@@ -0,0 +1 @@
+<svg height="128" viewBox="0 0 128 128" width="128" xmlns="http://www.w3.org/2000/svg"><path d="M8 72h24V56H8zm16.4 20.28 11.32 11.312L47.032 92.28 35.72 80.968zm0-56.56 11.32 11.312L47.032 35.72 35.72 24.4zM40 64a24 24 0 0 0 48 0 24 24 0 0 0-48 0zm24 56A56 56 0 0 0 64 8v18.672a37.328 37.328 0 0 1 0 74.656z" stroke="#000" stroke-width="8" stroke-opacity=".3"/><path d="M8 72h24V56H8zm16.4 20.28 11.32 11.312L47.032 92.28 35.72 80.968zm0-56.56 11.32 11.312L47.032 35.72 35.72 24.4zM40 64a24 24 0 0 0 48 0 24 24 0 0 0-48 0zm24 56A56 56 0 0 0 64 8v18.672a37.328 37.328 0 0 1 0 74.656z" fill="#f7f5cf"/></svg>
diff --git a/editor/icons/GraphEdit.svg b/editor/icons/GraphEdit.svg
index fd633a4662..24685e0caf 100644
--- a/editor/icons/GraphEdit.svg
+++ b/editor/icons/GraphEdit.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M11 1c-.554 0-1 .446-1 1v3c0 .554.446 1 1 1h3c.554 0 1-.446 1-1V2c0-.554-.446-1-1-1h-3zM9 3.883L6.732 5.016c.17.292.268.628.268.984v1.117l2.268-1.133A1.964 1.964 0 019 5V3.883zM2 5c-.554 0-1 .446-1 1v4c0 .554.446 1 1 1h3c.554 0 1-.446 1-1V6c0-.554-.446-1-1-1H2zm5 3.883V10c0 .356-.099.692-.268.984L9 12.117V11c0-.356.099-.692.268-.984L7 8.883zM11 10c-.554 0-1 .446-1 1v3c0 .554.446 1 1 1h3c.554 0 1-.446 1-1v-3c0-.554-.446-1-1-1h-3z" color="#000" fill="#8eef97"/><path d="M5 3h6" fill="none"/><rect width="3" height="1" x="-5" y="6.5" ry=".5" fill="#4a4a4a"/></svg>
+<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M11 1a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V2a1 1 0 0 0-1-1zM6.732 5A2 2 0 0 1 7 6v1.117L9.268 6A2 2 0 0 1 9 5V3.883zM2 5a1 1 0 0 0-1 1v4a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1V6a1 1 0 0 0-1-1zm5 3.883V10a2 2 0 0 1-.268 1L9 12.117V11a2 2 0 0 1 .268-1zM11 10a1 1 0 0 0-1 1v3a1 1 0 0 0 1 1h3a1 1 0 0 0 1-1v-3a1 1 0 0 0-1-1z" fill="#8eef97"/></svg>
diff --git a/editor/icons/GraphElement.svg b/editor/icons/GraphElement.svg
index 5629993c25..f579f59656 100644
--- a/editor/icons/GraphElement.svg
+++ b/editor/icons/GraphElement.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2a6 6 0 00-6 6 6 6 0 006 6 6 6 0 006-6 6 6 0 00-6-6zm0 2a4 4 0 014 4 4 4 0 01-4 4 4 4 0 01-4-4 4 4 0 014-4zm0 2a2 2 0 100 4 2 2 0 000-4z" fill="#8eef97"/></svg>
+<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><circle cx="8" cy="8" r="2" fill="#8eef97"/><circle cx="8" cy="8" r="5" stroke-width="2" stroke="#8eef97" fill="none"/></svg>
diff --git a/editor/icons/GraphNode.svg b/editor/icons/GraphNode.svg
index 9bef701ffd..83f666ed06 100644
--- a/editor/icons/GraphNode.svg
+++ b/editor/icons/GraphNode.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.846 2A1.841 1.841 0 003 3.846V4h10v-.154A1.841 1.841 0 0011.154 2H4.846zM3 5v1a3 3 0 013 3 3 3 0 01-3 3v.154C3 13.177 3.823 14 4.846 14h6.308A1.841 1.841 0 0013 12.154V12a3 3 0 01-3-3 3 3 0 013-3V5H3zm0 2a2 2 0 00-2 2 2 2 0 002 2 2 2 0 002-2 2 2 0 00-2-2zm10 0a2 2 0 00-2 2 2 2 0 002 2 2 2 0 002-2 2 2 0 00-2-2z" fill="#8eef97"/></svg>
+<svg height="16" width="16" viewBox="0 0 16 16" xmlns="http://www.w3.org/2000/svg"><path d="M5 2a2 2 0 0 0-2 2h10a2 2 0 0 0-2-2zM3 5v1a3 3 0 0 1 0 6 2 2 0 0 0 2 2h6a2 2 0 0 0 2-2 3 3 0 0 1 0-6V5zm0 2a2 2 0 0 0 0 4 2 2 0 0 0 0-4zm10 0a2 2 0 0 0 0 4 2 2 0 0 0 0-4z" fill="#8eef97"/></svg>
diff --git a/editor/icons/GuiToggleOnMirroredDisabled.svg b/editor/icons/GuiToggleOnDisabledMirrored.svg
index bbf9b0d95d..bbf9b0d95d 100644
--- a/editor/icons/GuiToggleOnMirroredDisabled.svg
+++ b/editor/icons/GuiToggleOnDisabledMirrored.svg
diff --git a/editor/icons/IOSDeviceWired.svg b/editor/icons/IOSDeviceWired.svg
index 15bb0b4523..a138458849 100644
--- a/editor/icons/IOSDeviceWired.svg
+++ b/editor/icons/IOSDeviceWired.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16" viewBox="0 0 4.233 4.233"><path fill="#e0e0e0" d="M1.795.265a.53.53 0 0 0-.53.529v2.645c0 .293.237.53.53.53h1.587a.53.53 0 0 0 .53-.53V.794a.53.53 0 0 0-.53-.53zm0 .529h.256v.165a.247.247 0 0 0 .247.248h.58A.247.247 0 0 0 3.126.96V.794h.256v2.645H1.795z"/><path fill="#e0e0e0" d="M1.743 2.964a.178.178 0 0 0-.178-.178H1.18a.534.534 0 0 0-.503-.356v.178H.32v.178h.356v.356H.32v.178h.356v.178a.533.533 0 0 0 .502-.356h.387c.099 0 .178-.08.178-.178z" style="stroke-width:.177922"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16" viewBox="0 0 16 16"><path fill="#e0e0e0" d="M7 1a2 2 0 0 0-2 2v7.5h-.4a2 2 0 0 0-2-1.5v.8H1v.8h1.6v1.2H1v.8h1.6v.8a2 2 0 0 0 2-1.5H5V13a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 2h1v.6a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V3h1v10H7z"/></svg>
diff --git a/editor/icons/IOSDeviceWireless.svg b/editor/icons/IOSDeviceWireless.svg
index 91fc679460..a07fa85a6b 100644
--- a/editor/icons/IOSDeviceWireless.svg
+++ b/editor/icons/IOSDeviceWireless.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16" viewBox="0 0 4.233 4.233"><path fill="#e0e0e0" d="M1.795.265a.53.53 0 0 0-.53.529v2.645c0 .293.237.53.53.53h1.587a.53.53 0 0 0 .53-.53V.794a.53.53 0 0 0-.53-.53zm0 .529h.256v.165a.247.247 0 0 0 .247.248h.58A.247.247 0 0 0 3.126.96V.794h.256v2.645H1.795z"/><path d="M1.034 2.457a.444.444 0 0 1-.159-.34.444.444 0 0 1 .16-.34m-.286 1.02a.889.889 0 0 1-.318-.68.889.889 0 0 1 .318-.681" style="fill:none;fill-opacity:.996078;stroke:#e0e0e0;stroke-width:.222194;stroke-linecap:round;stroke-linejoin:round;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:16.5;stroke-opacity:1;paint-order:stroke markers fill"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" xml:space="preserve" width="16" height="16" viewBox="0 0 16 16"><path fill="#e0e0e0" d="M7 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 2h1v.6a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V3h1v10H7z"/><path d="M3.75 9a1.75 1.75 0 0 1 0-2.5m-1 4a3.5 3.5 0 0 1 0-5.5" fill="none" stroke="#e0e0e0" stroke-linecap="round"/></svg>
diff --git a/editor/icons/IOSSimulator.svg b/editor/icons/IOSSimulator.svg
index 59ab11a8a5..cb5e877a84 100644
--- a/editor/icons/IOSSimulator.svg
+++ b/editor/icons/IOSSimulator.svg
@@ -1 +1 @@
-<svg xmlns="http://www.w3.org/2000/svg" height="16" viewBox="0 0 4.233 4.233" width="16"><path d="M1.399.735H.32v2.763h1.078c0-.004-.006-.006-.006-.01V.745c0-.004.006-.006.006-.01z" fill="#4bb7f8"/><path d="M.49.9v2.432h.62v-.18H.67v-.35h.44v-.18H.67V1.08h.44V.9H.49z" fill="#e0e0e0"/><path d="M1.795.265a.53.53 0 0 0-.53.529v2.645c0 .293.237.53.53.53h1.587a.53.53 0 0 0 .53-.53V.794a.53.53 0 0 0-.53-.53zm0 .529h.256v.165a.247.247 0 0 0 .247.248h.58A.247.247 0 0 0 3.126.96V.794h.256v2.645H1.795z" fill="#e0e0e0"/></svg>
+<svg xmlns="http://www.w3.org/2000/svg" height="16" viewBox="0 0 16 16" width="16"><path d="M5 3H1v10h4z" fill="#4bb7f8"/><path d="M1.7 3.5v9h2.6v-.8H2.5v-1.3h1.8v-.8H2.5V4.3h1.8v-.8zM7 1a2 2 0 0 0-2 2v10a2 2 0 0 0 2 2h6a2 2 0 0 0 2-2V3a2 2 0 0 0-2-2zm0 2h1v.6a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1V3h1v10H7z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/KeyPosition.svg b/editor/icons/KeyPosition.svg
index 37ba41f996..c96df83523 100644
--- a/editor/icons/KeyPosition.svg
+++ b/editor/icons/KeyPosition.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 1a.76.76 0 0 0-.54.225L4.226 4.46a.76.76 0 0 0 0 1.078L7.46 8.775a.76.76 0 0 0 1.078 0l3.236-3.236a.76.76 0 0 0 0-1.078L8.54 1.225A.76.76 0 0 0 8 1zM1 8v5a3 3 0 0 0 3 3h1v-2H4a1 1 0 0 1-1-1V8zm7 2a3 3 0 0 0 0 6 3 3 0 0 0 0-6zm6 0a3 3 0 0 0 0 6h1v-2h-1a1 1 0 0 1 0-2h1v-2h-1zm-6 2a1 1 0 0 1 0 2 1 1 0 0 1 0-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.226 3.46a.76.76 0 0 0 0 1.078L7.46 7.775a.76.76 0 0 0 1.078 0l3.236-3.236a.76.76 0 0 0 0-1.078L8.54.225a.76.76 0 0 0-1.08 0zM8 9a3 3 0 0 0 0 6 3 3 0 0 0 0-6zm0 2a1 1 0 0 1 0 2 1 1 0 0 1 0-2zm5-2a1 1 0 0 0 0 4h-2v2h2a1 1 0 0 0 0-4h2V9zM0 9h2a2.7 2.7 0 0 1 0 5.4V16H0zm2 3.7a1 1 0 0 0 0-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/KeyRotation.svg b/editor/icons/KeyRotation.svg
index 4d46f8a0f0..88fc22bafd 100644
--- a/editor/icons/KeyRotation.svg
+++ b/editor/icons/KeyRotation.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 1a.76.76 0 0 0-.54.225L4.226 4.46a.76.76 0 0 0 0 1.078L7.46 8.775a.76.76 0 0 0 1.078 0l3.236-3.236a.76.76 0 0 0 0-1.078L8.54 1.225A.76.76 0 0 0 8 1zm3 7v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1-1-1v-1h2v-2h-2V8zm0 5a3 3 0 0 0-6 0 3 3 0 0 0 6 0zm-7-3a3 3 0 0 0-3 3v3h2v-3a1 1 0 0 1 1-1h1v-2zm4 2a1 1 0 0 1 0 2 1 1 0 0 1 0-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.226 3.46a.76.76 0 0 0 0 1.078L7.46 7.775a.76.76 0 0 0 1.078 0l3.236-3.236a.76.76 0 0 0 0-1.078L8.54.225a.76.76 0 0 0-1.08 0zM11 7v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1-1-1v-1h2V9h-2V7zm0 5a3 3 0 0 0-6 0 3 3 0 0 0 6 0zM4 9a3 3 0 0 0-3 3v3h2v-3a1 1 0 0 1 1-1h1V9zm4 2a1 1 0 0 1 0 2 1 1 0 0 1 0-2z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/KeyScale.svg b/editor/icons/KeyScale.svg
index c7b55028ab..bd36c83b30 100644
--- a/editor/icons/KeyScale.svg
+++ b/editor/icons/KeyScale.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 1a.76.76 0 0 0-.54.225L4.226 4.46a.76.76 0 0 0 0 1.078L7.46 8.775a.76.76 0 0 0 1.078 0l3.236-3.236a.76.76 0 0 0 0-1.078L8.54 1.225A.76.76 0 0 0 8 1zm3 7v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1-1-1V8zm-8 2a2 2 0 1 0 0 4H1v2h2a2 2 0 1 0 0-4h2v-2zm6 0a3 3 0 1 0 0 6h1v-2H9a1 1 0 0 1 0-2h1v-2z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4.226 3.46a.76.76 0 0 0 0 1.078L7.46 7.775a.76.76 0 0 0 1.078 0l3.236-3.236a.76.76 0 0 0 0-1.078L8.54.225a.76.76 0 0 0-1.08 0zM11 7v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1-1-1V7zM3 9a2 2 0 1 0 0 4H1v2h2a2 2 0 1 0 0-4h2V9zm6 0a3 3 0 1 0 0 6h1v-2H9a1 1 0 0 1 0-2h1V9z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/MiniObject.svg b/editor/icons/MiniObject.svg
index 7fe3b773d6..3bba3bc1a3 100644
--- a/editor/icons/MiniObject.svg
+++ b/editor/icons/MiniObject.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m6 2v8h2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3v-2zm0 5a3 3 0 0 0 -3-3 3 3 0 0 0 -3 3 3 3 0 0 0 3 3 3 3 0 0 0 3-3zm7-3v5a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-5zm-10 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#55f3e3"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M7 2v8h2a3 3 0 0 0 0-6V2zM6 7a3 3 0 0 0-6 0 3 3 0 0 0 6 0zm7-1v3a1 1 0 0 1-1 1h-1v2h1a3 3 0 0 0 3-3V6zM3 6a1 1 0 0 1 0 2 1 1 0 0 1 0-2zm6 0a1 1 0 0 1 0 2zm4-4h2v2h-2z" fill="#55f3e3"/></svg>
diff --git a/editor/icons/Nil.svg b/editor/icons/Nil.svg
index e4fbb90389..32a6ebcff3 100644
--- a/editor/icons/Nil.svg
+++ b/editor/icons/Nil.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2v2h2v-2zm4 0v5c0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228-.0000096-.99999-.44772-1-1v-5zm-11 2v6h2v-4h1c.55228.0000096.99999.44772 1 1v3h2v-3c0-1.6569-1.3431-3-3-3zm7 2v4h2v-4z" fill="#e0e0e0"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2v2h2V2zm3 0v5a3 3 0 0 0 3 3h1V8h-1a1 1 0 0 1-1-1V2zM1 4v6h2V6h1a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3zm7 2v4h2V6z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/NodePath.svg b/editor/icons/NodePath.svg
index 14c753a136..2d3153372f 100644
--- a/editor/icons/NodePath.svg
+++ b/editor/icons/NodePath.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2v-2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2zm5 0v8h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3v-2zm-9 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1z" fill="#417aec"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 2v8h2V8a3 3 0 0 0 0-6zm6 0v5a3 3 0 0 0 3 3h1V8H9a1 1 0 0 1-1-1V6h2V4H8V2zm5 0v8h2V6a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3V2zM2 4a1 1 0 0 1 0 2z" fill="#417aec"/></svg>
diff --git a/editor/icons/PackedByteArray.svg b/editor/icons/PackedByteArray.svg
index 448e25c478..d7fa7fcfc5 100644
--- a/editor/icons/PackedByteArray.svg
+++ b/editor/icons/PackedByteArray.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2h-2zm12 0v2h2v8h-2v2h4v-12h-2z" fill="#e0e0e0"/><path d="m5 3a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v4h2a3 3 0 0 0 1-.17578v.17578h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4h-2v3a1 1 0 0 1 -1 1v-4h-2z" fill="#5fff97"/><path d="m6 9v-6h2v4a1 1 0 0 0 1-1v-3h2v4a1 1 0 0 0 1-1v-3h2v3a3 3 0 0 1 -3 3h-2v-.1758a3 3 0 0 1 -1 .1758z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M5 3a3 3 0 0 0-3 3v3h2V6a1 1 0 0 1 1-1h1v4h2a3 3 0 0 0 1-.176V9h2a3 3 0 0 0 3-3V3h-2v3a1 1 0 0 1-1 1V3H9v3a1 1 0 0 1-1 1V3z" fill="#5fff97"/><path d="M6 9V3h2v4a1 1 0 0 0 1-1V3h2v4a1 1 0 0 0 1-1V3h2v3a3 3 0 0 1-3 3H9v-.176A3 3 0 0 1 8 9z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/PackedColorArray.svg b/editor/icons/PackedColorArray.svg
index 6911ff1d34..9f9616ea5c 100644
--- a/editor/icons/PackedColorArray.svg
+++ b/editor/icons/PackedColorArray.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 3.5a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2z" fill="#ff4545"/><path d="m13 3.5a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1z" fill="#45d7ff"/><path d="m7 1.5v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#80ff45"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M6 3.5a3 3 0 0 0 0 6h1v-2H6a1 1 0 0 1 0-2h1v-2z" fill="#ff4545"/><path d="M7 1.5v5a3 3 0 0 0 3 3v-2a1 1 0 0 1-1-1v-5z" fill="#80ff45"/><path d="M13 3.5a3 3 0 0 0-3 3v3h2v-3a1 1 0 0 1 1-1z" fill="#45d7ff"/></svg>
diff --git a/editor/icons/PackedFloat32Array.svg b/editor/icons/PackedFloat32Array.svg
index ccfbb748b7..da6433f909 100644
--- a/editor/icons/PackedFloat32Array.svg
+++ b/editor/icons/PackedFloat32Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1-1zm1 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm3 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#35d4f4"/><path d="m7 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M6 2a3 3 0 0 0-3 3v5h2V8h1V6H5V5a1 1 0 0 1 1-1zm1 0v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V2zm3 0v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2z" fill="#35d4f4"/><path d="M7 2v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V2z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/PackedFloat64Array.svg b/editor/icons/PackedFloat64Array.svg
index ccfbb748b7..da6433f909 100644
--- a/editor/icons/PackedFloat64Array.svg
+++ b/editor/icons/PackedFloat64Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m6 2a3 3 0 0 0 -3 3v5h2v-2h1v-2h-1v-1a1 1 0 0 1 1-1zm1 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm3 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#35d4f4"/><path d="m7 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M6 2a3 3 0 0 0-3 3v5h2V8h1V6H5V5a1 1 0 0 1 1-1zm1 0v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V2zm3 0v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2z" fill="#35d4f4"/><path d="M7 2v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V2z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/PackedInt32Array.svg b/editor/icons/PackedInt32Array.svg
index 973e4b9ab2..018fc23723 100644
--- a/editor/icons/PackedInt32Array.svg
+++ b/editor/icons/PackedInt32Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m3 2v2h2v-2zm2 2v2h-2v4h4v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#5abbef"/><path d="m5 4v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M3 2v2h2V2zm2 2v2H3v4h4V6a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3zm5 3a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2h-2z" fill="#5abbef"/><path d="M5 4v6h2V6a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/PackedInt64Array.svg b/editor/icons/PackedInt64Array.svg
index 973e4b9ab2..018fc23723 100644
--- a/editor/icons/PackedInt64Array.svg
+++ b/editor/icons/PackedInt64Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m3 2v2h2v-2zm2 2v2h-2v4h4v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#5abbef"/><path d="m5 4v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M3 2v2h2V2zm2 2v2H3v4h4V6a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3zm5 3a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2h-2z" fill="#5abbef"/><path d="M5 4v6h2V6a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/PackedStringArray.svg b/editor/icons/PackedStringArray.svg
index 5273d6bc56..7d4b685547 100644
--- a/editor/icons/PackedStringArray.svg
+++ b/editor/icons/PackedStringArray.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m7 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-2a1 1 0 0 1 1-1h1v3a3 3 0 0 0 3 3h2v-3a1 1 0 0 1 1-1v-2a3 3 0 0 0 -3 3v1a1 1 0 0 1 -1-1v-1h1v-2h-1v-2h-2z" fill="#4593ec"/><path d="m8 2v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M5 2a2.5 2.5 0 0 0 0 5 .5.5 0 0 1 0 1H2v2h3a2.5 2.5 0 0 0 0-5 .5.5 0 0 1 0-1h3v3a3 3 0 0 0 3 3h2V7a1 1 0 0 1 1-1V4a3 3 0 0 0-3 3v1a1 1 0 0 1-1-1V6h1V4h-1V2z" fill="#4593ec"/><path d="M8 2v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/PackedVector2Array.svg b/editor/icons/PackedVector2Array.svg
index f7e23b800f..bf502f4868 100644
--- a/editor/icons/PackedVector2Array.svg
+++ b/editor/icons/PackedVector2Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.0019531v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm-6 1v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4z" fill="#ac73f1"/><path d="m9 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.00195v2.0001h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5001z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M9 2v2h1a1 1 0 0 1 0 2 2 2 0 0 0-2 2v2h5V8h-3a3 3 0 0 0 0-6zM3 3v6h2a3 3 0 0 0 3-3V3H6v3a1 1 0 0 1-1 1V3z" fill="#ac73f1"/><path d="M9 2v2h1a1 1 0 0 1 0 2 2 2 0 0 0-2 2v2h5V8h-3a3 3 0 0 0 0-6z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/PackedVector3Array.svg b/editor/icons/PackedVector3Array.svg
index e78be63df2..9f4df41008 100644
--- a/editor/icons/PackedVector3Array.svg
+++ b/editor/icons/PackedVector3Array.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 0v12h4v-2h-2v-8h2v-2zm12 0v2h2v8h-2v2h4v-12z" fill="#e0e0e0"/><path d="m8 1v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44772 1-1 1h-1v2h1c1.0716-.0001501 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34772-.36523-.50195.13856-.15301.26095-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.003906v-2zm0 2h-2v3c-.0000096.55228-.44772.99999-1 1v-4h-2v6h2c1.6569 0 3-1.3431 3-3z" fill="#de66f0"/><path d="m8 1v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44772 1-1 1h-1v2h1c1.0716-.0001501 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34772-.36523-.50195.13856-.15301.26095-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.003906v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 0v12h4v-2H2V2h2V0zm12 0v2h2v8h-2v2h4V0z" fill="#e0e0e0"/><path d="M8 1v2h2a1 1 0 0 1-1 1v2a1 1 0 0 1 0 2H8v2h1a3 3 0 0 0 2.232-5A3 3 0 0 0 12 3V1zm0 2H6v3a1 1 0 0 1-1 1V3H3v6h2a3 3 0 0 0 3-3z" fill="#de66f0"/><path d="M8 1v2h2a1 1 0 0 1-1 1v2a1 1 0 0 1 0 2H8v2h1a3 3 0 0 0 2.232-5A3 3 0 0 0 12 3V1z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/Paint.svg b/editor/icons/Paint.svg
new file mode 100644
index 0000000000..eb0c621296
--- /dev/null
+++ b/editor/icons/Paint.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M2.92 10c-.263.3-.42.73-.42 1.238 0 1.628-3.138-.178-.337 2.67.884.9 2.654.67 3.538-.228a2.33 2.33 0 0 0 0-3.256c-1.1-1.119-2.2-1.084-2.78-.424zm2.3-1.64 2.4 2.4 6.8-6.8a1.7 1.7 0 0 0-2.4-2.45z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Plane.svg b/editor/icons/Plane.svg
index 5857ac56f7..eb3c5482a4 100644
--- a/editor/icons/Plane.svg
+++ b/editor/icons/Plane.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 2v8h2v-2a3 3 0 0 0 3-3 3 3 0 0 0 -3-3zm6 0v5a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-5zm-4 2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm8 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3z" fill="#f74949"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 2v8h2V8a3 3 0 0 0 0-6zm6 0v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V2zM3 4a1 1 0 0 1 0 2zm8 0v6h2V6a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3z" fill="#f74949"/></svg>
diff --git a/editor/icons/Projection.svg b/editor/icons/Projection.svg
index c6c9fed679..aa415cdedf 100644
--- a/editor/icons/Projection.svg
+++ b/editor/icons/Projection.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2v-2c.772 0 1.468-.3 2-.779v2.779h2v-3c0-.552.448-1 1-1h1v-2h-1c-.781 0-1.486.306-2.02.795-.107-1.56-1.393-2.795-2.98-2.795zm8 4v2c0 1 1 2 2 2h1c1 0 2-1 2-2v-2c0-1-1-2-2-2h-1c-1 0-2 1-2 2zm6-4v2h2v-2zm-12 2c.552 0 1 .448 1 1s-.448 1-1 1zm8 2h1v2h-1zm4 0v3c0 .552-.448 1-1 1h-1v2h1c1.657 0 3-1.343 3-3v-3z" fill="#44bd44"/><path d="m7 4c-1.657 0-3 1.343-3 3v3h2v-3c0-.552.448-1 1-1h1v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 2v8h2V8a3 3 0 0 0 2-.779V10h2V7a1 1 0 0 1 1-1h1V4H7a3 3 0 0 0-2.02.795A3 3 0 0 0 2 2zm8 4v2a2 2 0 0 0 2 2h1a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2h-1a2 2 0 0 0-2 2zm6-4v2h2V2zM2 4a1 1 0 0 1 0 2zm8 2h1v2h-1zm4 0v3a1 1 0 0 1-1 1h-1v2h1a3 3 0 0 0 3-3V6z" fill="#44bd44"/><path d="M7 4a3 3 0 0 0-3 3v3h2V7a1 1 0 0 1 1-1h1V4z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/Quaternion.svg b/editor/icons/Quaternion.svg
index cf29160ff4..39b4937420 100644
--- a/editor/icons/Quaternion.svg
+++ b/editor/icons/Quaternion.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 3a3 3 0 0 0 -3 3 3 3 0 0 0 3 3v2h2v-2.7695a3 3 0 0 0 2 .76953h2v-6h-2v4a1 1 0 0 1 -1-1v-3h-2zm0 2v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#ec418e"/><path d="m4 3v3a3 3 0 0 0 3 3h2v-6h-2v4a1 1 0 0 1 -1-1v-3z" fill="#fff" fill-opacity=".39216"/><path d="m13 1v2h-2a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-3a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-2 4v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#ec418e"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 3a3 3 0 0 0 0 6v2h2V8.236A3 3 0 0 0 7 9h2v-.764A3 3 0 0 0 11 9h2V6a3 3 0 0 0 3 3V7a1 1 0 0 1-1-1V5h1V3h-1V1h-2v2h-2a3 3 0 0 0-2 .764V3H7v4a1 1 0 0 1-1-1V3zm0 4a1 1 0 0 1 0-2zm8 0a1 1 0 0 1 0-2z" fill="#ec418e"/><path d="M4 3v3a3 3 0 0 0 3 3h2V3H7v4a1 1 0 0 1-1-1V3z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/RID.svg b/editor/icons/RID.svg
index 40764867ba..d24977463c 100644
--- a/editor/icons/RID.svg
+++ b/editor/icons/RID.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 2v2h2v-2zm7 0v2h-1a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1 2v-8zm-10 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2zm3 2v4h2v-4zm6 0h1v2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#41ec80"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M7 2v2h2V2zm7 0v2h-1a3 3 0 0 0 0 6h3V2zM4 4a3 3 0 0 0-3 3v3h2V7a1 1 0 0 1 1-1h1V4zm3 2v4h2V6zm6 0h1v2h-1a1 1 0 0 1 0-2z" fill="#41ec80"/></svg>
diff --git a/editor/icons/Rect2.svg b/editor/icons/Rect2.svg
index 5b069bd3c1..bdb70284ec 100644
--- a/editor/icons/Rect2.svg
+++ b/editor/icons/Rect2.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m13 2v2h-1a3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5-1.3457 3 3 0 0 0 -3 3 3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1h3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v1a3 3 0 0 0 3 3v-2a1 1 0 0 1 -1-1v-1h1v-2h-1v-2zm-10 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#f1738f"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M13 2v2h-1a3 3 0 0 0-2.5 1.346A3 3 0 1 0 7 10h1V8H7a1 1 0 0 1-1-1h3a3 3 0 0 0 3 3h1V8h-1a1 1 0 0 1 0-2h1v1a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2zM3 4a3 3 0 0 0-3 3v3h2V7a1 1 0 0 1 1-1h1V4z" fill="#f1738f"/></svg>
diff --git a/editor/icons/Rect2i.svg b/editor/icons/Rect2i.svg
index 76f4fededf..f091f6529e 100644
--- a/editor/icons/Rect2i.svg
+++ b/editor/icons/Rect2i.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m9 2v2h-1c-1.7267 0-3 1.3359-3 3 0 1.6569 1.3431 3 3 3h1v-2h-1c-.55228 0-1-.44772-1-1s.44772-1 1-1h1v1c0 1.6569 1.3431 3 3 3v-2c-.55228 0-.93526-.45152-1-1v-1h1v-2h-1v-2zm-5 2c-1.6569 0-2.9547 1.3438-3 3v3h2v-3c0-.55228.44772-1 1-1h1v-2z" fill="#f1738f"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#5abbef"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M9 2v2H8a3 3 0 0 0 0 6h1V8H8a1 1 0 0 1 0-2h1v1a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2zM4 4a3 3 0 0 0-3 3v3h2V7a1 1 0 0 1 1-1h1V4z" fill="#f1738f"/><path d="M13 2v2h2V2zm0 4v4h2V6z" fill="#5abbef"/></svg>
diff --git a/editor/icons/String.svg b/editor/icons/String.svg
index abcb92d4b2..0028973437 100644
--- a/editor/icons/String.svg
+++ b/editor/icons/String.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2a3 3 0 0 0 -3 3v2a1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 3-3v-2a1 1 0 0 1 1-1h1v-2zm2 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2zm8 2a3 3 0 0 0 -3 3v3h2v-3a1 1 0 0 1 1-1h1v-2z" fill="#4593ec"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M7 2H4a2.5 2.5 0 0 0 0 5 .5.5 0 0 1 0 1H1v2h3a2.5 2.5 0 0 0 0-5 .5.5 0 0 1 0-1h3zm1 0v5a3 3 0 0 0 3 3V8a1 1 0 0 1-1-1V6h1V4h-1V2zm4 8h2V7a1 1 0 0 1 1-1V4a3 3 0 0 0-3 3z" fill="#4593ec"/></svg>
diff --git a/editor/icons/StringName.svg b/editor/icons/StringName.svg
index 3b67f2accd..3520c20150 100644
--- a/editor/icons/StringName.svg
+++ b/editor/icons/StringName.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2c-1.6569 0-3 1.3431-3 3v2c0 .55228-.44772 1-1 1h-1v2h1c1.6569 0 3-1.3431 3-3v-2c0-.55228.44772-1 1-1h1v3c0 1.6569 1.3431 3 3 3h3v-4h1c.55228 0 1 .44772 1 1v3h2v-3c0-1.6569-1.3431-3-3-3h-5v-2zm3 4h2v2h-1c-.55228 0-1-.44772-1-1z" fill="#4593ec"/><path d="m10 4v6h2v-4h1c.55228 0 1 .44772 1 1v3h2v-3c0-1.6569-1.3431-3-3-3h-1z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 2a2.5 2.5 0 0 0 0 5 .5.5 0 0 1 0 1H0v2h3a2.5 2.5 0 0 0 0-5 .5.5 0 0 1 0-1h3v3a3 3 0 0 0 3 3h3V6a2 2 0 0 1 2 2v2h2V8a4 4 0 0 0-4-4H8V2zm7 4v2H9a1 1 0 0 1-1-1V6z" fill="#4593ec"/><path d="M6 2v5a3 3 0 0 0 3 3h1V8H9a1 1 0 0 1-1-1V6h2V4H8V2z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/TorusMesh.svg b/editor/icons/TorusMesh.svg
index c720b59aa5..adf3a8403b 100644
--- a/editor/icons/TorusMesh.svg
+++ b/editor/icons/TorusMesh.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><ellipse cx="8" cy="7.5" fill="none" rx="6" ry="3.5" stroke="#ffca5f" stroke-width="2"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><g fill="none" stroke="#ffca5f"><path d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z" stroke-width="2"/><path d="M6.2 7.2a2 1 0 1 0 3.6 0" stroke-width="1.75" stroke-linecap="round"/></g></svg>
diff --git a/editor/icons/Transform2D.svg b/editor/icons/Transform2D.svg
index 75be0b73e1..58e5621b33 100644
--- a/editor/icons/Transform2D.svg
+++ b/editor/icons/Transform2D.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v2h2v6h2v-6h2v-2zm7 0v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.0019531v2h7a4 4 0 0 0 3.4648-2 4 4 0 0 0 0-4 4 4 0 0 0 -3.4648-2h-2v6h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm5 2a2 2 0 0 1 1.7324 1 2 2 0 0 1 0 2 2 2 0 0 1 -1.7324 1z" fill="#b9ec41"/><path d="m7 2v2c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001326-1.3751.38108-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.0019531v2h5v-2h-3c1.0716-.00015 2.0618-.57193 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53582-.92807-1.526-1.4998-2.5977-1.5z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 2v2h2v6h2V4h3a1 1 0 0 1 0 2 2 2 0 0 0-2 2v2h7a4 4 0 0 0 0-8h-2v6H7a3 3 0 0 0 0-6zm12 2a2 2 0 0 1 0 4z" fill="#b9ec41"/><path d="M6.5 2v2H7a1 1 0 0 1 0 2 2 2 0 0 0-2 2v2h5V8H7a3 3 0 0 0 0-6h-.5z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/Transform3D.svg b/editor/icons/Transform3D.svg
index 10d2769d97..f07775446f 100644
--- a/editor/icons/Transform3D.svg
+++ b/editor/icons/Transform3D.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m4 4h3.349c0 .549-.451 1.267-1 1.267v1c.549 0 1 .326 1 .874 0 .549-.451.859-1 .859h-1v2h1c1.07 0 2.063-.573 2.598-1.5s.535-1.806 0-2.733c-.104-.18-.227-.348-.366-.502.139-.153.261-.32.366-.498.262-.457.398-.64.398-.767h.004v-2h-9.349v2h2v6h2zm6 6h2c1.428 0 2.751-.764 3.465-2 .713-1.236.713-2.764 0-4-.714-1.236-2.037-2-3.465-2h-2zm2-6c.714 0 1.376.382 1.732 1 .357.618.357 1.382 0 2-.356.618-1.018 1-1.732 1z" fill="#f68f45"/><path d="m6.00006 2v2h1.349c0 .549-.451 1.267-1 1.267v1c.549 0 1 .326 1 .874 0 .549-.451.859-1 .859h-1v2h1c1.07 0 2.062-.573 2.598-1.5.535-.927.535-1.806 0-2.733-.104-.18-.227-.348-.366-.502.139-.153.261-.32.366-.498.262-.457.398-.64.398-.767h.004v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M4 4h3.349a1 1.267 0 0 1-1 1.267v1a.866.866 0 0 1 0 1.732h-1v2h1a2.81 2.81 0 0 0 2.232-4.734A1.32 1.32 0 0 0 9.345 4V2H0v2h2v6h2zm6 6h2a4 4 0 0 0 0-8h-2zm2-6a2 2 0 0 1 0 4z" fill="#f68f45"/><path d="M5.5 4h1.849a1 1.267 0 0 1-1 1.267v1a.866.866 0 0 1 0 1.732h-1v2h1a2.81 2.81 0 0 0 2.232-4.734A1.32 1.32 0 0 0 9.345 4V2H5.5z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/Uv.svg b/editor/icons/Uv.svg
index 82c914c84f..be004249ec 100644
--- a/editor/icons/Uv.svg
+++ b/editor/icons/Uv.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m1 5v4a3 3 0 0 0 1.5 2.5977 3 3 0 0 0 3 0 3 3 0 0 0 1.5-2.5977v-4h-2v4a1 1 0 0 1 -1 1 1 1 0 0 1 -1-1v-4zm8 0 2 7h1 1 1l2-7h-2l-1.5 5.25-1.5-5.25z" fill="#e0e0e0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M1 5v4a3 3 0 0 0 6 0V5H5v4a1 1 0 0 1-2 0V5zm8 0 2 7h3l2-7h-2l-1.5 5.25L11 5z" fill="#e0e0e0"/></svg>
diff --git a/editor/icons/Variant.svg b/editor/icons/Variant.svg
index dff2c67ebc..c4e485d1e1 100644
--- a/editor/icons/Variant.svg
+++ b/editor/icons/Variant.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 4a3 3 0 0 0 -3 3 3 3 0 0 0 3 3h2v-6zm3 0v6h2v-4a1 1 0 0 1 1 1v3h2v-3a3 3 0 0 0 -3-3zm5 3a3 3 0 0 0 3 3v2h2v-8h-2v4a1 1 0 0 1 -1-1v-3h-2zm-8-1v2a1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#41ecad"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 3a3 3 0 0 0 0 6h2V3zm3 0v6h2V5a1 1 0 0 1 1 1v3h2V6a3 3 0 0 0-3-3zm5 2a3 3 0 0 0 3 3 1 1 0 0 1-1 1h-1v2h1a3 3 0 0 0 3-3V3h-2v3a1 1 0 0 1-1-1V3h-2zM3 7a1 1 0 0 1 0-2z" fill="#41ecad"/></svg>
diff --git a/editor/icons/Vector2.svg b/editor/icons/Vector2.svg
index 2bab922ca9..fd6ea7a5cf 100644
--- a/editor/icons/Vector2.svg
+++ b/editor/icons/Vector2.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.001953v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5zm-11 2v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#ac73f1"/><path d="m12 2v2h1a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 2 2 0 0 0 -1.7324 1 2 2 0 0 0 -.26562 1h-.001953v2h5v-2h-3a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -2.5977-1.5z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M12 2v2h1a1 1 0 0 1 0 2 2 2 0 0 0-2 2v2h5V8h-3a3 3 0 0 0 0-6zM1 4v6h2a3 3 0 0 0 3-3V4H4v3a1 1 0 0 1-1 1V4zm9 6V8H9a1 1 0 0 1 0-2h1V4H9a3 3 0 0 0 0 6z" fill="#ac73f1"/><path d="M12 2v2h1a1 1 0 0 1 0 2 2 2 0 0 0-2 2v2h5V8h-3a3 3 0 0 0 0-6z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/Vector2i.svg b/editor/icons/Vector2i.svg
index f2923542e8..5e82eb34d1 100644
--- a/editor/icons/Vector2i.svg
+++ b/editor/icons/Vector2i.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2v2h1c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001248-1.3751.38109-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.002v2h5v-2h-3c1.0717-.0001344 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53578-.92809-1.526-1.4999-2.5977-1.5zm-7 2v6h2c1.6569 0 3-1.3431 3-3v-3h-2v3c0 .55228-.44772 1-1 1v-4z" fill="#ac73f1"/><path d="m8 2v2h1c.55228 0 1 .44772 1 1s-.44772 1-1 1c-.71466-.0001248-1.3751.38109-1.7324 1-.17472.30426-.26633.64914-.26562 1h-.001953v2h5v-2h-3c1.0717-.0001344 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.53583-.92809-1.526-1.4999-2.5977-1.5z" fill="#fff" fill-opacity=".39216"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#5abbef"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2v2h1a1 1 0 0 1 0 2 2 2 0 0 0-2 2v2h5V8H9a3 3 0 0 0 0-6zM1 4v6h2a3 3 0 0 0 3-3V4H4v3a1 1 0 0 1-1 1V4z" fill="#ac73f1"/><path d="M8 2v2h1a1 1 0 0 1 0 2 2 2 0 0 0-2 2v2h5V8H9a3 3 0 0 0 0-6z" fill="#fff" fill-opacity=".4"/><path d="M13 2v2h2V2zm0 4v4h2V6z" fill="#5abbef"/></svg>
diff --git a/editor/icons/Vector3.svg b/editor/icons/Vector3.svg
index 85cac571cf..a78f8904d7 100644
--- a/editor/icons/Vector3.svg
+++ b/editor/icons/Vector3.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -.36523-.50195 3 3 0 0 0 .36523-.49805 3 3 0 0 0 .39844-1.5h.003906v-2zm-11 2v6h2a3 3 0 0 0 3-3v-3h-2v3a1 1 0 0 1 -1 1v-4zm5 3a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1 1 1 0 0 1 1-1h1v-2h-1a3 3 0 0 0 -3 3z" fill="#de66f0"/><path d="m12 2v2h2a1 1 0 0 1 -1 1v2a1 1 0 0 1 1 1 1 1 0 0 1 -1 1h-1v2h1a3 3 0 0 0 2.5977-1.5 3 3 0 0 0 0-3 3 3 0 0 0 -.36523-.50195 3 3 0 0 0 .36523-.49805 3 3 0 0 0 .39844-1.5h.003906v-2z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M11 2v2h2a1 1 0 0 1-1 1v2a1 1 0 0 1 0 2h-1v2h1a3 3 0 0 0 2.232-5A3 3 0 0 0 15 4V2zM1 4v6h2a3 3 0 0 0 3-3V4H4v3a1 1 0 0 1-1 1V4zm9 6V8H9a1 1 0 0 1 0-2h1V4H9a3 3 0 0 0 0 6z" fill="#de66f0"/><path d="M11 2v2h2a1 1 0 0 1-1 1v2a1 1 0 0 1 0 2h-1v2h1a3 3 0 0 0 2.232-5A3 3 0 0 0 15 4V2z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/Vector3i.svg b/editor/icons/Vector3i.svg
index 26e9c1b3ef..0f7dd4799c 100644
--- a/editor/icons/Vector3i.svg
+++ b/editor/icons/Vector3i.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m8 2v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.45296.92408-1 1h-1v2h1c1.0717-.000134 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34771-.36523-.50195.13855-.15301.26094-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.0039v-2zm-7 2v6h2c1.6569 0 3-1.3431 3-3v-3h-2v3c0 .55228-.44772 1-1 1v-4z" fill="#de66f0"/><path d="m8 2v2h2c0 .55228-.44772 1-1 1v2c.55228 0 1 .44772 1 1s-.44948.95585-1 1h-1v2h1c1.0717-.000134 2.0619-.57191 2.5977-1.5.5359-.9282.5359-2.0718 0-3-.10406-.1795-.22646-.34771-.36523-.50195.13855-.15301.26094-.31991.36523-.49805.26209-.45639.3995-.97371.39844-1.5h.0039v-2z" fill="#fff" fill-opacity=".39216"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#5abbef"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M8 2v2h2a1 1 0 0 1-1 1v2a1 1 0 0 1 0 2H8v2h1a3 3 0 0 0 2.232-5A3 3 0 0 0 12 4V2zM1 4v6h2a3 3 0 0 0 3-3V4H4v3a1 1 0 0 1-1 1V4z" fill="#de66f0"/><path d="M8 2v2h2a1 1 0 0 1-1 1v2a1 1 0 0 1 0 2H8v2h1a3 3 0 0 0 2.232-5A3 3 0 0 0 12 4V2z" fill="#fff" fill-opacity=".4"/><path d="M13 2v2h2V2zm0 4v4h2V6z" fill="#5abbef"/></svg>
diff --git a/editor/icons/Vector4.svg b/editor/icons/Vector4.svg
index 2eefa0a7e3..224d61e8e1 100644
--- a/editor/icons/Vector4.svg
+++ b/editor/icons/Vector4.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m11 3v5h3v3h2v-9h-2v4h-1v-3zm-10 1v6h2c1.646 0 3-1.354 3-3v-3h-2v3c0 .549-.451 1-1 1v-4zm5 3c0 1.646 1.354 3 3 3h1v-2h-1c-.549 0-1-.451-1-1s.451-1 1-1h1v-2h-1c-1.646 0-3 1.354-3 3z" fill="#f066bd"/><path d="m11 3v5h3v3h2v-9h-2v4h-1v-3z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M11 3v5h3v3h2V2h-2v4h-1V3zM1 4v6h2a3 3 0 0 0 3-3V4H4v3a1 1 0 0 1-1 1V4zm9 6V8H9a1 1 0 0 1 0-2h1V4H9a3 3 0 0 0 0 6z" fill="#f066bd"/><path d="M11 3v5h3v3h2V2h-2v4h-1V3z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/icons/Vector4i.svg b/editor/icons/Vector4i.svg
index d86cba253b..1bcedeccbb 100644
--- a/editor/icons/Vector4i.svg
+++ b/editor/icons/Vector4i.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 3v5h3v3h2v-9h-2v4h-1v-3zm-6 1v6h2c1.657 0 3-1.343 3-3v-3h-2v3c0 .552-.448 1-1 1v-4z" fill="#f066bd"/><path d="m7 3v5h3v3h2v-9h-2v4h-1v-3z" fill="#fff" fill-opacity=".39216"/><path d="m13 2v2h2v-2zm0 4v4h2v-4z" fill="#5abbef"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M7 3v5h3v3h2V2h-2v4H9V3zM1 4v6h2a3 3 0 0 0 3-3V4H4v3a1 1 0 0 1-1 1V4z" fill="#f066bd"/><path d="M7 3v5h3v3h2V2h-2v4H9V3z" fill="#fff" fill-opacity=".4"/><path d="M13 2v2h2V2zm0 4v4h2V6z" fill="#5abbef"/></svg>
diff --git a/editor/icons/bool.svg b/editor/icons/bool.svg
index 674cbc9e6c..4fd042bbc7 100644
--- a/editor/icons/bool.svg
+++ b/editor/icons/bool.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m0 2v8h2a3 3 0 0 0 2.5-1.3457 3 3 0 0 0 2.5 1.3457 3 3 0 0 0 2-.76758 3 3 0 0 0 2 .76758 3 3 0 0 0 2.5-1.3457 3 3 0 0 0 2.5 1.3457v-2a1 1 0 0 1 -1-1v-5h-2v2.7695a3 3 0 0 0 -2-.76953 3 3 0 0 0 -2 .76758 3 3 0 0 0 -2-.76758 3 3 0 0 0 -2.5 1.3457 3 3 0 0 0 -2.5-1.3457v-2zm2 4a1 1 0 0 1 1 1 1 1 0 0 1 -1 1zm5 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1zm4 0a1 1 0 0 1 1 1 1 1 0 0 1 -1 1 1 1 0 0 1 -1-1 1 1 0 0 1 1-1z" fill="#6f91f0"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M0 4v8h2a3 3 0 0 0 2.5-1.346 3 3 0 0 0 4.5.578 3 3 0 0 0 4.5-.578A3 3 0 0 0 16 12v-2a1 1 0 0 1-1-1V4h-2v2.77a3 3 0 0 0-4 0 3 3 0 0 0-4.5.578A3 3 0 0 0 2 6V4zm2 4a1 1 0 0 1 0 2zm5 0a1 1 0 0 1 0 2 1 1 0 0 1 0-2zm4 0a1 1 0 0 1 0 2 1 1 0 0 1 0-2z" fill="#6f91f0"/></svg>
diff --git a/editor/icons/float.svg b/editor/icons/float.svg
index b941332e6c..051234584d 100644
--- a/editor/icons/float.svg
+++ b/editor/icons/float.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m3 2a3 3 0 0 0 -3 3v5h2v-2h2v-2h-2v-1a1 1 0 0 1 1-1h1v-2zm3 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-5zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1 -1-1v-1h2v-2h-2v-2z" fill="#35d4f4"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M3 4a3 3 0 0 0-3 3v5h2v-2h2V8H2V7a1 1 0 0 1 1-1h1V4zm3 0v5a3 3 0 0 0 3 3h1v-2H9a1 1 0 0 1-1-1V4zm6 0v5a3 3 0 0 0 3 3h1v-2h-1a1 1 0 0 1-1-1V8h2V6h-2V4z" fill="#35d4f4"/></svg>
diff --git a/editor/icons/uint.svg b/editor/icons/uint.svg
index 7dd5a92925..1be22d7a2f 100644
--- a/editor/icons/uint.svg
+++ b/editor/icons/uint.svg
@@ -1 +1 @@
-<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m5 2v2h2v-2zm2 2v2h-2v-2h-2v4c-.5522847 0-1-.4477153-1-1v-3h-2v3a3 3 0 0 0 0 .0507812 3 3 0 0 0 3 2.9492188h6v-4c.5522847 0 1 .4477153 1 1v3h2v-3c0-1.6568542-1.343146-3-3-3zm5 3c0 1.6568542 1.343146 3 3 3h1v-2h-1c-.552285 0-1-.4477153-1-1v-1h2v-2h-2v-2h-2z" fill="#5abbef"/><path d="m5 10v-6h-2v4a1 1 0 0 1 -1-1v-3h-2v3a3 3 0 0 0 3 3z" fill="#fff" fill-opacity=".39216"/></svg>
+<svg height="12" viewBox="0 0 16 12" width="16" xmlns="http://www.w3.org/2000/svg"><path d="M5 2v2h2V2zm2 2v2H5V4H3v4a1 1 0 0 1-1-1V4H0v3a3 3 0 0 0 0 .05A3 3 0 0 0 3 10h6V6a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3zm5 3a3 3 0 0 0 3 3h1V8h-1a1 1 0 0 1-1-1V6h2V4h-2V2h-2z" fill="#5abbef"/><path d="M5 10V4H3v4a1 1 0 0 1-1-1V4H0v3a3 3 0 0 0 3 3zm2 0h2V6a1 1 0 0 1 1 1v3h2V7a3 3 0 0 0-3-3H7z" fill="#fff" fill-opacity=".4"/></svg>
diff --git a/editor/import/collada.cpp b/editor/import/collada.cpp
index a499fc4feb..d27b0aea40 100644
--- a/editor/import/collada.cpp
+++ b/editor/import/collada.cpp
@@ -2196,7 +2196,7 @@ bool Collada::_move_geometry_to_skeletons(VisualScene *p_vscene, Node *p_node, L
ERR_FAIL_COND_V(!state.scene_map.has(nodeid), false); //weird, it should have it...
NodeJoint *nj = dynamic_cast<NodeJoint *>(state.scene_map[nodeid]);
- ERR_FAIL_COND_V(!nj, false);
+ ERR_FAIL_NULL_V(nj, false);
ERR_FAIL_COND_V(!nj->owner, false); //weird, node should have a skeleton owner
NodeSkeleton *sk = nj->owner;
diff --git a/editor/import/editor_import_collada.cpp b/editor/import/editor_import_collada.cpp
index 5f714e4488..1e410b7272 100644
--- a/editor/import/editor_import_collada.cpp
+++ b/editor/import/editor_import_collada.cpp
@@ -208,7 +208,7 @@ Error ColladaImport::_create_scene(Collada::Node *p_node, Node3D *p_parent) {
return OK; //do nothing not needed
}
- if (!bool(GLOBAL_DEF("collada/use_ambient", false))) {
+ if (!bool(GLOBAL_GET("collada/use_ambient"))) {
return OK;
}
//well, it's an ambient light..
@@ -1107,7 +1107,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
ImporterMeshInstance3D *mi = Object::cast_to<ImporterMeshInstance3D>(node);
- ERR_FAIL_COND_V(!mi, ERR_BUG);
+ ERR_FAIL_NULL_V(mi, ERR_BUG);
Collada::SkinControllerData *skin = nullptr;
Collada::MorphControllerData *morph = nullptr;
@@ -1131,7 +1131,7 @@ Error ColladaImport::_create_resources(Collada::Node *p_node, bool p_use_compres
ERR_FAIL_COND_V(!node_map.has(skname), ERR_INVALID_DATA);
NodeMap nmsk = node_map[skname];
Skeleton3D *sk = Object::cast_to<Skeleton3D>(nmsk.node);
- ERR_FAIL_COND_V(!sk, ERR_INVALID_DATA);
+ ERR_FAIL_NULL_V(sk, ERR_INVALID_DATA);
ERR_FAIL_COND_V(!skeleton_bone_map.has(sk), ERR_INVALID_DATA);
HashMap<String, int> &bone_remap_map = skeleton_bone_map[sk];
diff --git a/editor/import/resource_importer_scene.cpp b/editor/import/resource_importer_scene.cpp
index c70918e55e..6996280477 100644
--- a/editor/import/resource_importer_scene.cpp
+++ b/editor/import/resource_importer_scene.cpp
@@ -155,11 +155,11 @@ Variant EditorScenePostImportPlugin::get_option_value(const StringName &p_name)
return Variant();
}
void EditorScenePostImportPlugin::add_import_option(const String &p_name, Variant p_default_value) {
- ERR_FAIL_COND_MSG(current_option_list == nullptr, "add_import_option() can only be called from get_import_options()");
+ ERR_FAIL_NULL_MSG(current_option_list, "add_import_option() can only be called from get_import_options().");
add_import_option_advanced(p_default_value.get_type(), p_name, p_default_value);
}
void EditorScenePostImportPlugin::add_import_option_advanced(Variant::Type p_type, const String &p_name, Variant p_default_value, PropertyHint p_hint, const String &p_hint_string, int p_usage_flags) {
- ERR_FAIL_COND_MSG(current_option_list == nullptr, "add_import_option_advanced() can only be called from get_import_options()");
+ ERR_FAIL_NULL_MSG(current_option_list, "add_import_option_advanced() can only be called from get_import_options().");
current_option_list->push_back(ResourceImporter::ImportOption(PropertyInfo(p_type, p_name, p_hint, p_hint_string, p_usage_flags), p_default_value));
}
@@ -356,7 +356,7 @@ static String _fixstr(const String &p_what, const String &p_str) {
}
static void _pre_gen_shape_list(Ref<ImporterMesh> &mesh, Vector<Ref<Shape3D>> &r_shape_list, bool p_convex) {
- ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value");
+ ERR_FAIL_NULL_MSG(mesh, "Cannot generate shape list with null mesh value.");
if (!p_convex) {
Ref<ConcavePolygonShape3D> shape = mesh->create_trimesh_shape();
r_shape_list.push_back(shape);
@@ -2143,7 +2143,7 @@ void ResourceImporterScene::_optimize_track_usage(AnimationPlayer *p_player, Ani
List<StringName> anims;
p_player->get_animation_list(&anims);
Node *parent = p_player->get_parent();
- ERR_FAIL_COND(parent == nullptr);
+ ERR_FAIL_NULL(parent);
HashMap<NodePath, uint32_t> used_tracks[TRACK_CHANNEL_MAX];
bool tracks_to_add = false;
static const Animation::TrackType track_types[TRACK_CHANNEL_MAX] = { Animation::TYPE_POSITION_3D, Animation::TYPE_ROTATION_3D, Animation::TYPE_SCALE_3D, Animation::TYPE_BLEND_SHAPE };
@@ -2727,7 +2727,7 @@ Node *EditorSceneFormatImporterESCN::import_scene(const String &p_path, uint32_t
}
}
- ERR_FAIL_COND_V(!scene, nullptr);
+ ERR_FAIL_NULL_V(scene, nullptr);
return scene;
}
diff --git a/editor/import_dock.cpp b/editor/import_dock.cpp
index 614047296a..d13c0e7f86 100644
--- a/editor/import_dock.cpp
+++ b/editor/import_dock.cpp
@@ -709,7 +709,7 @@ ImportDock::ImportDock() {
content->hide();
imported = memnew(Label);
- imported->add_theme_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("normal"), SNAME("LineEdit")));
+ imported->add_theme_style_override("normal", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("normal"), SNAME("LineEdit")));
imported->set_clip_text(true);
content->add_child(imported);
HBoxContainer *hb = memnew(HBoxContainer);
diff --git a/editor/inspector_dock.cpp b/editor/inspector_dock.cpp
index ac06841b30..044ac52147 100644
--- a/editor/inspector_dock.cpp
+++ b/editor/inspector_dock.cpp
@@ -205,7 +205,7 @@ void InspectorDock::_menu_option_confirm(int p_option, bool p_confirmed) {
default: {
if (p_option >= OBJECT_METHOD_BASE) {
- ERR_FAIL_COND(!current);
+ ERR_FAIL_NULL(current);
int idx = p_option - OBJECT_METHOD_BASE;
@@ -373,7 +373,7 @@ void InspectorDock::_resource_created() {
ERR_FAIL_COND(!c);
Resource *r = Object::cast_to<Resource>(c);
- ERR_FAIL_COND(!r);
+ ERR_FAIL_NULL(r);
EditorNode::get_singleton()->push_item(r);
}
diff --git a/editor/localization_editor.cpp b/editor/localization_editor.cpp
index d4154d371b..fb34740318 100644
--- a/editor/localization_editor.cpp
+++ b/editor/localization_editor.cpp
@@ -101,7 +101,7 @@ void LocalizationEditor::_translation_delete(Object *p_item, int p_column, int p
}
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
- ERR_FAIL_COND(!ti);
+ ERR_FAIL_NULL(ti);
int idx = ti->get_metadata(0);
@@ -163,7 +163,7 @@ void LocalizationEditor::_translation_res_option_add(const PackedStringArray &p_
Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
- ERR_FAIL_COND(!k);
+ ERR_FAIL_NULL(k);
String key = k->get_metadata(0);
@@ -194,7 +194,7 @@ void LocalizationEditor::_translation_res_select() {
void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) {
TreeItem *ed = translation_remap_options->get_edited();
- ERR_FAIL_COND(!ed);
+ ERR_FAIL_NULL(ed);
locale_select->set_locale(ed->get_tooltip_text(1));
locale_select->popup_locale_dialog();
@@ -202,7 +202,7 @@ void LocalizationEditor::_translation_res_option_popup(bool p_arrow_clicked) {
void LocalizationEditor::_translation_res_option_selected(const String &p_locale) {
TreeItem *ed = translation_remap_options->get_edited();
- ERR_FAIL_COND(!ed);
+ ERR_FAIL_NULL(ed);
ed->set_text(1, TranslationServer::get_singleton()->get_locale_name(p_locale));
ed->set_tooltip_text(1, p_locale);
@@ -222,9 +222,9 @@ void LocalizationEditor::_translation_res_option_changed() {
Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
- ERR_FAIL_COND(!k);
+ ERR_FAIL_NULL(k);
TreeItem *ed = translation_remap_options->get_edited();
- ERR_FAIL_COND(!ed);
+ ERR_FAIL_NULL(ed);
String key = k->get_metadata(0);
int idx = ed->get_metadata(0);
@@ -299,9 +299,9 @@ void LocalizationEditor::_translation_res_option_delete(Object *p_item, int p_co
Dictionary remaps = GLOBAL_GET("internationalization/locale/translation_remaps");
TreeItem *k = translation_remap->get_selected();
- ERR_FAIL_COND(!k);
+ ERR_FAIL_NULL(k);
TreeItem *ed = Object::cast_to<TreeItem>(p_item);
- ERR_FAIL_COND(!ed);
+ ERR_FAIL_NULL(ed);
String key = k->get_metadata(0);
int idx = ed->get_metadata(0);
@@ -348,7 +348,7 @@ void LocalizationEditor::_pot_delete(Object *p_item, int p_column, int p_button,
}
TreeItem *ti = Object::cast_to<TreeItem>(p_item);
- ERR_FAIL_COND(!ti);
+ ERR_FAIL_NULL(ti);
int idx = ti->get_metadata(0);
diff --git a/editor/plugins/abstract_polygon_2d_editor.cpp b/editor/plugins/abstract_polygon_2d_editor.cpp
index 86653f8775..fd5ebc423e 100644
--- a/editor/plugins/abstract_polygon_2d_editor.cpp
+++ b/editor/plugins/abstract_polygon_2d_editor.cpp
@@ -285,7 +285,7 @@ bool AbstractPolygon2DEditor::forward_gui_input(const Ref<InputEvent> &p_event)
if (mode == MODE_EDIT || (_is_line() && mode == MODE_CREATE)) {
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
- if (mb->is_ctrl_pressed() || mb->is_shift_pressed() || mb->is_alt_pressed()) {
+ if (mb->is_meta_pressed() || mb->is_ctrl_pressed() || mb->is_shift_pressed() || mb->is_alt_pressed()) {
return false;
}
@@ -725,7 +725,6 @@ AbstractPolygon2DEditor::AbstractPolygon2DEditor(bool p_wip_destructive) {
selected_point = Vertex();
edge_point = PosVertex();
- add_child(memnew(VSeparator));
button_create = memnew(Button);
button_create->set_flat(true);
add_child(button_create);
diff --git a/editor/plugins/animation_blend_space_1d_editor.cpp b/editor/plugins/animation_blend_space_1d_editor.cpp
index 373a927ef9..58eec1fa1e 100644
--- a/editor/plugins/animation_blend_space_1d_editor.cpp
+++ b/editor/plugins/animation_blend_space_1d_editor.cpp
@@ -423,9 +423,9 @@ void AnimationNodeBlendSpace1DEditor::_add_menu_type(int p_index) {
String type = menu->get_item_metadata(p_index);
Object *obj = ClassDB::instantiate(type);
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
- ERR_FAIL_COND(!an);
+ ERR_FAIL_NULL(an);
node = Ref<AnimationNode>(an);
}
diff --git a/editor/plugins/animation_blend_space_2d_editor.cpp b/editor/plugins/animation_blend_space_2d_editor.cpp
index cd69e90660..7971fbf6d6 100644
--- a/editor/plugins/animation_blend_space_2d_editor.cpp
+++ b/editor/plugins/animation_blend_space_2d_editor.cpp
@@ -349,9 +349,9 @@ void AnimationNodeBlendSpace2DEditor::_add_menu_type(int p_index) {
String type = menu->get_item_metadata(p_index);
Object *obj = ClassDB::instantiate(type);
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
- ERR_FAIL_COND(!an);
+ ERR_FAIL_NULL(an);
node = Ref<AnimationNode>(an);
}
diff --git a/editor/plugins/animation_blend_tree_editor_plugin.cpp b/editor/plugins/animation_blend_tree_editor_plugin.cpp
index ac3be4ba84..f28c989ac1 100644
--- a/editor/plugins/animation_blend_tree_editor_plugin.cpp
+++ b/editor/plugins/animation_blend_tree_editor_plugin.cpp
@@ -106,7 +106,7 @@ void AnimationNodeBlendTreeEditor::_property_changed(const StringName &p_propert
}
updating = true;
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- undo_redo->create_action(TTR("Parameter Changed:") + " " + String(p_property), UndoRedo::MERGE_ENDS);
+ undo_redo->create_action(vformat(TTR("Parameter Changed: %s"), 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));
undo_redo->add_do_method(this, "update_graph");
@@ -325,14 +325,14 @@ void AnimationNodeBlendTreeEditor::_add_node(int p_idx) {
base_name = anode->get_class();
} else if (!add_options[p_idx].type.is_empty()) {
AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(add_options[p_idx].type));
- ERR_FAIL_COND(!an);
+ ERR_FAIL_NULL(an);
anode = Ref<AnimationNode>(an);
base_name = add_options[p_idx].name;
} else {
ERR_FAIL_COND(add_options[p_idx].script.is_null());
StringName base_type = add_options[p_idx].script->get_instance_base_type();
AnimationNode *an = Object::cast_to<AnimationNode>(ClassDB::instantiate(base_type));
- ERR_FAIL_COND(!an);
+ ERR_FAIL_NULL(an);
anode = Ref<AnimationNode>(an);
anode->set_script(add_options[p_idx].script);
base_name = add_options[p_idx].name;
@@ -568,7 +568,7 @@ void AnimationNodeBlendTreeEditor::_node_selected(Object *p_node) {
}
GraphNode *gn = Object::cast_to<GraphNode>(p_node);
- ERR_FAIL_COND(!gn);
+ ERR_FAIL_NULL(gn);
String name = gn->get_name();
@@ -598,7 +598,7 @@ void AnimationNodeBlendTreeEditor::_filter_toggled() {
void AnimationNodeBlendTreeEditor::_filter_edited() {
TreeItem *edited = filters->get_edited();
- ERR_FAIL_COND(!edited);
+ ERR_FAIL_NULL(edited);
NodePath edited_path = edited->get_metadata(0);
bool filtered = edited->is_checked(0);
@@ -966,7 +966,7 @@ void AnimationNodeBlendTreeEditor::_node_renamed(const String &p_text, Ref<Anima
String prev_name = blend_tree->get_node_name(p_node);
ERR_FAIL_COND(prev_name.is_empty());
GraphNode *gn = Object::cast_to<GraphNode>(graph->get_node(prev_name));
- ERR_FAIL_COND(!gn);
+ ERR_FAIL_NULL(gn);
const String &new_name = p_text;
diff --git a/editor/plugins/animation_library_editor.cpp b/editor/plugins/animation_library_editor.cpp
index f658b2d5e6..6a54bc654f 100644
--- a/editor/plugins/animation_library_editor.cpp
+++ b/editor/plugins/animation_library_editor.cpp
@@ -621,7 +621,7 @@ void AnimationLibraryEditor::update_tree() {
}
tree->clear();
- ERR_FAIL_COND(!player);
+ ERR_FAIL_NULL(player);
Color ss_color = get_theme_color(SNAME("prop_subsection"), EditorStringName(Editor));
diff --git a/editor/plugins/animation_player_editor_plugin.cpp b/editor/plugins/animation_player_editor_plugin.cpp
index 59e114fe45..05e189290d 100644
--- a/editor/plugins/animation_player_editor_plugin.cpp
+++ b/editor/plugins/animation_player_editor_plugin.cpp
@@ -111,11 +111,11 @@ void AnimationPlayerEditor::_notification(int p_what) {
get_tree()->connect("node_removed", callable_mp(this, &AnimationPlayerEditor::_node_removed));
- add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
+ add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("panel"), SNAME("Panel")));
} break;
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
+ add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("panel"), SNAME("Panel")));
} break;
case NOTIFICATION_TRANSLATION_CHANGED:
@@ -2013,7 +2013,7 @@ bool EditorInspectorPluginAnimationTrackKeyEdit::can_handle(Object *p_object) {
void EditorInspectorPluginAnimationTrackKeyEdit::parse_begin(Object *p_object) {
AnimationTrackKeyEdit *atk = Object::cast_to<AnimationTrackKeyEdit>(p_object);
- ERR_FAIL_COND(!atk);
+ ERR_FAIL_NULL(atk);
atk_editor = memnew(AnimationTrackKeyEditEditor(atk->animation, atk->track, atk->key_ofs, atk->use_fps));
add_custom_control(atk_editor);
diff --git a/editor/plugins/animation_state_machine_editor.cpp b/editor/plugins/animation_state_machine_editor.cpp
index 5e40a2f986..a16d689e3d 100644
--- a/editor/plugins/animation_state_machine_editor.cpp
+++ b/editor/plugins/animation_state_machine_editor.cpp
@@ -158,7 +158,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
}
// Select node or push a field inside
- if (mb.is_valid() && !mb->is_shift_pressed() && !mb->is_ctrl_pressed() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
+ if (mb.is_valid() && !mb->is_shift_pressed() && !mb->is_command_or_control_pressed() && mb->is_pressed() && tool_select->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
selected_transition_from = StringName();
selected_transition_to = StringName();
selected_transition_index = -1;
@@ -337,7 +337,7 @@ void AnimationNodeStateMachineEditor::_state_machine_gui_input(const Ref<InputEv
ABS(box_selecting_from.x - box_selecting_to.x),
ABS(box_selecting_from.y - box_selecting_to.y));
- if (mb->is_ctrl_pressed() || mb->is_shift_pressed()) {
+ if (mb->is_command_or_control_pressed() || mb->is_shift_pressed()) {
previous_selected = selected_nodes;
} else {
selected_nodes.clear();
@@ -708,9 +708,9 @@ void AnimationNodeStateMachineEditor::_add_menu_type(int p_index) {
String type = menu->get_item_metadata(p_index);
Object *obj = ClassDB::instantiate(type);
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
AnimationNode *an = Object::cast_to<AnimationNode>(obj);
- ERR_FAIL_COND(!an);
+ ERR_FAIL_NULL(an);
node = Ref<AnimationNode>(an);
base_name = type.replace_first("AnimationNode", "");
diff --git a/editor/plugins/asset_library_editor_plugin.cpp b/editor/plugins/asset_library_editor_plugin.cpp
index ae9497116d..5c08263099 100644
--- a/editor/plugins/asset_library_editor_plugin.cpp
+++ b/editor/plugins/asset_library_editor_plugin.cpp
@@ -661,7 +661,7 @@ void EditorAssetLibrary::shortcut_input(const Ref<InputEvent> &p_event) {
}
void EditorAssetLibrary::_install_asset() {
- ERR_FAIL_COND(!description);
+ ERR_FAIL_NULL(description);
EditorAssetLibraryItemDownload *d = _get_asset_in_progress(description->get_asset_id());
if (d) {
diff --git a/editor/plugins/canvas_item_editor_plugin.cpp b/editor/plugins/canvas_item_editor_plugin.cpp
index 703cd7ef81..f62eaee96e 100644
--- a/editor/plugins/canvas_item_editor_plugin.cpp
+++ b/editor/plugins/canvas_item_editor_plugin.cpp
@@ -78,7 +78,8 @@ class SnapDialog : public ConfirmationDialog {
SpinBox *grid_offset_y;
SpinBox *grid_step_x;
SpinBox *grid_step_y;
- SpinBox *primary_grid_steps;
+ SpinBox *primary_grid_step_x;
+ SpinBox *primary_grid_step_y;
SpinBox *rotation_offset;
SpinBox *rotation_step;
SpinBox *scale_step;
@@ -151,24 +152,30 @@ public:
grid_step_y->set_select_all_on_focus(true);
child_container->add_child(grid_step_y);
- child_container = memnew(GridContainer);
- child_container->set_columns(2);
- container->add_child(child_container);
-
label = memnew(Label);
label->set_text(TTR("Primary Line Every:"));
label->set_h_size_flags(Control::SIZE_EXPAND_FILL);
child_container->add_child(label);
- primary_grid_steps = memnew(SpinBox);
- primary_grid_steps->set_min(0);
- primary_grid_steps->set_step(1);
- primary_grid_steps->set_max(100);
- primary_grid_steps->set_allow_greater(true);
- primary_grid_steps->set_suffix(TTR("steps"));
- primary_grid_steps->set_h_size_flags(Control::SIZE_EXPAND_FILL);
- primary_grid_steps->set_select_all_on_focus(true);
- child_container->add_child(primary_grid_steps);
+ primary_grid_step_x = memnew(SpinBox);
+ primary_grid_step_x->set_min(1);
+ primary_grid_step_x->set_step(1);
+ primary_grid_step_x->set_max(SPIN_BOX_GRID_RANGE);
+ primary_grid_step_x->set_allow_greater(true);
+ primary_grid_step_x->set_suffix("steps");
+ primary_grid_step_x->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ primary_grid_step_x->set_select_all_on_focus(true);
+ child_container->add_child(primary_grid_step_x);
+
+ primary_grid_step_y = memnew(SpinBox);
+ primary_grid_step_y->set_min(1);
+ primary_grid_step_y->set_step(1);
+ primary_grid_step_y->set_max(SPIN_BOX_GRID_RANGE);
+ primary_grid_step_y->set_allow_greater(true);
+ primary_grid_step_y->set_suffix("steps");
+ primary_grid_step_y->set_h_size_flags(Control::SIZE_EXPAND_FILL);
+ primary_grid_step_y->set_select_all_on_focus(true);
+ child_container->add_child(primary_grid_step_y);
container->add_child(memnew(HSeparator));
@@ -224,21 +231,22 @@ public:
child_container->add_child(scale_step);
}
- void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const int p_primary_grid_steps, const real_t p_rotation_offset, const real_t p_rotation_step, const real_t p_scale_step) {
+ void set_fields(const Point2 p_grid_offset, const Point2 p_grid_step, const Vector2i p_primary_grid_step, const real_t p_rotation_offset, const real_t p_rotation_step, const real_t p_scale_step) {
grid_offset_x->set_value(p_grid_offset.x);
grid_offset_y->set_value(p_grid_offset.y);
grid_step_x->set_value(p_grid_step.x);
grid_step_y->set_value(p_grid_step.y);
- primary_grid_steps->set_value(p_primary_grid_steps);
+ primary_grid_step_x->set_value(p_primary_grid_step.x);
+ primary_grid_step_y->set_value(p_primary_grid_step.y);
rotation_offset->set_value(Math::rad_to_deg(p_rotation_offset));
rotation_step->set_value(Math::rad_to_deg(p_rotation_step));
scale_step->set_value(p_scale_step);
}
- void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, int &p_primary_grid_steps, real_t &p_rotation_offset, real_t &p_rotation_step, real_t &p_scale_step) {
+ void get_fields(Point2 &p_grid_offset, Point2 &p_grid_step, Vector2i &p_primary_grid_step, real_t &p_rotation_offset, real_t &p_rotation_step, real_t &p_scale_step) {
p_grid_offset = Point2(grid_offset_x->get_value(), grid_offset_y->get_value());
p_grid_step = Point2(grid_step_x->get_value(), grid_step_y->get_value());
- p_primary_grid_steps = int(primary_grid_steps->get_value());
+ p_primary_grid_step = Vector2i(primary_grid_step_x->get_value(), primary_grid_step_y->get_value());
p_rotation_offset = Math::deg_to_rad(rotation_offset->get_value());
p_rotation_step = Math::deg_to_rad(rotation_step->get_value());
p_scale_step = scale_step->get_value();
@@ -346,7 +354,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
snap_target[0] = SNAP_TARGET_NONE;
snap_target[1] = SNAP_TARGET_NONE;
- bool is_snap_active = smart_snap_active ^ Input::get_singleton()->is_key_pressed(Key::CTRL);
+ bool is_snap_active = smart_snap_active ^ Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
// Smart snap using the canvas position
Vector2 output = p_target;
@@ -472,7 +480,7 @@ Point2 CanvasItemEditor::snap_point(Point2 p_target, unsigned int p_modes, unsig
}
real_t CanvasItemEditor::snap_angle(real_t p_target, real_t p_start) const {
- if (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(Key::CTRL)) && snap_rotation_step != 0) {
+ if (((smart_snap_active || snap_rotation) ^ Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) && snap_rotation_step != 0) {
if (snap_relative) {
return Math::snapped(p_target - snap_rotation_offset, snap_rotation_step) + snap_rotation_offset + (p_start - (int)(p_start / snap_rotation_step) * snap_rotation_step);
} else {
@@ -497,7 +505,7 @@ void CanvasItemEditor::shortcut_input(const Ref<InputEvent> &p_ev) {
viewport->queue_redraw();
}
- if (k->is_pressed() && !k->is_ctrl_pressed() && !k->is_echo() && (grid_snap_active || _is_grid_visible())) {
+ if (k->is_pressed() && !k->is_command_or_control_pressed() && !k->is_echo() && (grid_snap_active || _is_grid_visible())) {
if (multiply_grid_step_shortcut.is_valid() && multiply_grid_step_shortcut->matches_event(p_ev)) {
// Multiply the grid size
grid_step_multiplier = MIN(grid_step_multiplier + 1, 12);
@@ -800,7 +808,7 @@ List<CanvasItem *> CanvasItemEditor::_get_edited_canvas_items(bool retrieve_lock
}
Vector2 CanvasItemEditor::_anchor_to_position(const Control *p_control, Vector2 anchor) {
- ERR_FAIL_COND_V(!p_control, Vector2());
+ ERR_FAIL_NULL_V(p_control, Vector2());
Transform2D parent_transform = p_control->get_transform().affine_inverse();
Rect2 parent_rect = p_control->get_parent_anchorable_rect();
@@ -813,7 +821,7 @@ Vector2 CanvasItemEditor::_anchor_to_position(const Control *p_control, Vector2
}
Vector2 CanvasItemEditor::_position_to_anchor(const Control *p_control, Vector2 position) {
- ERR_FAIL_COND_V(!p_control, Vector2());
+ ERR_FAIL_NULL_V(p_control, Vector2());
Rect2 parent_rect = p_control->get_parent_anchorable_rect();
@@ -894,11 +902,11 @@ void CanvasItemEditor::_commit_canvas_item_state(List<CanvasItem *> p_canvas_ite
}
void CanvasItemEditor::_snap_changed() {
- static_cast<SnapDialog *>(snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
+ static_cast<SnapDialog *>(snap_dialog)->get_fields(grid_offset, grid_step, primary_grid_step, snap_rotation_offset, snap_rotation_step, snap_scale_step);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "grid_offset", grid_offset);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "grid_step", grid_step);
- EditorSettings::get_singleton()->set_project_metadata("2d_editor", "primary_grid_steps", primary_grid_steps);
+ EditorSettings::get_singleton()->set_project_metadata("2d_editor", "primary_grid_step", primary_grid_step);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "snap_rotation_offset", snap_rotation_offset);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "snap_rotation_step", snap_rotation_step);
EditorSettings::get_singleton()->set_project_metadata("2d_editor", "snap_scale_step", snap_scale_step);
@@ -1916,7 +1924,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 = m->is_ctrl_pressed();
+ bool is_ctrl = m->is_command_or_control_pressed();
Point2 drag_from_local = simple_xform.xform(drag_from);
Point2 drag_to_local = simple_xform.xform(drag_to);
@@ -2048,27 +2056,31 @@ bool CanvasItemEditor::_gui_input_move(const Ref<InputEvent> &p_event) {
if (drag_type == DRAG_MOVE || drag_type == DRAG_MOVE_X || drag_type == DRAG_MOVE_Y) {
// Move the nodes
- if (m.is_valid()) {
+ if (m.is_valid() && !drag_selection.is_empty()) {
_restore_canvas_item_state(drag_selection, true);
drag_to = transform.affine_inverse().xform(m->get_position());
Point2 previous_pos;
- if (!drag_selection.is_empty()) {
- if (drag_selection.size() == 1) {
- Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse();
- previous_pos = xform.xform(drag_selection[0]->_edit_get_position());
- } else {
- previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
- }
+ if (drag_selection.size() == 1) {
+ Transform2D xform = drag_selection[0]->get_global_transform_with_canvas() * drag_selection[0]->get_transform().affine_inverse();
+ previous_pos = xform.xform(drag_selection[0]->_edit_get_position());
+ } else {
+ previous_pos = _get_encompassing_rect_from_list(drag_selection).position;
}
- Point2 new_pos = snap_point(previous_pos + (drag_to - drag_from), SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, nullptr, drag_selection);
+ Point2 drag_delta = drag_to - drag_from;
+ if (drag_selection.size() == 1 && (drag_type == DRAG_MOVE_X || drag_type == DRAG_MOVE_Y)) {
+ const CanvasItem *selected = drag_selection.front()->get();
+ drag_delta = selected->get_transform().affine_inverse().basis_xform(drag_delta);
- if (drag_type == DRAG_MOVE_X) {
- new_pos.y = previous_pos.y;
- } else if (drag_type == DRAG_MOVE_Y) {
- new_pos.x = previous_pos.x;
+ if (drag_type == DRAG_MOVE_X) {
+ drag_delta.y = 0;
+ } else {
+ drag_delta.x = 0;
+ }
+ drag_delta = selected->get_transform().basis_xform(drag_delta);
}
+ Point2 new_pos = snap_point(previous_pos + drag_delta, SNAP_GRID | SNAP_GUIDES | SNAP_PIXEL | SNAP_NODE_PARENT | SNAP_NODE_ANCHORS | SNAP_OTHER_NODES, 0, nullptr, drag_selection);
bool single_axis = m->is_shift_pressed();
if (single_axis) {
@@ -2925,10 +2937,10 @@ void CanvasItemEditor::_draw_grid() {
if (last_cell != cell) {
Color grid_color;
- if (primary_grid_steps == 0) {
+ if (primary_grid_step.x <= 1) {
grid_color = secondary_grid_color;
} else {
- grid_color = cell % primary_grid_steps == 0 ? primary_grid_color : secondary_grid_color;
+ grid_color = cell % primary_grid_step.x == 0 ? primary_grid_color : secondary_grid_color;
}
viewport->draw_line(Point2(i, 0), Point2(i, viewport_size.height), grid_color, Math::round(EDSCALE));
@@ -2948,10 +2960,10 @@ void CanvasItemEditor::_draw_grid() {
if (last_cell != cell) {
Color grid_color;
- if (primary_grid_steps == 0) {
+ if (primary_grid_step.y <= 1) {
grid_color = secondary_grid_color;
} else {
- grid_color = cell % primary_grid_steps == 0 ? primary_grid_color : secondary_grid_color;
+ grid_color = cell % primary_grid_step.y == 0 ? primary_grid_color : secondary_grid_color;
}
viewport->draw_line(Point2(0, i), Point2(viewport_size.width, i), grid_color, Math::round(EDSCALE));
@@ -3600,7 +3612,7 @@ void CanvasItemEditor::_draw_axis() {
}
void CanvasItemEditor::_draw_invisible_nodes_positions(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
- ERR_FAIL_COND(!p_node);
+ ERR_FAIL_NULL(p_node);
Node *scene = EditorNode::get_singleton()->get_edited_scene();
if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) {
@@ -3731,7 +3743,7 @@ void CanvasItemEditor::_draw_transform_message() {
}
void CanvasItemEditor::_draw_locks_and_groups(Node *p_node, const Transform2D &p_parent_xform, const Transform2D &p_canvas_xform) {
- ERR_FAIL_COND(!p_node);
+ ERR_FAIL_NULL(p_node);
Node *scene = EditorNode::get_singleton()->get_edited_scene();
if (p_node != scene && p_node->get_owner() != scene && !scene->is_editable_instance(p_node->get_owner())) {
@@ -3888,7 +3900,7 @@ void CanvasItemEditor::_update_editor_settings() {
key_auto_insert_button->add_theme_color_override("icon_pressed_color", key_auto_color.lerp(Color(1, 0, 0), 0.55));
animation_menu->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
- context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles)));
+ context_toolbar_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles)));
panner->setup((ViewPanner::ControlScheme)EDITOR_GET("editors/panning/2d_editor_panning_scheme").operator int(), ED_GET_SHORTCUT("canvas_item_editor/pan_view"), bool(EDITOR_GET("editors/panning/simple_panning")));
panner->set_scroll_speed(EDITOR_GET("editors/panning/2d_editor_pan_speed"));
@@ -3983,7 +3995,7 @@ void CanvasItemEditor::_notification(int p_what) {
select_sb->set_texture_margin_all(4);
select_sb->set_content_margin_all(4);
- AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
+ AnimationPlayerEditor::get_singleton()->get_track_editor()->connect("keying_changed", callable_mp(this, &CanvasItemEditor::_keying_changed));
AnimationPlayerEditor::get_singleton()->connect("animation_selected", callable_mp(this, &CanvasItemEditor::_keying_changed).unbind(1));
_keying_changed();
_update_editor_settings();
@@ -4341,8 +4353,8 @@ void CanvasItemEditor::_popup_callback(int p_op) {
snap_config_menu->get_popup()->set_item_checked(idx, snap_pixel);
} break;
case SNAP_CONFIGURE: {
- static_cast<SnapDialog *>(snap_dialog)->set_fields(grid_offset, grid_step, primary_grid_steps, snap_rotation_offset, snap_rotation_step, snap_scale_step);
- snap_dialog->popup_centered(Size2(220, 160) * EDSCALE);
+ static_cast<SnapDialog *>(snap_dialog)->set_fields(grid_offset, grid_step, primary_grid_step, snap_rotation_offset, snap_rotation_step, snap_scale_step);
+ snap_dialog->popup_centered(Size2(320, 160) * EDSCALE);
} break;
case SKELETON_SHOW_BONES: {
List<Node *> selection = editor_selection->get_selected_node_list();
@@ -4728,7 +4740,7 @@ Dictionary CanvasItemEditor::get_state() const {
state["ofs"] = view_offset;
state["grid_offset"] = grid_offset;
state["grid_step"] = grid_step;
- state["primary_grid_steps"] = primary_grid_steps;
+ state["primary_grid_step"] = primary_grid_step;
state["snap_rotation_offset"] = snap_rotation_offset;
state["snap_rotation_step"] = snap_rotation_step;
state["snap_scale_step"] = snap_scale_step;
@@ -4780,8 +4792,15 @@ void CanvasItemEditor::set_state(const Dictionary &p_state) {
grid_step = state["grid_step"];
}
+#ifndef DISABLE_DEPRECATED
if (state.has("primary_grid_steps")) {
- primary_grid_steps = state["primary_grid_steps"];
+ primary_grid_step.x = state["primary_grid_steps"];
+ primary_grid_step.y = state["primary_grid_steps"];
+ }
+#endif // DISABLE_DEPRECATED
+
+ if (state.has("primary_grid_step")) {
+ primary_grid_step = state["primary_grid_step"];
}
if (state.has("snap_rotation_step")) {
@@ -4934,20 +4953,58 @@ void CanvasItemEditor::clear() {
grid_offset = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "grid_offset", Vector2());
grid_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "grid_step", Vector2(8, 8));
- primary_grid_steps = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "primary_grid_steps", 8);
+ primary_grid_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "primary_grid_step", Vector2i(8, 8));
snap_rotation_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_rotation_step", Math::deg_to_rad(15.0));
snap_rotation_offset = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_rotation_offset", 0.0);
snap_scale_step = EditorSettings::get_singleton()->get_project_metadata("2d_editor", "snap_scale_step", 0.1);
}
void CanvasItemEditor::add_control_to_menu_panel(Control *p_control) {
- ERR_FAIL_COND(!p_control);
+ ERR_FAIL_NULL(p_control);
+ ERR_FAIL_COND(p_control->get_parent());
+
+ VSeparator *sep = memnew(VSeparator);
+ context_toolbar_hbox->add_child(sep);
+ context_toolbar_hbox->add_child(p_control);
+ context_toolbar_separators[p_control] = sep;
- context_menu_hbox->add_child(p_control);
+ p_control->connect("visibility_changed", callable_mp(this, &CanvasItemEditor::_update_context_toolbar));
+
+ _update_context_toolbar();
}
void CanvasItemEditor::remove_control_from_menu_panel(Control *p_control) {
- context_menu_hbox->remove_child(p_control);
+ ERR_FAIL_NULL(p_control);
+ ERR_FAIL_COND(p_control->get_parent() != context_toolbar_hbox);
+
+ p_control->disconnect("visibility_changed", callable_mp(this, &CanvasItemEditor::_update_context_toolbar));
+
+ context_toolbar_hbox->remove_child(context_toolbar_separators[p_control]);
+ context_toolbar_hbox->remove_child(p_control);
+ context_toolbar_separators.erase(p_control);
+
+ _update_context_toolbar();
+}
+
+void CanvasItemEditor::_update_context_toolbar() {
+ bool has_visible = false;
+ bool first_visible = false;
+
+ for (int i = 0; i < context_toolbar_hbox->get_child_count(); i++) {
+ Control *child = Object::cast_to<Control>(context_toolbar_hbox->get_child(i));
+ if (!child || !context_toolbar_separators.has(child)) {
+ continue;
+ }
+ if (child->is_visible()) {
+ first_visible = !has_visible;
+ has_visible = true;
+ }
+
+ VSeparator *sep = context_toolbar_separators[child];
+ sep->set_visible(!first_visible && child->is_visible());
+ }
+
+ context_toolbar_panel->set_visible(has_visible);
}
void CanvasItemEditor::add_control_to_left_panel(Control *p_control) {
@@ -4997,9 +5054,17 @@ CanvasItemEditor::CanvasItemEditor() {
EditorRunBar::get_singleton()->call_deferred(SNAME("connect"), "play_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(true));
EditorRunBar::get_singleton()->call_deferred(SNAME("connect"), "stop_pressed", callable_mp(this, &CanvasItemEditor::_update_override_camera_button).bind(false));
+ // Add some margin to the sides for better esthetics.
+ // This prevents the first button's hover/pressed effect from "touching" the panel's border,
+ // which looks ugly.
+ MarginContainer *toolbar_margin = memnew(MarginContainer);
+ toolbar_margin->add_theme_constant_override("margin_left", 4 * EDSCALE);
+ toolbar_margin->add_theme_constant_override("margin_right", 4 * EDSCALE);
+ add_child(toolbar_margin);
+
// A fluid container for all toolbars.
HFlowContainer *main_flow = memnew(HFlowContainer);
- add_child(main_flow);
+ toolbar_margin->add_child(main_flow);
// Main toolbars.
HBoxContainer *main_menu_hbox = memnew(HBoxContainer);
@@ -5107,13 +5172,6 @@ CanvasItemEditor::CanvasItemEditor() {
viewport->add_child(controls_vb);
- // Add some margin to the left for better esthetics.
- // This prevents the first button's hover/pressed effect from "touching" the panel's border,
- // which looks ugly.
- Control *margin_left = memnew(Control);
- main_menu_hbox->add_child(margin_left);
- margin_left->set_custom_minimum_size(Size2(2, 0) * EDSCALE);
-
select_button = memnew(Button);
select_button->set_flat(true);
main_menu_hbox->add_child(select_button);
@@ -5355,15 +5413,14 @@ CanvasItemEditor::CanvasItemEditor() {
main_menu_hbox->add_child(memnew(VSeparator));
// Contextual toolbars.
- context_menu_panel = memnew(PanelContainer);
- context_menu_hbox = memnew(HBoxContainer);
- context_menu_panel->add_child(context_menu_hbox);
- main_flow->add_child(context_menu_panel);
+ context_toolbar_panel = memnew(PanelContainer);
+ context_toolbar_hbox = memnew(HBoxContainer);
+ context_toolbar_panel->add_child(context_toolbar_hbox);
+ main_flow->add_child(context_toolbar_panel);
// Animation controls.
animation_hb = memnew(HBoxContainer);
- context_menu_hbox->add_child(animation_hb);
- animation_hb->add_child(memnew(VSeparator));
+ add_control_to_menu_panel(animation_hb);
animation_hb->hide();
key_loc_button = memnew(Button);
@@ -5552,7 +5609,7 @@ void CanvasItemEditorViewport::_create_preview(const Vector<String> &files) cons
Ref<PackedScene> scene = Ref<PackedScene>(Object::cast_to<PackedScene>(*res));
if (texture != nullptr || scene != nullptr) {
bool root_node_selected = EditorNode::get_singleton()->get_editor_selection()->is_selected(EditorNode::get_singleton()->get_edited_scene());
- String desc = TTR("Drag and drop to add as child of current scene's root node.") + "\n" + TTR("Hold Ctrl when dropping to add as child of selected node.");
+ String desc = TTR("Drag and drop to add as child of current scene's root node.") + "\n" + vformat(TTR("Hold %s when dropping to add as child of selected node."), keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL));
if (!root_node_selected) {
desc += "\n" + TTR("Hold Shift when dropping to add as sibling of selected node.");
}
@@ -5856,7 +5913,7 @@ bool CanvasItemEditorViewport::_only_packed_scenes_selected() const {
void CanvasItemEditorViewport::drop_data(const Point2 &p_point, const Variant &p_data) {
bool is_shift = Input::get_singleton()->is_key_pressed(Key::SHIFT);
- 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);
selected_files.clear();
diff --git a/editor/plugins/canvas_item_editor_plugin.h b/editor/plugins/canvas_item_editor_plugin.h
index 674f38c8c0..9aac6e44df 100644
--- a/editor/plugins/canvas_item_editor_plugin.h
+++ b/editor/plugins/canvas_item_editor_plugin.h
@@ -48,6 +48,7 @@ class PanelContainer;
class StyleBoxTexture;
class ViewPanner;
class VScrollBar;
+class VSeparator;
class VSplitContainer;
class CanvasItemEditorSelectedItem : public Object {
@@ -192,10 +193,14 @@ private:
HScrollBar *h_scroll = nullptr;
VScrollBar *v_scroll = nullptr;
+
// Used for secondary menu items which are displayed depending on the currently selected node
// (such as MeshInstance's "Mesh" menu).
- PanelContainer *context_menu_panel = nullptr;
- HBoxContainer *context_menu_hbox = nullptr;
+ PanelContainer *context_toolbar_panel = nullptr;
+ HBoxContainer *context_toolbar_hbox = nullptr;
+ HashMap<Control *, VSeparator *> context_toolbar_separators;
+
+ void _update_context_toolbar();
Transform2D transform;
GridVisibility grid_visibility = GRID_VISIBILITY_SHOW_WHEN_SNAPPING;
@@ -216,7 +221,7 @@ private:
// Defaults are defined in clear().
Point2 grid_offset;
Point2 grid_step;
- int primary_grid_steps = 0;
+ Vector2i primary_grid_step;
int grid_step_multiplier = 0;
real_t snap_rotation_step = 0.0;
diff --git a/editor/plugins/control_editor_plugin.cpp b/editor/plugins/control_editor_plugin.cpp
index f1667d14ab..8401f6c0b6 100644
--- a/editor/plugins/control_editor_plugin.cpp
+++ b/editor/plugins/control_editor_plugin.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/gui/grid_container.h"
@@ -193,7 +194,7 @@ void EditorPropertyAnchorsPreset::setup(const Vector<String> &p_options) {
String preset_name = option_name.trim_prefix("Preset");
String humanized_name = preset_name.capitalize();
String icon_name = "ControlAlign" + preset_name;
- options->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(icon_name), humanized_name);
+ options->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(icon_name, EditorStringName(EditorIcons)), humanized_name);
} else {
options->add_item(option_name);
}
@@ -816,7 +817,7 @@ void ControlEditorToolbar::_container_flags_selected(int p_flags, bool p_vertica
}
Vector2 ControlEditorToolbar::_position_to_anchor(const Control *p_control, Vector2 position) {
- ERR_FAIL_COND_V(!p_control, Vector2());
+ ERR_FAIL_NULL_V(p_control, Vector2());
Rect2 parent_rect = p_control->get_parent_anchorable_rect();
@@ -976,8 +977,6 @@ void ControlEditorToolbar::_notification(int p_what) {
}
ControlEditorToolbar::ControlEditorToolbar() {
- add_child(memnew(VSeparator));
-
// Anchor and offset tools.
anchors_button = memnew(ControlEditorPopupButton);
anchors_button->set_tooltip_text(TTR("Presets for the anchor and offset values of a Control node."));
diff --git a/editor/plugins/cpu_particles_2d_editor_plugin.cpp b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
index 967ef3cb6b..f0fd40a77e 100644
--- a/editor/plugins/cpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/cpu_particles_2d_editor_plugin.cpp
@@ -267,8 +267,6 @@ CPUParticles2DEditorPlugin::CPUParticles2DEditorPlugin() {
add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
toolbar->hide();
- toolbar->add_child(memnew(VSeparator));
-
menu = memnew(MenuButton);
menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART);
menu->get_popup()->add_item(TTR("Load Emission Mask"), MENU_LOAD_EMISSION_MASK);
diff --git a/editor/plugins/curve_editor_plugin.cpp b/editor/plugins/curve_editor_plugin.cpp
index 468278bd27..37f0ca449d 100644
--- a/editor/plugins/curve_editor_plugin.cpp
+++ b/editor/plugins/curve_editor_plugin.cpp
@@ -225,7 +225,7 @@ void CurveEdit::gui_input(const Ref<InputEvent> &p_event) {
} else if (grabbing == GRAB_NONE) {
// Adding a new point. Insert a temporary point for the user to adjust, so it's not in the undo/redo.
Vector2 new_pos = get_world_pos(mpos).clamp(Vector2(0.0, curve->get_min_value()), Vector2(1.0, curve->get_max_value()));
- if (snap_enabled || mb->is_ctrl_pressed()) {
+ if (snap_enabled || mb->is_command_or_control_pressed()) {
new_pos.x = Math::snapped(new_pos.x, 1.0 / snap_count);
new_pos.y = Math::snapped(new_pos.y - curve->get_min_value(), curve->get_range() / snap_count) + curve->get_min_value();
}
@@ -276,7 +276,7 @@ void CurveEdit::gui_input(const Ref<InputEvent> &p_event) {
// Drag point.
Vector2 new_pos = get_world_pos(mpos).clamp(Vector2(0.0, curve->get_min_value()), Vector2(1.0, curve->get_max_value()));
- if (snap_enabled || mm->is_ctrl_pressed()) {
+ if (snap_enabled || mm->is_command_or_control_pressed()) {
new_pos.x = Math::snapped(new_pos.x, 1.0 / snap_count);
new_pos.y = Math::snapped(new_pos.y - curve->get_min_value(), curve->get_range() / snap_count) + curve->get_min_value();
}
@@ -1041,7 +1041,7 @@ bool EditorInspectorPluginCurve::can_handle(Object *p_object) {
void EditorInspectorPluginCurve::parse_begin(Object *p_object) {
Curve *curve = Object::cast_to<Curve>(p_object);
- ERR_FAIL_COND(!curve);
+ ERR_FAIL_NULL(curve);
Ref<Curve> c(curve);
CurveEditor *editor = memnew(CurveEditor);
diff --git a/editor/plugins/editor_debugger_plugin.cpp b/editor/plugins/editor_debugger_plugin.cpp
index eb1b2dcca7..9f495d5cd2 100644
--- a/editor/plugins/editor_debugger_plugin.cpp
+++ b/editor/plugins/editor_debugger_plugin.cpp
@@ -76,27 +76,27 @@ void EditorDebuggerSession::remove_session_tab(Control *p_tab) {
}
void EditorDebuggerSession::send_message(const String &p_message, const Array &p_args) {
- ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger");
+ ERR_FAIL_NULL_MSG(debugger, "Plugin is not attached to debugger.");
debugger->send_message(p_message, p_args);
}
void EditorDebuggerSession::toggle_profiler(const String &p_profiler, bool p_enable, const Array &p_data) {
- ERR_FAIL_COND_MSG(!debugger, "Plugin is not attached to debugger");
+ ERR_FAIL_NULL_MSG(debugger, "Plugin is not attached to debugger.");
debugger->toggle_profiler(p_profiler, p_enable, p_data);
}
bool EditorDebuggerSession::is_breaked() {
- ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ ERR_FAIL_NULL_V_MSG(debugger, false, "Plugin is not attached to debugger.");
return debugger->is_breaked();
}
bool EditorDebuggerSession::is_debuggable() {
- ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ ERR_FAIL_NULL_V_MSG(debugger, false, "Plugin is not attached to debugger.");
return debugger->is_debuggable();
}
bool EditorDebuggerSession::is_active() {
- ERR_FAIL_COND_V_MSG(!debugger, false, "Plugin is not attached to debugger");
+ ERR_FAIL_NULL_V_MSG(debugger, false, "Plugin is not attached to debugger.");
return debugger->is_session_active();
}
@@ -121,7 +121,7 @@ void EditorDebuggerSession::_debugger_gone_away() {
}
EditorDebuggerSession::EditorDebuggerSession(ScriptEditorDebugger *p_debugger) {
- ERR_FAIL_COND(!p_debugger);
+ ERR_FAIL_NULL(p_debugger);
debugger = p_debugger;
debugger->connect("started", callable_mp(this, &EditorDebuggerSession::_started));
debugger->connect("stopped", callable_mp(this, &EditorDebuggerSession::_stopped));
diff --git a/editor/plugins/font_config_plugin.cpp b/editor/plugins/font_config_plugin.cpp
index 5dd5de224f..6de2549059 100644
--- a/editor/plugins/font_config_plugin.cpp
+++ b/editor/plugins/font_config_plugin.cpp
@@ -970,7 +970,7 @@ bool EditorInspectorPluginFontPreview::can_handle(Object *p_object) {
void EditorInspectorPluginFontPreview::parse_begin(Object *p_object) {
Font *fd = Object::cast_to<Font>(p_object);
- ERR_FAIL_COND(!fd);
+ ERR_FAIL_NULL(fd);
FontPreview *editor = memnew(FontPreview);
editor->set_data(fd);
diff --git a/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp
index 894047c524..56a3cb488b 100644
--- a/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/audio_listener_3d_gizmo_plugin.cpp
@@ -30,11 +30,13 @@
#include "audio_listener_3d_gizmo_plugin.h"
+#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/audio_listener_3d.h"
AudioListener3DGizmoPlugin::AudioListener3DGizmoPlugin() {
- create_icon_material("audio_listener_3d_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoAudioListener3D")));
+ create_icon_material("audio_listener_3d_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoAudioListener3D"), EditorStringName(EditorIcons)));
}
bool AudioListener3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
diff --git a/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp
index ad40af7784..cda00b9543 100644
--- a/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/audio_stream_player_3d_gizmo_plugin.cpp
@@ -30,7 +30,9 @@
#include "audio_stream_player_3d_gizmo_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/audio_stream_player_3d.h"
@@ -38,7 +40,7 @@
AudioStreamPlayer3DGizmoPlugin::AudioStreamPlayer3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/stream_player_3d", Color(0.4, 0.8, 1));
- create_icon_material("stream_player_3d_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("Gizmo3DSamplePlayer")));
+ create_icon_material("stream_player_3d_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Gizmo3DSamplePlayer"), EditorStringName(EditorIcons)));
create_material("stream_player_3d_material_primary", gizmo_color);
create_material("stream_player_3d_material_secondary", gizmo_color * Color(1, 1, 1, 0.35));
// Enable vertex colors for the billboard material as the gizmo color depends on the
@@ -121,136 +123,137 @@ void AudioStreamPlayer3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gi
}
void AudioStreamPlayer3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- const AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_node_3d());
-
p_gizmo->clear();
- const Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo);
-
- if (player->get_attenuation_model() != AudioStreamPlayer3D::ATTENUATION_DISABLED || player->get_max_distance() > CMP_EPSILON) {
- // Draw a circle to represent sound volume attenuation.
- // Use only a billboard circle to represent radius.
- // This helps distinguish AudioStreamPlayer3D gizmos from OmniLight3D gizmos.
- const Ref<Material> lines_billboard_material = get_material("stream_player_3d_material_billboard", p_gizmo);
-
- // Soft distance cap varies depending on attenuation model, as some will fade out more aggressively than others.
- // Multipliers were empirically determined through testing.
- float soft_multiplier;
- switch (player->get_attenuation_model()) {
- case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE:
- soft_multiplier = 12.0;
- break;
- case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE:
- soft_multiplier = 4.0;
- break;
- case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC:
- soft_multiplier = 3.25;
- break;
- default:
- // Ensures Max Distance's radius visualization is not capped by Unit Size
- // (when the attenuation mode is Disabled).
- soft_multiplier = 10000.0;
- break;
- }
-
- // Draw the distance at which the sound can be reasonably heard.
- // This can be either a hard distance cap with the Max Distance property (if set above 0.0),
- // or a soft distance cap with the Unit Size property (sound never reaches true zero).
- // When Max Distance is 0.0, `r` represents the distance above which the
- // sound can't be heard in *most* (but not all) scenarios.
- float r;
- if (player->get_max_distance() > CMP_EPSILON) {
- r = MIN(player->get_unit_size() * soft_multiplier, player->get_max_distance());
- } else {
- r = player->get_unit_size() * soft_multiplier;
- }
- Vector<Vector3> points_billboard;
-
- for (int i = 0; i < 120; i++) {
- // Create a circle.
- const float ra = Math::deg_to_rad((float)(i * 3));
- const float rb = Math::deg_to_rad((float)((i + 1) * 3));
- const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
- const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
-
- // Draw a billboarded circle.
- points_billboard.push_back(Vector3(a.x, a.y, 0));
- points_billboard.push_back(Vector3(b.x, b.y, 0));
- }
-
- Color color;
- switch (player->get_attenuation_model()) {
- // Pick cold colors for all attenuation models (except Disabled),
- // so that soft caps can be easily distinguished from hard caps
- // (which use warm colors).
- case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE:
- color = Color(0.4, 0.8, 1);
- break;
- case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE:
- color = Color(0.4, 0.5, 1);
- break;
- case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC:
- color = Color(0.4, 0.2, 1);
- break;
- default:
- // Disabled attenuation mode.
- // This is never reached when Max Distance is 0, but the
- // hue-inverted form of this color will be used if Max Distance is greater than 0.
- color = Color(1, 1, 1);
- break;
+ if (p_gizmo->is_selected()) {
+ const AudioStreamPlayer3D *player = Object::cast_to<AudioStreamPlayer3D>(p_gizmo->get_node_3d());
+
+ if (player->get_attenuation_model() != AudioStreamPlayer3D::ATTENUATION_DISABLED || player->get_max_distance() > CMP_EPSILON) {
+ // Draw a circle to represent sound volume attenuation.
+ // Use only a billboard circle to represent radius.
+ // This helps distinguish AudioStreamPlayer3D gizmos from OmniLight3D gizmos.
+ const Ref<Material> lines_billboard_material = get_material("stream_player_3d_material_billboard", p_gizmo);
+
+ // Soft distance cap varies depending on attenuation model, as some will fade out more aggressively than others.
+ // Multipliers were empirically determined through testing.
+ float soft_multiplier;
+ switch (player->get_attenuation_model()) {
+ case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE:
+ soft_multiplier = 12.0;
+ break;
+ case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE:
+ soft_multiplier = 4.0;
+ break;
+ case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC:
+ soft_multiplier = 3.25;
+ break;
+ default:
+ // Ensures Max Distance's radius visualization is not capped by Unit Size
+ // (when the attenuation mode is Disabled).
+ soft_multiplier = 10000.0;
+ break;
+ }
+
+ // Draw the distance at which the sound can be reasonably heard.
+ // This can be either a hard distance cap with the Max Distance property (if set above 0.0),
+ // or a soft distance cap with the Unit Size property (sound never reaches true zero).
+ // When Max Distance is 0.0, `r` represents the distance above which the
+ // sound can't be heard in *most* (but not all) scenarios.
+ float r;
+ if (player->get_max_distance() > CMP_EPSILON) {
+ r = MIN(player->get_unit_size() * soft_multiplier, player->get_max_distance());
+ } else {
+ r = player->get_unit_size() * soft_multiplier;
+ }
+ Vector<Vector3> points_billboard;
+
+ for (int i = 0; i < 120; i++) {
+ // Create a circle.
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+ // Draw a billboarded circle.
+ points_billboard.push_back(Vector3(a.x, a.y, 0));
+ points_billboard.push_back(Vector3(b.x, b.y, 0));
+ }
+
+ Color color;
+ switch (player->get_attenuation_model()) {
+ // Pick cold colors for all attenuation models (except Disabled),
+ // so that soft caps can be easily distinguished from hard caps
+ // (which use warm colors).
+ case AudioStreamPlayer3D::ATTENUATION_INVERSE_DISTANCE:
+ color = Color(0.4, 0.8, 1);
+ break;
+ case AudioStreamPlayer3D::ATTENUATION_INVERSE_SQUARE_DISTANCE:
+ color = Color(0.4, 0.5, 1);
+ break;
+ case AudioStreamPlayer3D::ATTENUATION_LOGARITHMIC:
+ color = Color(0.4, 0.2, 1);
+ break;
+ default:
+ // Disabled attenuation mode.
+ // This is never reached when Max Distance is 0, but the
+ // hue-inverted form of this color will be used if Max Distance is greater than 0.
+ color = Color(1, 1, 1);
+ break;
+ }
+
+ if (player->get_max_distance() > CMP_EPSILON) {
+ // Sound is hard-capped by max distance. The attenuation model still matters,
+ // so invert the hue of the color that was chosen above.
+ color.set_h(color.get_h() + 0.5);
+ }
+
+ p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color);
}
- if (player->get_max_distance() > CMP_EPSILON) {
- // Sound is hard-capped by max distance. The attenuation model still matters,
- // so invert the hue of the color that was chosen above.
- color.set_h(color.get_h() + 0.5);
- }
+ if (player->is_emission_angle_enabled()) {
+ const float pc = player->get_emission_angle();
+ const float ofs = -Math::cos(Math::deg_to_rad(pc));
+ const float radius = Math::sin(Math::deg_to_rad(pc));
- p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color);
- }
+ Vector<Vector3> points_primary;
+ points_primary.resize(200);
- if (player->is_emission_angle_enabled()) {
- const float pc = player->get_emission_angle();
- const float ofs = -Math::cos(Math::deg_to_rad(pc));
- const float radius = Math::sin(Math::deg_to_rad(pc));
+ real_t step = Math_TAU / 100.0;
+ for (int i = 0; i < 100; i++) {
+ const float a = i * step;
+ const float an = (i + 1) * step;
- Vector<Vector3> points_primary;
- points_primary.resize(200);
+ const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs);
+ const Vector3 to(Math::sin(an) * radius, Math::cos(an) * radius, ofs);
- real_t step = Math_TAU / 100.0;
- for (int i = 0; i < 100; i++) {
- const float a = i * step;
- const float an = (i + 1) * step;
+ points_primary.write[i * 2 + 0] = from;
+ points_primary.write[i * 2 + 1] = to;
+ }
- const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs);
- const Vector3 to(Math::sin(an) * radius, Math::cos(an) * radius, ofs);
+ const Ref<Material> material_primary = get_material("stream_player_3d_material_primary", p_gizmo);
+ p_gizmo->add_lines(points_primary, material_primary);
- points_primary.write[i * 2 + 0] = from;
- points_primary.write[i * 2 + 1] = to;
- }
+ Vector<Vector3> points_secondary;
+ points_secondary.resize(16);
- const Ref<Material> material_primary = get_material("stream_player_3d_material_primary", p_gizmo);
- p_gizmo->add_lines(points_primary, material_primary);
+ for (int i = 0; i < 8; i++) {
+ const float a = i * (Math_TAU / 8.0);
+ const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs);
- Vector<Vector3> points_secondary;
- points_secondary.resize(16);
+ points_secondary.write[i * 2 + 0] = from;
+ points_secondary.write[i * 2 + 1] = Vector3();
+ }
- for (int i = 0; i < 8; i++) {
- const float a = i * (Math_TAU / 8.0);
- const Vector3 from(Math::sin(a) * radius, Math::cos(a) * radius, ofs);
+ const Ref<Material> material_secondary = get_material("stream_player_3d_material_secondary", p_gizmo);
+ p_gizmo->add_lines(points_secondary, material_secondary);
- points_secondary.write[i * 2 + 0] = from;
- points_secondary.write[i * 2 + 1] = Vector3();
+ Vector<Vector3> handles;
+ const float ha = Math::deg_to_rad(player->get_emission_angle());
+ handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha)));
+ p_gizmo->add_handles(handles, get_material("handles"));
}
-
- const Ref<Material> material_secondary = get_material("stream_player_3d_material_secondary", p_gizmo);
- p_gizmo->add_lines(points_secondary, material_secondary);
-
- Vector<Vector3> handles;
- const float ha = Math::deg_to_rad(player->get_emission_angle());
- handles.push_back(Vector3(Math::sin(ha), 0, -Math::cos(ha)));
- p_gizmo->add_handles(handles, get_material("handles"));
}
+ const Ref<Material> icon = get_material("stream_player_3d_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05);
}
diff --git a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp
index b0fc5d1ec0..af7874e4da 100644
--- a/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/camera_3d_gizmo_plugin.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
@@ -41,7 +42,7 @@ Camera3DGizmoPlugin::Camera3DGizmoPlugin() {
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/camera", Color(0.8, 0.4, 0.8));
create_material("camera_material", gizmo_color);
- create_icon_material("camera_icon", Node3DEditor::get_singleton()->get_editor_theme_icon("GizmoCamera3D"));
+ create_icon_material("camera_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoCamera3D"), EditorStringName(EditorIcons)));
create_handle_material("handles");
}
diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
index 3becc9c9fd..2695253b78 100644
--- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.cpp
@@ -34,6 +34,7 @@
#include "core/math/geometry_3d.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/gizmos/gizmo_3d_helper.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/collision_shape_3d.h"
#include "scene/resources/box_shape_3d.h"
@@ -47,6 +48,7 @@
#include "scene/resources/world_boundary_shape_3d.h"
CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() {
+ helper.instantiate();
const Color gizmo_color = EDITOR_GET("editors/3d_gizmos/gizmo_colors/shape");
create_material("shape_material", gizmo_color);
const float gizmo_value = gizmo_color.get_v();
@@ -55,6 +57,9 @@ CollisionShape3DGizmoPlugin::CollisionShape3DGizmoPlugin() {
create_handle_material("handles");
}
+CollisionShape3DGizmoPlugin::~CollisionShape3DGizmoPlugin() {
+}
+
bool CollisionShape3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<CollisionShape3D>(p_spatial) != nullptr;
}
@@ -80,7 +85,7 @@ String CollisionShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_g
}
if (Object::cast_to<BoxShape3D>(*s)) {
- return "Size";
+ return helper->box_get_handle_name(p_id);
}
if (Object::cast_to<CapsuleShape3D>(*s)) {
@@ -135,8 +140,7 @@ Variant CollisionShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p
}
void CollisionShape3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
- initial_transform = p_gizmo->get_node_3d()->get_global_transform();
- initial_value = get_handle_value(p_gizmo, p_id, p_secondary);
+ helper->initialize_handle_action(get_handle_value(p_gizmo, p_id, p_secondary), p_gizmo->get_node_3d()->get_global_transform());
}
void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
@@ -147,13 +151,8 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
return;
}
- Transform3D gt = initial_transform;
- Transform3D gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+ Vector3 sg[2];
+ helper->get_segment(p_camera, p_point, sg);
if (Object::cast_to<SphereShape3D>(*s)) {
Ref<SphereShape3D> ss = s;
@@ -188,38 +187,12 @@ void CollisionShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, i
}
if (Object::cast_to<BoxShape3D>(*s)) {
- Vector3 axis;
- axis[p_id / 2] = 1.0;
Ref<BoxShape3D> bs = s;
- Vector3 ra, rb;
- int sign = p_id % 2 * -2 + 1;
- Vector3 initial_size = initial_value;
-
- Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096 * sign, sg[0], sg[1], ra, rb);
- if (ra[p_id / 2] == 0) {
- // Point before half of the shape. Needs to be calculated in opposite direction.
- Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096 * -sign, sg[0], sg[1], ra, rb);
- }
-
- float d = ra[p_id / 2] * sign;
-
- Vector3 he = bs->get_size();
- he[p_id / 2] = d * 2;
- if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- he[p_id / 2] = Math::snapped(he[p_id / 2], Node3DEditor::get_singleton()->get_translate_snap());
- }
-
- if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
- he[p_id / 2] = MAX(he[p_id / 2], 0.001);
- bs->set_size(he);
- cs->set_global_position(initial_transform.get_origin());
- } else {
- he[p_id / 2] = MAX(he[p_id / 2], -initial_size[p_id / 2] + 0.002);
- bs->set_size((initial_size + (he - initial_size) * 0.5).abs());
- Vector3 pos = initial_transform.affine_inverse().xform(initial_transform.get_origin());
- pos += (bs->get_size() - initial_size) * 0.5 * sign;
- cs->set_global_position(initial_transform.xform(pos));
- }
+ Vector3 size = bs->get_size();
+ Vector3 position;
+ helper->box_set_handle(sg, p_id, size, position);
+ bs->set_size(size);
+ cs->set_global_position(position);
}
if (Object::cast_to<CapsuleShape3D>(*s)) {
@@ -291,20 +264,7 @@ void CollisionShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo
}
if (Object::cast_to<BoxShape3D>(*s)) {
- Ref<BoxShape3D> ss = s;
- if (p_cancel) {
- cs->set_global_position(initial_transform.get_origin());
- ss->set_size(p_restore);
- return;
- }
-
- 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_do_method(cs, "set_global_position", cs->get_global_position());
- ur->add_undo_method(ss.ptr(), "set_size", p_restore);
- ur->add_undo_method(cs, "set_global_position", initial_transform.get_origin());
- ur->commit_action();
+ helper->box_commit_handle(TTR("Change Box Shape Size"), p_cancel, cs, s.ptr());
}
if (Object::cast_to<CapsuleShape3D>(*s)) {
@@ -446,14 +406,7 @@ void CollisionShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
lines.push_back(b);
}
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
- Vector3 ax;
- ax[i] = bs->get_size()[i] / 2;
- handles.push_back(ax);
- handles.push_back(-ax);
- }
+ const Vector<Vector3> handles = helper->box_get_handles(bs->get_size());
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
diff --git a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h
index 6b7740de2f..464012acf9 100644
--- a/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h
+++ b/editor/plugins/gizmos/collision_shape_3d_gizmo_plugin.h
@@ -33,11 +33,12 @@
#include "editor/plugins/node_3d_editor_gizmos.h"
+class Gizmo3DHelper;
+
class CollisionShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CollisionShape3DGizmoPlugin, EditorNode3DGizmoPlugin);
- Transform3D initial_transform;
- Variant initial_value;
+ Ref<Gizmo3DHelper> helper;
public:
bool has_gizmo(Node3D *p_spatial) override;
@@ -52,6 +53,7 @@ public:
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
CollisionShape3DGizmoPlugin();
+ ~CollisionShape3DGizmoPlugin();
};
#endif // COLLISION_SHAPE_3D_GIZMO_PLUGIN_H
diff --git a/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp
index e00b5349d2..3745b407a3 100644
--- a/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/cpu_particles_3d_gizmo_plugin.cpp
@@ -30,11 +30,13 @@
#include "cpu_particles_3d_gizmo_plugin.h"
+#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/cpu_particles_3d.h"
CPUParticles3DGizmoPlugin::CPUParticles3DGizmoPlugin() {
- create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoCPUParticles3D")));
+ create_icon_material("particles_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoCPUParticles3D"), EditorStringName(EditorIcons)));
}
bool CPUParticles3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
diff --git a/editor/plugins/gizmos/decal_gizmo_plugin.cpp b/editor/plugins/gizmos/decal_gizmo_plugin.cpp
index b439598ef4..7572e1dcd5 100644
--- a/editor/plugins/gizmos/decal_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/decal_gizmo_plugin.cpp
@@ -30,19 +30,28 @@
#include "decal_gizmo_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/gizmos/gizmo_3d_helper.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/decal.h"
DecalGizmoPlugin::DecalGizmoPlugin() {
+ helper.instantiate();
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/decal", Color(0.6, 0.5, 1.0));
+ create_icon_material("decal_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoDecal"), EditorStringName(EditorIcons)));
+
create_material("decal_material", gizmo_color);
create_handle_material("handles");
}
+DecalGizmoPlugin::~DecalGizmoPlugin() {
+}
+
bool DecalGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<Decal>(p_spatial) != nullptr;
}
@@ -56,16 +65,7 @@ int DecalGizmoPlugin::get_priority() const {
}
String DecalGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- switch (p_id) {
- case 0:
- return "Size X";
- case 1:
- return "Size Y";
- case 2:
- return "Size Z";
- }
-
- return "";
+ return helper->box_get_handle_name(p_id);
}
Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
@@ -73,52 +73,25 @@ Variant DecalGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int
return decal->get_size();
}
+void DecalGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
+ helper->initialize_handle_action(get_handle_value(p_gizmo, p_id, p_secondary), p_gizmo->get_node_3d()->get_global_transform());
+}
+
void DecalGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
Decal *decal = Object::cast_to<Decal>(p_gizmo->get_node_3d());
- Transform3D gt = decal->get_global_transform();
-
- Transform3D gi = gt.affine_inverse();
-
Vector3 size = decal->get_size();
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+ Vector3 sg[2];
+ helper->get_segment(p_camera, p_point, sg);
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_id] = 1.0;
-
- Vector3 ra, rb;
- Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_id] * 2;
- if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001) {
- d = 0.001;
- }
-
- size[p_id] = d;
+ Vector3 position;
+ helper->box_set_handle(sg, p_id, size, position);
decal->set_size(size);
+ decal->set_global_position(position);
}
void DecalGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- Decal *decal = Object::cast_to<Decal>(p_gizmo->get_node_3d());
-
- Vector3 restore = p_restore;
-
- if (p_cancel) {
- decal->set_size(restore);
- return;
- }
-
- EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Decal Size"));
- ur->add_do_method(decal, "set_size", decal->get_size());
- ur->add_undo_method(decal, "set_size", restore);
- ur->commit_action();
+ helper->box_commit_handle(TTR("Change Decal Size"), p_cancel, p_gizmo->get_node_3d());
}
void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
@@ -153,16 +126,11 @@ void DecalGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
lines.push_back(Vector3(0, half_size_y, 0));
lines.push_back(Vector3(0, half_size_y * 1.2, 0));
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
-
+ Vector<Vector3> handles = helper->box_get_handles(decal->get_size());
Ref<Material> material = get_material("decal_material", p_gizmo);
+ const Ref<Material> icon = get_material("decal_icon", p_gizmo);
p_gizmo->add_lines(lines, material);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
p_gizmo->add_handles(handles, get_material("handles"));
}
diff --git a/editor/plugins/gizmos/decal_gizmo_plugin.h b/editor/plugins/gizmos/decal_gizmo_plugin.h
index 800a14b2d5..c7809dc556 100644
--- a/editor/plugins/gizmos/decal_gizmo_plugin.h
+++ b/editor/plugins/gizmos/decal_gizmo_plugin.h
@@ -33,9 +33,13 @@
#include "editor/plugins/node_3d_editor_gizmos.h"
+class Gizmo3DHelper;
+
class DecalGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(DecalGizmoPlugin, EditorNode3DGizmoPlugin);
+ Ref<Gizmo3DHelper> helper;
+
public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
@@ -44,10 +48,12 @@ public:
String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) override;
void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
DecalGizmoPlugin();
+ ~DecalGizmoPlugin();
};
#endif // DECAL_GIZMO_PLUGIN_H
diff --git a/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp b/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp
index 8f7cbee405..931a738aa2 100644
--- a/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/fog_volume_gizmo_plugin.cpp
@@ -30,7 +30,9 @@
#include "fog_volume_gizmo_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/fog_volume.h"
@@ -41,6 +43,8 @@ FogVolumeGizmoPlugin::FogVolumeGizmoPlugin() {
gizmo_color.a = 0.15;
create_material("shape_material_internal", gizmo_color);
+ create_icon_material("fog_volume_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoFogVolume"), EditorStringName(EditorIcons)));
+
create_handle_material("handles");
}
@@ -143,6 +147,8 @@ void FogVolumeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
+ const Ref<Material> icon = get_material("fog_volume_icon", p_gizmo);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
p_gizmo->add_handles(handles, handles_material);
}
}
diff --git a/editor/plugins/gizmos/gizmo_3d_helper.cpp b/editor/plugins/gizmos/gizmo_3d_helper.cpp
new file mode 100644
index 0000000000..6c7acb6708
--- /dev/null
+++ b/editor/plugins/gizmos/gizmo_3d_helper.cpp
@@ -0,0 +1,131 @@
+/**************************************************************************/
+/* gizmo_3d_helper.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 "gizmo_3d_helper.h"
+
+#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/node_3d_editor_plugin.h"
+#include "scene/3d/camera_3d.h"
+
+void Gizmo3DHelper::initialize_handle_action(const Variant &p_initial_value, const Transform3D &p_initial_transform) {
+ initial_value = p_initial_value;
+ initial_transform = p_initial_transform;
+}
+
+void Gizmo3DHelper::get_segment(Camera3D *p_camera, const Point2 &p_point, Vector3 *r_segment) {
+ Transform3D gt = initial_transform;
+ Transform3D gi = gt.affine_inverse();
+
+ Vector3 ray_from = p_camera->project_ray_origin(p_point);
+ Vector3 ray_dir = p_camera->project_ray_normal(p_point);
+
+ r_segment[0] = gi.xform(ray_from);
+ r_segment[1] = gi.xform(ray_from + ray_dir * 4096);
+}
+
+Vector<Vector3> Gizmo3DHelper::box_get_handles(const Vector3 &p_box_size) {
+ Vector<Vector3> handles;
+ for (int i = 0; i < 3; i++) {
+ Vector3 ax;
+ ax[i] = p_box_size[i] / 2;
+ handles.push_back(ax);
+ handles.push_back(-ax);
+ }
+ return handles;
+}
+
+String Gizmo3DHelper::box_get_handle_name(int p_id) const {
+ switch (p_id) {
+ case 0:
+ case 1:
+ return "Size X";
+ case 2:
+ case 3:
+ return "Size Y";
+ case 4:
+ case 5:
+ return "Size Z";
+ }
+ return "";
+}
+
+void Gizmo3DHelper::box_set_handle(const Vector3 p_segment[2], int p_id, Vector3 &r_box_size, Vector3 &r_box_position) {
+ Vector3 axis;
+ axis[p_id / 2] = 1.0;
+ Vector3 ra, rb;
+ int sign = p_id % 2 * -2 + 1;
+ Vector3 initial_size = initial_value;
+
+ Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096 * sign, p_segment[0], p_segment[1], ra, rb);
+ if (ra[p_id / 2] == 0) {
+ // Point before half of the shape. Needs to be calculated in opposite direction.
+ Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096 * -sign, p_segment[0], p_segment[1], ra, rb);
+ }
+
+ float d = ra[p_id / 2] * sign;
+
+ Vector3 he = r_box_size;
+ he[p_id / 2] = d * 2;
+ if (Node3DEditor::get_singleton()->is_snap_enabled()) {
+ he[p_id / 2] = Math::snapped(he[p_id / 2], Node3DEditor::get_singleton()->get_translate_snap());
+ }
+
+ if (Input::get_singleton()->is_key_pressed(Key::ALT)) {
+ he[p_id / 2] = MAX(he[p_id / 2], 0.001);
+ r_box_size = he;
+ r_box_position = initial_transform.get_origin();
+ } else {
+ he[p_id / 2] = MAX(he[p_id / 2], -initial_size[p_id / 2] + 0.002);
+ r_box_size = (initial_size + (he - initial_size) * 0.5).abs();
+ Vector3 pos = initial_transform.affine_inverse().xform(initial_transform.get_origin());
+ pos += (r_box_size - initial_size) * 0.5 * sign;
+ r_box_position = initial_transform.xform(pos);
+ }
+}
+
+void Gizmo3DHelper::box_commit_handle(const String &p_action_name, bool p_cancel, Object *p_position_object, Object *p_size_object, const StringName &p_position_property, const StringName &p_size_property) {
+ if (!p_size_object) {
+ p_size_object = p_position_object;
+ }
+
+ if (p_cancel) {
+ p_size_object->set(p_size_property, initial_value);
+ p_position_object->set(p_position_property, initial_transform.get_origin());
+ return;
+ }
+
+ EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
+ ur->create_action(p_action_name);
+ ur->add_do_property(p_size_object, p_size_property, p_size_object->get(p_size_property));
+ ur->add_do_property(p_position_object, p_position_property, p_position_object->get(p_position_property));
+ ur->add_undo_property(p_size_object, p_size_property, initial_value);
+ ur->add_undo_property(p_position_object, p_position_property, initial_transform.get_origin());
+ ur->commit_action();
+}
diff --git a/editor/plugins/gizmos/gizmo_3d_helper.h b/editor/plugins/gizmos/gizmo_3d_helper.h
new file mode 100644
index 0000000000..387ea020b8
--- /dev/null
+++ b/editor/plugins/gizmos/gizmo_3d_helper.h
@@ -0,0 +1,55 @@
+/**************************************************************************/
+/* gizmo_3d_helper.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 GIZMO_3D_HELPER_H
+#define GIZMO_3D_HELPER_H
+
+#include "core/object/ref_counted.h"
+
+class Camera3D;
+
+class Gizmo3DHelper : public RefCounted {
+ GDCLASS(Gizmo3DHelper, RefCounted);
+
+ int current_handle_id;
+ Variant initial_value;
+ Transform3D initial_transform;
+
+public:
+ void initialize_handle_action(const Variant &p_initial_value, const Transform3D &p_initial_transform);
+ void get_segment(Camera3D *p_camera, const Point2 &p_point, Vector3 *r_segment);
+
+ Vector<Vector3> box_get_handles(const Vector3 &p_box_size);
+ String box_get_handle_name(int p_id) const;
+ void box_set_handle(const Vector3 p_segment[2], int p_id, Vector3 &r_box_size, Vector3 &r_box_position);
+ void box_commit_handle(const String &p_action_name, bool p_cancel, Object *p_position_object, Object *p_size_object = nullptr, const StringName &p_position_property = "global_position", const StringName &p_size_property = "size");
+};
+
+#endif // GIZMO_3D_HELPER_H
diff --git a/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp
index f17518482a..2b673207ab 100644
--- a/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/gpu_particles_3d_gizmo_plugin.cpp
@@ -30,7 +30,9 @@
#include "gpu_particles_3d_gizmo_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/gpu_particles_3d.h"
@@ -40,7 +42,7 @@ GPUParticles3DGizmoPlugin::GPUParticles3DGizmoPlugin() {
create_material("particles_material", gizmo_color);
gizmo_color.a = MAX((gizmo_color.a - 0.2) * 0.02, 0.0);
create_material("particles_solid_material", gizmo_color);
- create_icon_material("particles_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoGPUParticles3D")));
+ create_icon_material("particles_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoGPUParticles3D"), EditorStringName(EditorIcons)));
create_handle_material("handles");
}
@@ -151,49 +153,50 @@ void GPUParticles3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
}
void GPUParticles3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_node_3d());
-
p_gizmo->clear();
- Vector<Vector3> lines;
- AABB aabb = particles->get_visibility_aabb();
+ if (p_gizmo->is_selected()) {
+ GPUParticles3D *particles = Object::cast_to<GPUParticles3D>(p_gizmo->get_node_3d());
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
+ Vector<Vector3> lines;
+ AABB aabb = particles->get_visibility_aabb();
- Vector<Vector3> handles;
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
- for (int i = 0; i < 3; i++) {
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
- ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
- handles.push_back(ax);
- }
+ Vector<Vector3> handles;
- Vector3 center = aabb.get_center();
- for (int i = 0; i < 3; i++) {
- Vector3 ax;
- ax[i] = 1.0;
- handles.push_back(center + ax);
- lines.push_back(center);
- lines.push_back(center + ax);
- }
+ for (int i = 0; i < 3; i++) {
+ Vector3 ax;
+ ax[i] = aabb.position[i] + aabb.size[i];
+ ax[(i + 1) % 3] = aabb.position[(i + 1) % 3] + aabb.size[(i + 1) % 3] * 0.5;
+ ax[(i + 2) % 3] = aabb.position[(i + 2) % 3] + aabb.size[(i + 2) % 3] * 0.5;
+ handles.push_back(ax);
+ }
- Ref<Material> material = get_material("particles_material", p_gizmo);
- Ref<Material> icon = get_material("particles_icon", p_gizmo);
+ Vector3 center = aabb.get_center();
+ for (int i = 0; i < 3; i++) {
+ Vector3 ax;
+ ax[i] = 1.0;
+ handles.push_back(center + ax);
+ lines.push_back(center);
+ lines.push_back(center + ax);
+ }
- p_gizmo->add_lines(lines, material);
+ Ref<Material> material = get_material("particles_material", p_gizmo);
+
+ p_gizmo->add_lines(lines, material);
- if (p_gizmo->is_selected()) {
Ref<Material> solid_material = get_material("particles_solid_material", p_gizmo);
p_gizmo->add_solid_box(solid_material, aabb.get_size(), aabb.get_center());
+
+ p_gizmo->add_handles(handles, get_material("handles"));
}
- p_gizmo->add_handles(handles, get_material("handles"));
+ Ref<Material> icon = get_material("particles_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05);
}
diff --git a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp
index 248e15c2c1..2cbfccc05e 100644
--- a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.cpp
@@ -32,10 +32,13 @@
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/gizmos/gizmo_3d_helper.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/gpu_particles_collision_3d.h"
GPUParticlesCollision3DGizmoPlugin::GPUParticlesCollision3DGizmoPlugin() {
+ helper.instantiate();
+
Color gizmo_color_attractor = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/particle_attractor", Color(1, 0.7, 0.5));
create_material("shape_material_attractor", gizmo_color_attractor);
gizmo_color_attractor.a = 0.15;
@@ -49,6 +52,9 @@ GPUParticlesCollision3DGizmoPlugin::GPUParticlesCollision3DGizmoPlugin() {
create_handle_material("handles");
}
+GPUParticlesCollision3DGizmoPlugin::~GPUParticlesCollision3DGizmoPlugin() {
+}
+
bool GPUParticlesCollision3DGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return (Object::cast_to<GPUParticlesCollision3D>(p_spatial) != nullptr) || (Object::cast_to<GPUParticlesAttractor3D>(p_spatial) != nullptr);
}
@@ -69,7 +75,7 @@ String GPUParticlesCollision3DGizmoPlugin::get_handle_name(const EditorNode3DGiz
}
if (Object::cast_to<GPUParticlesCollisionBox3D>(cs) || Object::cast_to<GPUParticlesAttractorBox3D>(cs) || Object::cast_to<GPUParticlesAttractorVectorField3D>(cs) || Object::cast_to<GPUParticlesCollisionSDF3D>(cs) || Object::cast_to<GPUParticlesCollisionHeightField3D>(cs)) {
- return "Size";
+ return helper->box_get_handle_name(p_id);
}
return "";
@@ -89,16 +95,15 @@ Variant GPUParticlesCollision3DGizmoPlugin::get_handle_value(const EditorNode3DG
return Variant();
}
+void GPUParticlesCollision3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
+ helper->initialize_handle_action(get_handle_value(p_gizmo, p_id, p_secondary), p_gizmo->get_node_3d()->get_global_transform());
+}
+
void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
Node3D *sn = p_gizmo->get_node_3d();
- Transform3D gt = sn->get_global_transform();
- Transform3D gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 4096) };
+ Vector3 sg[2];
+ helper->get_segment(p_camera, p_point, sg);
if (Object::cast_to<GPUParticlesCollisionSphere3D>(sn) || Object::cast_to<GPUParticlesAttractorSphere3D>(sn)) {
Vector3 ra, rb;
@@ -116,22 +121,11 @@ void GPUParticlesCollision3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_g
}
if (Object::cast_to<GPUParticlesCollisionBox3D>(sn) || Object::cast_to<GPUParticlesAttractorBox3D>(sn) || Object::cast_to<GPUParticlesAttractorVectorField3D>(sn) || Object::cast_to<GPUParticlesCollisionSDF3D>(sn) || Object::cast_to<GPUParticlesCollisionHeightField3D>(sn)) {
- Vector3 axis;
- axis[p_id] = 1.0;
- Vector3 ra, rb;
- Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_id] * 2;
- if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001) {
- d = 0.001;
- }
-
- Vector3 he = sn->call("get_size");
- he[p_id] = d;
- sn->call("set_size", he);
+ Vector3 size = sn->call("get_size");
+ Vector3 position;
+ helper->box_set_handle(sg, p_id, size, position);
+ sn->call("set_size", size);
+ sn->set_global_position(position);
}
}
@@ -152,16 +146,7 @@ void GPUParticlesCollision3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *
}
if (Object::cast_to<GPUParticlesCollisionBox3D>(sn) || Object::cast_to<GPUParticlesAttractorBox3D>(sn) || Object::cast_to<GPUParticlesAttractorVectorField3D>(sn) || Object::cast_to<GPUParticlesCollisionSDF3D>(sn) || Object::cast_to<GPUParticlesCollisionHeightField3D>(sn)) {
- if (p_cancel) {
- sn->call("set_size", p_restore);
- return;
- }
-
- EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Box Shape Size"));
- ur->add_do_method(sn, "set_size", sn->call("get_size"));
- ur->add_undo_method(sn, "set_size", p_restore);
- ur->commit_action();
+ helper->box_commit_handle("Change Box Shape Size", p_cancel, sn);
}
}
@@ -237,13 +222,7 @@ void GPUParticlesCollision3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
lines.push_back(b);
}
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
- Vector3 ax;
- ax[i] = cs->call("get_size").operator Vector3()[i] / 2;
- handles.push_back(ax);
- }
+ Vector<Vector3> handles = helper->box_get_handles(aabb.size);
p_gizmo->add_lines(lines, material);
p_gizmo->add_collision_segments(lines);
diff --git a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h
index 6045f6e440..98572ff837 100644
--- a/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h
+++ b/editor/plugins/gizmos/gpu_particles_collision_3d_gizmo_plugin.h
@@ -33,9 +33,13 @@
#include "editor/plugins/node_3d_editor_gizmos.h"
+class Gizmo3DHelper;
+
class GPUParticlesCollision3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(GPUParticlesCollision3DGizmoPlugin, EditorNode3DGizmoPlugin);
+ Ref<Gizmo3DHelper> helper;
+
public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
@@ -44,10 +48,12 @@ public:
String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) override;
void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
GPUParticlesCollision3DGizmoPlugin();
+ ~GPUParticlesCollision3DGizmoPlugin();
};
#endif // GPU_PARTICLES_COLLISION_3D_GIZMO_PLUGIN_H
diff --git a/editor/plugins/gizmos/light_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/light_3d_gizmo_plugin.cpp
index 021cf4e8f1..967f8a65ce 100644
--- a/editor/plugins/gizmos/light_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/light_3d_gizmo_plugin.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/light_3d.h"
@@ -43,9 +44,9 @@ Light3DGizmoPlugin::Light3DGizmoPlugin() {
create_material("lines_secondary", Color(1, 1, 1, 0.35), false, false, true);
create_material("lines_billboard", Color(1, 1, 1), true, false, true);
- create_icon_material("light_directional_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoDirectionalLight")));
- create_icon_material("light_omni_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoLight")));
- create_icon_material("light_spot_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoSpotLight")));
+ create_icon_material("light_directional_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoDirectionalLight"), EditorStringName(EditorIcons)));
+ create_icon_material("light_omni_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoLight"), EditorStringName(EditorIcons)));
+ create_icon_material("light_spot_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoSpotLight"), EditorStringName(EditorIcons)));
create_handle_material("handles");
create_handle_material("handles_billboard", true);
@@ -158,124 +159,133 @@ void Light3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
p_gizmo->clear();
if (Object::cast_to<DirectionalLight3D>(light)) {
- Ref<Material> material = get_material("lines_primary", p_gizmo);
- Ref<Material> icon = get_material("light_directional_icon", p_gizmo);
+ if (p_gizmo->is_selected()) {
+ Ref<Material> material = get_material("lines_primary", p_gizmo);
- const int arrow_points = 7;
- const float arrow_length = 1.5;
+ const int arrow_points = 7;
+ const float arrow_length = 1.5;
- Vector3 arrow[arrow_points] = {
- Vector3(0, 0, -1),
- Vector3(0, 0.8, 0),
- Vector3(0, 0.3, 0),
- Vector3(0, 0.3, arrow_length),
- Vector3(0, -0.3, arrow_length),
- Vector3(0, -0.3, 0),
- Vector3(0, -0.8, 0)
- };
+ Vector3 arrow[arrow_points] = {
+ Vector3(0, 0, -1),
+ Vector3(0, 0.8, 0),
+ Vector3(0, 0.3, 0),
+ Vector3(0, 0.3, arrow_length),
+ Vector3(0, -0.3, arrow_length),
+ Vector3(0, -0.3, 0),
+ Vector3(0, -0.8, 0)
+ };
- int arrow_sides = 2;
+ int arrow_sides = 2;
- Vector<Vector3> lines;
+ Vector<Vector3> lines;
- for (int i = 0; i < arrow_sides; i++) {
- for (int j = 0; j < arrow_points; j++) {
- Basis ma(Vector3(0, 0, 1), Math_PI * i / arrow_sides);
+ for (int i = 0; i < arrow_sides; i++) {
+ for (int j = 0; j < arrow_points; j++) {
+ Basis ma(Vector3(0, 0, 1), Math_PI * i / arrow_sides);
- Vector3 v1 = arrow[j] - Vector3(0, 0, arrow_length);
- Vector3 v2 = arrow[(j + 1) % arrow_points] - Vector3(0, 0, arrow_length);
+ Vector3 v1 = arrow[j] - Vector3(0, 0, arrow_length);
+ Vector3 v2 = arrow[(j + 1) % arrow_points] - Vector3(0, 0, arrow_length);
- lines.push_back(ma.xform(v1));
- lines.push_back(ma.xform(v2));
+ lines.push_back(ma.xform(v1));
+ lines.push_back(ma.xform(v2));
+ }
}
+
+ p_gizmo->add_lines(lines, material, false, color);
}
- p_gizmo->add_lines(lines, material, false, color);
+ Ref<Material> icon = get_material("light_directional_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05, color);
}
if (Object::cast_to<OmniLight3D>(light)) {
- // Use both a billboard circle and 3 non-billboard circles for a better sphere-like representation
- const Ref<Material> lines_material = get_material("lines_secondary", p_gizmo);
- const Ref<Material> lines_billboard_material = get_material("lines_billboard", p_gizmo);
- const Ref<Material> icon = get_material("light_omni_icon", p_gizmo);
+ if (p_gizmo->is_selected()) {
+ // Use both a billboard circle and 3 non-billboard circles for a better sphere-like representation
+ const Ref<Material> lines_material = get_material("lines_secondary", p_gizmo);
+ const Ref<Material> lines_billboard_material = get_material("lines_billboard", p_gizmo);
+
+ OmniLight3D *on = Object::cast_to<OmniLight3D>(light);
+ const float r = on->get_param(Light3D::PARAM_RANGE);
+ Vector<Vector3> points;
+ Vector<Vector3> points_billboard;
+
+ for (int i = 0; i < 120; i++) {
+ // Create a circle
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
+
+ // Draw axis-aligned circles
+ points.push_back(Vector3(a.x, 0, a.y));
+ points.push_back(Vector3(b.x, 0, b.y));
+ points.push_back(Vector3(0, a.x, a.y));
+ points.push_back(Vector3(0, b.x, b.y));
+ points.push_back(Vector3(a.x, a.y, 0));
+ points.push_back(Vector3(b.x, b.y, 0));
+
+ // Draw a billboarded circle
+ points_billboard.push_back(Vector3(a.x, a.y, 0));
+ points_billboard.push_back(Vector3(b.x, b.y, 0));
+ }
+
+ p_gizmo->add_lines(points, lines_material, true, color);
+ p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color);
- OmniLight3D *on = Object::cast_to<OmniLight3D>(light);
- const float r = on->get_param(Light3D::PARAM_RANGE);
- Vector<Vector3> points;
- Vector<Vector3> points_billboard;
-
- for (int i = 0; i < 120; i++) {
- // Create a circle
- const float ra = Math::deg_to_rad((float)(i * 3));
- const float rb = Math::deg_to_rad((float)((i + 1) * 3));
- const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * r;
- const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * r;
-
- // Draw axis-aligned circles
- points.push_back(Vector3(a.x, 0, a.y));
- points.push_back(Vector3(b.x, 0, b.y));
- points.push_back(Vector3(0, a.x, a.y));
- points.push_back(Vector3(0, b.x, b.y));
- points.push_back(Vector3(a.x, a.y, 0));
- points.push_back(Vector3(b.x, b.y, 0));
-
- // Draw a billboarded circle
- points_billboard.push_back(Vector3(a.x, a.y, 0));
- points_billboard.push_back(Vector3(b.x, b.y, 0));
+ Vector<Vector3> handles;
+ handles.push_back(Vector3(r, 0, 0));
+ p_gizmo->add_handles(handles, get_material("handles_billboard"), Vector<int>(), true);
}
- p_gizmo->add_lines(points, lines_material, true, color);
- p_gizmo->add_lines(points_billboard, lines_billboard_material, true, color);
+ const Ref<Material> icon = get_material("light_omni_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05, color);
-
- Vector<Vector3> handles;
- handles.push_back(Vector3(r, 0, 0));
- p_gizmo->add_handles(handles, get_material("handles_billboard"), Vector<int>(), true);
}
if (Object::cast_to<SpotLight3D>(light)) {
- const Ref<Material> material_primary = get_material("lines_primary", p_gizmo);
- const Ref<Material> material_secondary = get_material("lines_secondary", p_gizmo);
- const Ref<Material> icon = get_material("light_spot_icon", p_gizmo);
-
- Vector<Vector3> points_primary;
- Vector<Vector3> points_secondary;
- SpotLight3D *sl = Object::cast_to<SpotLight3D>(light);
+ if (p_gizmo->is_selected()) {
+ const Ref<Material> material_primary = get_material("lines_primary", p_gizmo);
+ const Ref<Material> material_secondary = get_material("lines_secondary", p_gizmo);
+
+ Vector<Vector3> points_primary;
+ Vector<Vector3> points_secondary;
+ SpotLight3D *sl = Object::cast_to<SpotLight3D>(light);
+
+ float r = sl->get_param(Light3D::PARAM_RANGE);
+ float w = r * Math::sin(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+ float d = r * Math::cos(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+
+ for (int i = 0; i < 120; i++) {
+ // Draw a circle
+ const float ra = Math::deg_to_rad((float)(i * 3));
+ const float rb = Math::deg_to_rad((float)((i + 1) * 3));
+ const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
+ const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
+
+ points_primary.push_back(Vector3(a.x, a.y, -d));
+ points_primary.push_back(Vector3(b.x, b.y, -d));
+
+ if (i % 15 == 0) {
+ // Draw 8 lines from the cone origin to the sides of the circle
+ points_secondary.push_back(Vector3(a.x, a.y, -d));
+ points_secondary.push_back(Vector3());
+ }
+ }
- float r = sl->get_param(Light3D::PARAM_RANGE);
- float w = r * Math::sin(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
- float d = r * Math::cos(Math::deg_to_rad(sl->get_param(Light3D::PARAM_SPOT_ANGLE)));
+ points_primary.push_back(Vector3(0, 0, -r));
+ points_primary.push_back(Vector3());
- for (int i = 0; i < 120; i++) {
- // Draw a circle
- const float ra = Math::deg_to_rad((float)(i * 3));
- const float rb = Math::deg_to_rad((float)((i + 1) * 3));
- const Point2 a = Vector2(Math::sin(ra), Math::cos(ra)) * w;
- const Point2 b = Vector2(Math::sin(rb), Math::cos(rb)) * w;
+ p_gizmo->add_lines(points_primary, material_primary, false, color);
+ p_gizmo->add_lines(points_secondary, material_secondary, false, color);
- points_primary.push_back(Vector3(a.x, a.y, -d));
- points_primary.push_back(Vector3(b.x, b.y, -d));
+ Vector<Vector3> handles = {
+ Vector3(0, 0, -r),
+ Vector3(w, 0, -d)
+ };
- if (i % 15 == 0) {
- // Draw 8 lines from the cone origin to the sides of the circle
- points_secondary.push_back(Vector3(a.x, a.y, -d));
- points_secondary.push_back(Vector3());
- }
+ p_gizmo->add_handles(handles, get_material("handles"));
}
- points_primary.push_back(Vector3(0, 0, -r));
- points_primary.push_back(Vector3());
-
- p_gizmo->add_lines(points_primary, material_primary, false, color);
- p_gizmo->add_lines(points_secondary, material_secondary, false, color);
-
- Vector<Vector3> handles = {
- Vector3(0, 0, -r),
- Vector3(w, 0, -d)
- };
-
- p_gizmo->add_handles(handles, get_material("handles"));
+ const Ref<Material> icon = get_material("light_spot_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05, color);
}
}
diff --git a/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp
index a1a25958c4..b860f5c0ee 100644
--- a/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/lightmap_gi_gizmo_plugin.cpp
@@ -30,7 +30,9 @@
#include "lightmap_gi_gizmo_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/lightmap_gi.h"
@@ -48,7 +50,7 @@ LightmapGIGizmoPlugin::LightmapGIGizmoPlugin() {
add_material("lightmap_probe_material", mat);
- create_icon_material("baked_indirect_light_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoLightmapGI")));
+ create_icon_material("baked_indirect_light_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoLightmapGI"), EditorStringName(EditorIcons)));
}
bool LightmapGIGizmoPlugin::has_gizmo(Node3D *p_spatial) {
@@ -68,17 +70,17 @@ void LightmapGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
LightmapGI *baker = Object::cast_to<LightmapGI>(p_gizmo->get_node_3d());
Ref<LightmapGIData> data = baker->get_light_data();
+ p_gizmo->clear();
+
p_gizmo->add_unscaled_billboard(icon, 0.05);
- if (data.is_null()) {
+ if (data.is_null() || !p_gizmo->is_selected()) {
return;
}
Ref<Material> material_lines = get_material("lightmap_lines", p_gizmo);
Ref<Material> material_probes = get_material("lightmap_probe_material", p_gizmo);
- p_gizmo->clear();
-
Vector<Vector3> lines;
HashSet<Vector2i> lines_found;
diff --git a/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp
index 093beac6a2..420829515f 100644
--- a/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/lightmap_probe_gizmo_plugin.cpp
@@ -30,11 +30,15 @@
#include "lightmap_probe_gizmo_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/lightmap_probe.h"
LightmapProbeGizmoPlugin::LightmapProbeGizmoPlugin() {
+ create_icon_material("lightmap_probe_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoLightmapProbe"), EditorStringName(EditorIcons)));
+
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/lightprobe_lines", Color(0.5, 0.6, 1));
gizmo_color.a = 0.3;
@@ -111,5 +115,8 @@ void LightmapProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
}
}
+ const Ref<Material> icon = get_material("lightmap_probe_icon", p_gizmo);
+
p_gizmo->add_lines(lines, material_lines);
+ p_gizmo->add_unscaled_billboard(icon, 0.05);
}
diff --git a/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp b/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp
index d86ede5e44..fa2c95d8db 100644
--- a/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/marker_3d_gizmo_plugin.cpp
@@ -61,7 +61,7 @@ Marker3DGizmoPlugin::Marker3DGizmoPlugin() {
// Use a darkened axis color for the negative axis.
// This makes it possible to see in which direction the Marker3D node is rotated
// (which can be important depending on how it's used).
- const Color color_x = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_x_color"), EditorStringName(Editor));
+ const Color color_x = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("axis_x_color"), EditorStringName(Editor));
cursor_colors.push_back(color_x);
cursor_colors.push_back(color_x);
// FIXME: Use less strong darkening factor once GH-48573 is fixed.
@@ -69,13 +69,13 @@ Marker3DGizmoPlugin::Marker3DGizmoPlugin() {
cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75));
cursor_colors.push_back(color_x.lerp(Color(0, 0, 0), 0.75));
- const Color color_y = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_y_color"), EditorStringName(Editor));
+ const Color color_y = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("axis_y_color"), EditorStringName(Editor));
cursor_colors.push_back(color_y);
cursor_colors.push_back(color_y);
cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75));
cursor_colors.push_back(color_y.lerp(Color(0, 0, 0), 0.75));
- const Color color_z = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("axis_z_color"), EditorStringName(Editor));
+ const Color color_z = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("axis_z_color"), EditorStringName(Editor));
cursor_colors.push_back(color_z);
cursor_colors.push_back(color_z);
cursor_colors.push_back(color_z.lerp(Color(0, 0, 0), 0.75));
diff --git a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
index d9c2316ce0..d25311f1be 100644
--- a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.cpp
@@ -30,12 +30,16 @@
#include "reflection_probe_gizmo_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/gizmos/gizmo_3d_helper.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/reflection_probe.h"
ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() {
+ helper.instantiate();
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/reflection_probe", Color(0.6, 1, 0.5));
create_material("reflection_probe_material", gizmo_color);
@@ -46,10 +50,13 @@ ReflectionProbeGizmoPlugin::ReflectionProbeGizmoPlugin() {
gizmo_color.a = 0.1;
create_material("reflection_probe_solid_material", gizmo_color);
- create_icon_material("reflection_probe_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoReflectionProbe")));
+ create_icon_material("reflection_probe_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoReflectionProbe"), EditorStringName(EditorIcons)));
create_handle_material("handles");
}
+ReflectionProbeGizmoPlugin::~ReflectionProbeGizmoPlugin() {
+}
+
bool ReflectionProbeGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<ReflectionProbe>(p_spatial) != nullptr;
}
@@ -63,21 +70,17 @@ int ReflectionProbeGizmoPlugin::get_priority() const {
}
String ReflectionProbeGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
+ if (p_id < 6) {
+ return helper->box_get_handle_name(p_id);
+ }
switch (p_id) {
- case 0:
- return "Size X";
- case 1:
- return "Size Y";
- case 2:
- return "Size Z";
- case 3:
+ case 6:
return "Origin X";
- case 4:
+ case 7:
return "Origin Y";
- case 5:
+ case 8:
return "Origin Z";
}
-
return "";
}
@@ -86,47 +89,30 @@ Variant ReflectionProbeGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_
return AABB(probe->get_origin_offset(), probe->get_size());
}
+void ReflectionProbeGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
+ // The initial value is only used for resizing the box, so we only need AABB size.
+ AABB aabb = get_handle_value(p_gizmo, p_id, p_secondary);
+ helper->initialize_handle_action(aabb.size, p_gizmo->get_node_3d()->get_global_transform());
+}
+
void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
- Transform3D gt = probe->get_global_transform();
- Transform3D gi = gt.affine_inverse();
+ Vector3 sg[2];
+ helper->get_segment(p_camera, p_point, sg);
- if (p_id < 3) {
+ if (p_id < 6) {
Vector3 size = probe->get_size();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_id] = 1.0;
-
- Vector3 ra, rb;
- Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_id] * 2;
- if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001) {
- d = 0.001;
- }
-
- size[p_id] = d;
+ Vector3 position;
+ helper->box_set_handle(sg, p_id, size, position);
probe->set_size(size);
+ probe->set_global_position(position);
} else {
- p_id -= 3;
+ p_id -= 6;
Vector3 origin = probe->get_origin_offset();
origin[p_id] = 0;
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
Vector3 axis;
axis[p_id] = 1.0;
@@ -146,6 +132,11 @@ void ReflectionProbeGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, in
void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
+ if (p_id < 6) {
+ helper->box_commit_handle(TTR("Change Probe Size"), p_cancel, probe);
+ return;
+ }
+
AABB restore = p_restore;
if (p_cancel) {
@@ -155,70 +146,64 @@ void ReflectionProbeGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo,
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Probe Size"));
- ur->add_do_method(probe, "set_size", probe->get_size());
+ ur->create_action(TTR("Change Probe Origin Offset"));
ur->add_do_method(probe, "set_origin_offset", probe->get_origin_offset());
- ur->add_undo_method(probe, "set_size", restore.size);
ur->add_undo_method(probe, "set_origin_offset", restore.position);
ur->commit_action();
}
void ReflectionProbeGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
-
p_gizmo->clear();
- Vector<Vector3> lines;
- Vector<Vector3> internal_lines;
- Vector3 size = probe->get_size();
+ if (p_gizmo->is_selected()) {
+ ReflectionProbe *probe = Object::cast_to<ReflectionProbe>(p_gizmo->get_node_3d());
+ Vector<Vector3> lines;
+ Vector<Vector3> internal_lines;
+ Vector3 size = probe->get_size();
- AABB aabb;
- aabb.position = -size / 2;
- aabb.size = size;
+ AABB aabb;
+ aabb.position = -size / 2;
+ aabb.size = size;
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
- for (int i = 0; i < 8; i++) {
- Vector3 ep = aabb.get_endpoint(i);
- internal_lines.push_back(probe->get_origin_offset());
- internal_lines.push_back(ep);
- }
+ for (int i = 0; i < 8; i++) {
+ Vector3 ep = aabb.get_endpoint(i);
+ internal_lines.push_back(probe->get_origin_offset());
+ internal_lines.push_back(ep);
+ }
- Vector<Vector3> handles;
+ Vector<Vector3> handles = helper->box_get_handles(probe->get_size());
- for (int i = 0; i < 3; i++) {
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
+ for (int i = 0; i < 3; i++) {
+ Vector3 orig_handle = probe->get_origin_offset();
+ orig_handle[i] -= 0.25;
+ lines.push_back(orig_handle);
+ handles.push_back(orig_handle);
- for (int i = 0; i < 3; i++) {
- Vector3 orig_handle = probe->get_origin_offset();
- orig_handle[i] -= 0.25;
- lines.push_back(orig_handle);
- handles.push_back(orig_handle);
+ orig_handle[i] += 0.5;
+ lines.push_back(orig_handle);
+ }
- orig_handle[i] += 0.5;
- lines.push_back(orig_handle);
- }
+ Ref<Material> material = get_material("reflection_probe_material", p_gizmo);
+ Ref<Material> material_internal = get_material("reflection_internal_material", p_gizmo);
- Ref<Material> material = get_material("reflection_probe_material", p_gizmo);
- Ref<Material> material_internal = get_material("reflection_internal_material", p_gizmo);
- Ref<Material> icon = get_material("reflection_probe_icon", p_gizmo);
+ p_gizmo->add_lines(lines, material);
+ p_gizmo->add_lines(internal_lines, material_internal);
- p_gizmo->add_lines(lines, material);
- p_gizmo->add_lines(internal_lines, material_internal);
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("reflection_probe_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, probe->get_size());
+ }
- if (p_gizmo->is_selected()) {
- Ref<Material> solid_material = get_material("reflection_probe_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, probe->get_size());
+ p_gizmo->add_handles(handles, get_material("handles"));
}
+ Ref<Material> icon = get_material("reflection_probe_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05);
- p_gizmo->add_handles(handles, get_material("handles"));
}
diff --git a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.h b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.h
index bc9840b27c..b980f5a944 100644
--- a/editor/plugins/gizmos/reflection_probe_gizmo_plugin.h
+++ b/editor/plugins/gizmos/reflection_probe_gizmo_plugin.h
@@ -33,9 +33,13 @@
#include "editor/plugins/node_3d_editor_gizmos.h"
+class Gizmo3DHelper;
+
class ReflectionProbeGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(ReflectionProbeGizmoPlugin, EditorNode3DGizmoPlugin);
+ Ref<Gizmo3DHelper> helper;
+
public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
@@ -44,10 +48,12 @@ public:
String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) override;
void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
ReflectionProbeGizmoPlugin();
+ ~ReflectionProbeGizmoPlugin();
};
#endif // REFLECTION_PROBE_GIZMO_PLUGIN_H
diff --git a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp
index 08dbe76d87..b916e99ab6 100644
--- a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp
+++ b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.cpp
@@ -30,12 +30,17 @@
#include "voxel_gi_gizmo_plugin.h"
+#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/gizmos/gizmo_3d_helper.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/voxel_gi.h"
VoxelGIGizmoPlugin::VoxelGIGizmoPlugin() {
+ helper.instantiate();
+
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/voxel_gi", Color(0.5, 1, 0.6));
create_material("voxel_gi_material", gizmo_color);
@@ -47,10 +52,13 @@ VoxelGIGizmoPlugin::VoxelGIGizmoPlugin() {
gizmo_color.a = 0.05;
create_material("voxel_gi_solid_material", gizmo_color);
- create_icon_material("voxel_gi_icon", Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("GizmoVoxelGI")));
+ create_icon_material("voxel_gi_icon", EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GizmoVoxelGI"), EditorStringName(EditorIcons)));
create_handle_material("handles");
}
+VoxelGIGizmoPlugin::~VoxelGIGizmoPlugin() {
+}
+
bool VoxelGIGizmoPlugin::has_gizmo(Node3D *p_spatial) {
return Object::cast_to<VoxelGI>(p_spatial) != nullptr;
}
@@ -64,16 +72,7 @@ int VoxelGIGizmoPlugin::get_priority() const {
}
String VoxelGIGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
- switch (p_id) {
- case 0:
- return "Size X";
- case 1:
- return "Size Y";
- case 2:
- return "Size Z";
- }
-
- return "";
+ return helper->box_get_handle_name(p_id);
}
Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
@@ -81,129 +80,98 @@ Variant VoxelGIGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo, i
return probe->get_size();
}
+void VoxelGIGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
+ helper->initialize_handle_action(get_handle_value(p_gizmo, p_id, p_secondary), p_gizmo->get_node_3d()->get_global_transform());
+}
+
void VoxelGIGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
- Transform3D gt = probe->get_global_transform();
- Transform3D gi = gt.affine_inverse();
+ Vector3 sg[2];
+ helper->get_segment(p_camera, p_point, sg);
Vector3 size = probe->get_size();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
-
- Vector3 axis;
- axis[p_id] = 1.0;
-
- Vector3 ra, rb;
- Geometry3D::get_closest_points_between_segments(Vector3(), axis * 16384, sg[0], sg[1], ra, rb);
- float d = ra[p_id] * 2;
- if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001) {
- d = 0.001;
- }
-
- size[p_id] = d;
+ Vector3 position;
+ helper->box_set_handle(sg, p_id, size, position);
probe->set_size(size);
+ probe->set_global_position(position);
}
void VoxelGIGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) {
- VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
-
- Vector3 restore = p_restore;
-
- if (p_cancel) {
- probe->set_size(restore);
- return;
- }
-
- EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(TTR("Change Probe Size"));
- ur->add_do_method(probe, "set_size", probe->get_size());
- ur->add_undo_method(probe, "set_size", restore);
- ur->commit_action();
+ helper->box_commit_handle(TTR("Change Probe Size"), p_cancel, p_gizmo->get_node_3d());
}
void VoxelGIGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
- VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
+ p_gizmo->clear();
- Ref<Material> material = get_material("voxel_gi_material", p_gizmo);
- Ref<Material> icon = get_material("voxel_gi_icon", p_gizmo);
- Ref<Material> material_internal = get_material("voxel_gi_internal_material", p_gizmo);
+ if (p_gizmo->is_selected()) {
+ VoxelGI *probe = Object::cast_to<VoxelGI>(p_gizmo->get_node_3d());
+ Ref<Material> material = get_material("voxel_gi_material", p_gizmo);
+ Ref<Material> material_internal = get_material("voxel_gi_internal_material", p_gizmo);
- p_gizmo->clear();
+ Vector<Vector3> lines;
+ Vector3 size = probe->get_size();
- Vector<Vector3> lines;
- Vector3 size = probe->get_size();
+ static const int subdivs[VoxelGI::SUBDIV_MAX] = { 64, 128, 256, 512 };
- static const int subdivs[VoxelGI::SUBDIV_MAX] = { 64, 128, 256, 512 };
+ AABB aabb = AABB(-size / 2, size);
+ int subdiv = subdivs[probe->get_subdiv()];
+ float cell_size = aabb.get_longest_axis_size() / subdiv;
- AABB aabb = AABB(-size / 2, size);
- int subdiv = subdivs[probe->get_subdiv()];
- float cell_size = aabb.get_longest_axis_size() / subdiv;
+ for (int i = 0; i < 12; i++) {
+ Vector3 a, b;
+ aabb.get_edge(i, a, b);
+ lines.push_back(a);
+ lines.push_back(b);
+ }
- for (int i = 0; i < 12; i++) {
- Vector3 a, b;
- aabb.get_edge(i, a, b);
- lines.push_back(a);
- lines.push_back(b);
- }
+ p_gizmo->add_lines(lines, material);
- p_gizmo->add_lines(lines, material);
+ lines.clear();
- lines.clear();
+ for (int i = 1; i < subdiv; i++) {
+ for (int j = 0; j < 3; j++) {
+ if (cell_size * i > aabb.size[j]) {
+ continue;
+ }
- for (int i = 1; i < subdiv; i++) {
- for (int j = 0; j < 3; j++) {
- if (cell_size * i > aabb.size[j]) {
- continue;
- }
+ int j_n1 = (j + 1) % 3;
+ int j_n2 = (j + 2) % 3;
- int j_n1 = (j + 1) % 3;
- int j_n2 = (j + 2) % 3;
+ for (int k = 0; k < 4; k++) {
+ Vector3 from = aabb.position, to = aabb.position;
+ from[j] += cell_size * i;
+ to[j] += cell_size * i;
- for (int k = 0; k < 4; k++) {
- Vector3 from = aabb.position, to = aabb.position;
- from[j] += cell_size * i;
- to[j] += cell_size * i;
+ if (k & 1) {
+ to[j_n1] += aabb.size[j_n1];
+ } else {
+ to[j_n2] += aabb.size[j_n2];
+ }
- if (k & 1) {
- to[j_n1] += aabb.size[j_n1];
- } else {
- to[j_n2] += aabb.size[j_n2];
- }
+ if (k & 2) {
+ from[j_n1] += aabb.size[j_n1];
+ from[j_n2] += aabb.size[j_n2];
+ }
- if (k & 2) {
- from[j_n1] += aabb.size[j_n1];
- from[j_n2] += aabb.size[j_n2];
+ lines.push_back(from);
+ lines.push_back(to);
}
-
- lines.push_back(from);
- lines.push_back(to);
}
}
- }
- p_gizmo->add_lines(lines, material_internal);
+ p_gizmo->add_lines(lines, material_internal);
- Vector<Vector3> handles;
+ Vector<Vector3> handles = helper->box_get_handles(probe->get_size());
- for (int i = 0; i < 3; i++) {
- Vector3 ax;
- ax[i] = aabb.position[i] + aabb.size[i];
- handles.push_back(ax);
- }
+ if (p_gizmo->is_selected()) {
+ Ref<Material> solid_material = get_material("voxel_gi_solid_material", p_gizmo);
+ p_gizmo->add_solid_box(solid_material, aabb.get_size());
+ }
- if (p_gizmo->is_selected()) {
- Ref<Material> solid_material = get_material("voxel_gi_solid_material", p_gizmo);
- p_gizmo->add_solid_box(solid_material, aabb.get_size());
+ p_gizmo->add_handles(handles, get_material("handles"));
}
+ Ref<Material> icon = get_material("voxel_gi_icon", p_gizmo);
p_gizmo->add_unscaled_billboard(icon, 0.05);
- p_gizmo->add_handles(handles, get_material("handles"));
}
diff --git a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.h b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.h
index 4d1f282bd6..a5447c8b5c 100644
--- a/editor/plugins/gizmos/voxel_gi_gizmo_plugin.h
+++ b/editor/plugins/gizmos/voxel_gi_gizmo_plugin.h
@@ -33,9 +33,13 @@
#include "editor/plugins/node_3d_editor_gizmos.h"
+class Gizmo3DHelper;
+
class VoxelGIGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(VoxelGIGizmoPlugin, EditorNode3DGizmoPlugin);
+ Ref<Gizmo3DHelper> helper;
+
public:
bool has_gizmo(Node3D *p_spatial) override;
String get_gizmo_name() const override;
@@ -44,10 +48,12 @@ public:
String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) override;
void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel = false) override;
VoxelGIGizmoPlugin();
+ ~VoxelGIGizmoPlugin();
};
#endif // VOXEL_GI_GIZMO_PLUGIN_H
diff --git a/editor/plugins/gpu_particles_2d_editor_plugin.cpp b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
index a6ae6c1256..af04d45ba8 100644
--- a/editor/plugins/gpu_particles_2d_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_2d_editor_plugin.cpp
@@ -369,8 +369,6 @@ GPUParticles2DEditorPlugin::GPUParticles2DEditorPlugin() {
add_control_to_container(CONTAINER_CANVAS_EDITOR_MENU, toolbar);
toolbar->hide();
- toolbar->add_child(memnew(VSeparator));
-
menu = memnew(MenuButton);
menu->get_popup()->add_item(TTR("Restart"), MENU_RESTART);
menu->get_popup()->add_item(TTR("Generate Visibility Rect"), MENU_GENERATE_VISIBILITY_RECT);
diff --git a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
index af861b04b5..c7d7cc7918 100644
--- a/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
+++ b/editor/plugins/gpu_particles_collision_sdf_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_interface.h"
#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/gui/editor_file_dialog.h"
void GPUParticlesCollisionSDF3DEditorPlugin::_bake() {
@@ -126,12 +127,12 @@ void GPUParticlesCollisionSDF3DEditorPlugin::bake_func_begin(int p_steps) {
}
void GPUParticlesCollisionSDF3DEditorPlugin::bake_func_step(int p_step, const String &p_description) {
- ERR_FAIL_COND(tmp_progress == nullptr);
+ ERR_FAIL_NULL(tmp_progress);
tmp_progress->step(p_description, p_step, false);
}
void GPUParticlesCollisionSDF3DEditorPlugin::bake_func_end() {
- ERR_FAIL_COND(tmp_progress == nullptr);
+ ERR_FAIL_NULL(tmp_progress);
memdelete(tmp_progress);
tmp_progress = nullptr;
}
@@ -183,7 +184,7 @@ GPUParticlesCollisionSDF3DEditorPlugin::GPUParticlesCollisionSDF3DEditorPlugin()
bake_hb->hide();
bake = memnew(Button);
bake->set_flat(true);
- bake->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Bake")));
+ bake->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
bake->set_text(TTR("Bake SDF"));
bake->connect("pressed", callable_mp(this, &GPUParticlesCollisionSDF3DEditorPlugin::_bake));
bake_hb->add_child(bake);
diff --git a/editor/plugins/gradient_editor.cpp b/editor/plugins/gradient_editor.cpp
index 63dede4850..bcc7d2a004 100644
--- a/editor/plugins/gradient_editor.cpp
+++ b/editor/plugins/gradient_editor.cpp
@@ -312,7 +312,7 @@ void GradientEditor::gui_input(const Ref<InputEvent> &p_event) {
// Snap to "round" coordinates if holding Ctrl.
// Be more precise if holding Shift as well.
- if (mm->is_ctrl_pressed()) {
+ if (mm->is_command_or_control_pressed()) {
newofs = Math::snapped(newofs, mm->is_shift_pressed() ? 0.025 : 0.1);
} else if (mm->is_shift_pressed()) {
// Snap to nearest point if holding just Shift.
diff --git a/editor/plugins/gradient_texture_2d_editor_plugin.cpp b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
index 494d97c45c..5952185cc0 100644
--- a/editor/plugins/gradient_texture_2d_editor_plugin.cpp
+++ b/editor/plugins/gradient_texture_2d_editor_plugin.cpp
@@ -113,7 +113,7 @@ void GradientTexture2DEdit::gui_input(const Ref<InputEvent> &p_event) {
}
Vector2 new_pos = (mpos / size).clamp(Vector2(0, 0), Vector2(1, 1));
- if (snap_enabled || mm->is_ctrl_pressed()) {
+ if (snap_enabled || mm->is_command_or_control_pressed()) {
new_pos = new_pos.snapped(Vector2(1.0 / snap_count, 1.0 / snap_count));
}
@@ -201,7 +201,7 @@ void GradientTexture2DEdit::_draw() {
draw_texture_rect(texture, Rect2(Point2(), size));
// Draw grid snap lines.
- if (snap_enabled || (Input::get_singleton()->is_key_pressed(Key::CTRL) && grabbed != HANDLE_NONE)) {
+ if (snap_enabled || (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL) && grabbed != HANDLE_NONE)) {
const Color line_color = Color(0.5, 0.5, 0.5, 0.5);
for (int idx = 0; idx < snap_count + 1; idx++) {
diff --git a/editor/plugins/lightmap_gi_editor_plugin.cpp b/editor/plugins/lightmap_gi_editor_plugin.cpp
index db5593a132..7664739480 100644
--- a/editor/plugins/lightmap_gi_editor_plugin.cpp
+++ b/editor/plugins/lightmap_gi_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "lightmap_gi_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/gui/editor_file_dialog.h"
void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
@@ -103,6 +104,9 @@ void LightmapGIEditorPlugin::_bake_select_file(const String &p_file) {
case LightmapGI::BAKE_ERROR_FOREIGN_DATA: {
EditorNode::get_singleton()->show_warning(TTR("Lightmap data is not local to the scene."));
} break;
+ case LightmapGI::BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL: {
+ EditorNode::get_singleton()->show_warning(TTR("Maximum texture size is too small for the lightmap images."));
+ } break;
default: {
} break;
}
@@ -139,7 +143,7 @@ EditorProgress *LightmapGIEditorPlugin::tmp_progress = nullptr;
bool LightmapGIEditorPlugin::bake_func_step(float p_progress, const String &p_description, void *, bool p_refresh) {
if (!tmp_progress) {
tmp_progress = memnew(EditorProgress("bake_lightmaps", TTR("Bake Lightmaps"), 1000, false));
- ERR_FAIL_COND_V(tmp_progress == nullptr, false);
+ ERR_FAIL_NULL_V(tmp_progress, false);
}
return tmp_progress->step(p_description, p_progress * 1000, p_refresh);
}
@@ -165,7 +169,9 @@ void LightmapGIEditorPlugin::_bind_methods() {
LightmapGIEditorPlugin::LightmapGIEditorPlugin() {
bake = memnew(Button);
bake->set_flat(true);
- bake->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Bake")));
+ // TODO: Rework this as a dedicated toolbar control so we can hook into theme changes and update it
+ // when the editor theme updates.
+ bake->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
bake->set_text(TTR("Bake Lightmaps"));
bake->hide();
bake->connect("pressed", Callable(this, "_bake"));
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.cpp b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
index c299ba97d5..8d112446a3 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.cpp
@@ -513,17 +513,20 @@ void MeshInstance3DEditor::_create_outline_mesh() {
ur->commit_action();
}
-void MeshInstance3DEditor::_bind_methods() {
+void MeshInstance3DEditor::_notification(int p_what) {
+ switch (p_what) {
+ case NOTIFICATION_THEME_CHANGED: {
+ options->set_icon(get_editor_theme_icon(SNAME("MeshInstance3D")));
+ } break;
+ }
}
MeshInstance3DEditor::MeshInstance3DEditor() {
options = memnew(MenuButton);
+ options->set_text(TTR("Mesh"));
options->set_switch_on_hover(true);
Node3DEditor::get_singleton()->add_control_to_menu_panel(options);
- options->set_text(TTR("Mesh"));
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("MeshInstance3D")));
-
options->get_popup()->add_item(TTR("Create Trimesh Static Body"), MENU_OPTION_CREATE_STATIC_TRIMESH_BODY);
options->get_popup()->set_item_tooltip(-1, TTR("Creates a StaticBody3D and assigns a polygon-based collision shape to it automatically.\nThis is the most accurate (but slowest) option for collision detection."));
options->get_popup()->add_separator();
diff --git a/editor/plugins/mesh_instance_3d_editor_plugin.h b/editor/plugins/mesh_instance_3d_editor_plugin.h
index ea67d1aae9..eb984e240e 100644
--- a/editor/plugins/mesh_instance_3d_editor_plugin.h
+++ b/editor/plugins/mesh_instance_3d_editor_plugin.h
@@ -79,7 +79,8 @@ class MeshInstance3DEditor : public Control {
protected:
void _node_removed(Node *p_node);
- static void _bind_methods();
+
+ void _notification(int p_what);
public:
void edit(MeshInstance3D *p_mesh);
diff --git a/editor/plugins/mesh_library_editor_plugin.cpp b/editor/plugins/mesh_library_editor_plugin.cpp
index 750a71905b..e6f0e65e40 100644
--- a/editor/plugins/mesh_library_editor_plugin.cpp
+++ b/editor/plugins/mesh_library_editor_plugin.cpp
@@ -33,6 +33,7 @@
#include "editor/editor_interface.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/gui/editor_file_dialog.h"
#include "editor/inspector_dock.h"
#include "editor/plugins/node_3d_editor_plugin.h"
@@ -210,7 +211,7 @@ void MeshLibraryEditor::_import_scene_cbk(const String &p_str) {
ERR_FAIL_COND(ps.is_null());
Node *scene = ps->instantiate();
- ERR_FAIL_COND_MSG(!scene, "Cannot create an instance from PackedScene '" + p_str + "'.");
+ ERR_FAIL_NULL_MSG(scene, "Cannot create an instance from PackedScene '" + p_str + "'.");
_import_scene(scene, mesh_library, option == MENU_OPTION_UPDATE_FROM_SCENE, apply_xforms);
@@ -275,7 +276,7 @@ MeshLibraryEditor::MeshLibraryEditor() {
Node3DEditor::get_singleton()->add_control_to_menu_panel(menu);
menu->set_position(Point2(1, 1));
menu->set_text(TTR("MeshLibrary"));
- menu->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("MeshLibrary")));
+ menu->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MeshLibrary"), EditorStringName(EditorIcons)));
menu->get_popup()->add_item(TTR("Add Item"), MENU_OPTION_ADD_ITEM);
menu->get_popup()->add_item(TTR("Remove Selected Item"), MENU_OPTION_REMOVE_ITEM);
menu->get_popup()->add_separator();
diff --git a/editor/plugins/multimesh_editor_plugin.cpp b/editor/plugins/multimesh_editor_plugin.cpp
index a980b30bfe..da1abc2af1 100644
--- a/editor/plugins/multimesh_editor_plugin.cpp
+++ b/editor/plugins/multimesh_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "multimesh_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/gui/scene_tree_editor.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/mesh_instance_3d.h"
@@ -272,7 +273,7 @@ MultiMeshEditor::MultiMeshEditor() {
Node3DEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text("MultiMesh");
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("MultiMeshInstance3D")));
+ options->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MultiMeshInstance3D"), EditorStringName(EditorIcons)));
options->get_popup()->add_item(TTR("Populate Surface"));
options->get_popup()->connect("id_pressed", callable_mp(this, &MultiMeshEditor::_menu_option));
diff --git a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
index 4892538a0a..bbbde52935 100644
--- a/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
+++ b/editor/plugins/navigation_obstacle_3d_editor_plugin.cpp
@@ -38,6 +38,7 @@
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
@@ -81,7 +82,7 @@ void NavigationObstacle3DEditor::_menu_option(int p_option) {
}
void NavigationObstacle3DEditor::_wip_close() {
- ERR_FAIL_COND_MSG(!obstacle_node, "Edited NavigationObstacle3D is not valid.");
+ ERR_FAIL_NULL_MSG(obstacle_node, "Edited NavigationObstacle3D is not valid.");
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Set NavigationObstacle3D Vertices"));
undo_redo->add_undo_method(obstacle_node, "set_vertices", obstacle_node->get_vertices());
@@ -343,12 +344,12 @@ EditorPlugin::AfterGUIInput NavigationObstacle3DEditor::forward_3d_gui_input(Cam
}
PackedVector2Array NavigationObstacle3DEditor::_get_polygon() {
- ERR_FAIL_COND_V_MSG(!obstacle_node, PackedVector2Array(), "Edited object is not valid.");
+ ERR_FAIL_NULL_V_MSG(obstacle_node, PackedVector2Array(), "Edited object is not valid.");
return PackedVector2Array(obstacle_node->call("get_polygon"));
}
void NavigationObstacle3DEditor::_set_polygon(PackedVector2Array p_poly) {
- ERR_FAIL_COND_MSG(!obstacle_node, "Edited object is not valid.");
+ ERR_FAIL_NULL_MSG(obstacle_node, "Edited object is not valid.");
obstacle_node->call("set_polygon", p_poly);
}
@@ -521,7 +522,6 @@ void NavigationObstacle3DEditor::_bind_methods() {
NavigationObstacle3DEditor::NavigationObstacle3DEditor() {
obstacle_node = nullptr;
- add_child(memnew(VSeparator));
button_create = memnew(Button);
button_create->set_flat(true);
add_child(button_create);
@@ -554,7 +554,7 @@ NavigationObstacle3DEditor::NavigationObstacle3DEditor() {
handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- Ref<Texture2D> handle = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Editor3DHandle"));
+ Ref<Texture2D> handle = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Editor3DHandle"), EditorStringName(EditorIcons));
handle_material->set_point_size(handle->get_width());
handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle);
diff --git a/editor/plugins/node_3d_editor_gizmos.cpp b/editor/plugins/node_3d_editor_gizmos.cpp
index f6e93e292f..0d3000a318 100644
--- a/editor/plugins/node_3d_editor_gizmos.cpp
+++ b/editor/plugins/node_3d_editor_gizmos.cpp
@@ -34,13 +34,14 @@
#include "core/math/geometry_3d.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/resources/primitive_meshes.h"
#define HANDLE_HALF_SIZE 9.5
bool EditorNode3DGizmo::is_editable() const {
- ERR_FAIL_COND_V(!spatial_node, false);
+ ERR_FAIL_NULL_V(spatial_node, false);
Node *edited_root = spatial_node->get_tree()->get_edited_scene_root();
if (spatial_node == edited_root) {
return true;
@@ -76,7 +77,7 @@ void EditorNode3DGizmo::clear() {
void EditorNode3DGizmo::redraw() {
if (!GDVIRTUAL_CALL(_redraw)) {
- ERR_FAIL_COND(!gizmo_plugin);
+ ERR_FAIL_NULL(gizmo_plugin);
gizmo_plugin->redraw(this);
}
@@ -91,7 +92,7 @@ String EditorNode3DGizmo::get_handle_name(int p_id, bool p_secondary) const {
return ret;
}
- ERR_FAIL_COND_V(!gizmo_plugin, "");
+ ERR_FAIL_NULL_V(gizmo_plugin, "");
return gizmo_plugin->get_handle_name(this, p_id, p_secondary);
}
@@ -101,7 +102,7 @@ bool EditorNode3DGizmo::is_handle_highlighted(int p_id, bool p_secondary) const
return success;
}
- ERR_FAIL_COND_V(!gizmo_plugin, false);
+ ERR_FAIL_NULL_V(gizmo_plugin, false);
return gizmo_plugin->is_handle_highlighted(this, p_id, p_secondary);
}
@@ -111,7 +112,7 @@ Variant EditorNode3DGizmo::get_handle_value(int p_id, bool p_secondary) const {
return value;
}
- ERR_FAIL_COND_V(!gizmo_plugin, Variant());
+ ERR_FAIL_NULL_V(gizmo_plugin, Variant());
return gizmo_plugin->get_handle_value(this, p_id, p_secondary);
}
@@ -120,7 +121,7 @@ void EditorNode3DGizmo::begin_handle_action(int p_id, bool p_secondary) {
return;
}
- ERR_FAIL_COND(!gizmo_plugin);
+ ERR_FAIL_NULL(gizmo_plugin);
gizmo_plugin->begin_handle_action(this, p_id, p_secondary);
}
@@ -129,7 +130,7 @@ void EditorNode3DGizmo::set_handle(int p_id, bool p_secondary, Camera3D *p_camer
return;
}
- ERR_FAIL_COND(!gizmo_plugin);
+ ERR_FAIL_NULL(gizmo_plugin);
gizmo_plugin->set_handle(this, p_id, p_secondary, p_camera, p_point);
}
@@ -138,7 +139,7 @@ void EditorNode3DGizmo::commit_handle(int p_id, bool p_secondary, const Variant
return;
}
- ERR_FAIL_COND(!gizmo_plugin);
+ ERR_FAIL_NULL(gizmo_plugin);
gizmo_plugin->commit_handle(this, p_id, p_secondary, p_restore, p_cancel);
}
@@ -148,7 +149,7 @@ int EditorNode3DGizmo::subgizmos_intersect_ray(Camera3D *p_camera, const Vector2
return id;
}
- ERR_FAIL_COND_V(!gizmo_plugin, -1);
+ ERR_FAIL_NULL_V(gizmo_plugin, -1);
return gizmo_plugin->subgizmos_intersect_ray(this, p_camera, p_point);
}
@@ -163,7 +164,7 @@ Vector<int> EditorNode3DGizmo::subgizmos_intersect_frustum(const Camera3D *p_cam
return ret;
}
- ERR_FAIL_COND_V(!gizmo_plugin, Vector<int>());
+ ERR_FAIL_NULL_V(gizmo_plugin, Vector<int>());
return gizmo_plugin->subgizmos_intersect_frustum(this, p_camera, p_frustum);
}
@@ -173,7 +174,7 @@ Transform3D EditorNode3DGizmo::get_subgizmo_transform(int p_id) const {
return ret;
}
- ERR_FAIL_COND_V(!gizmo_plugin, Transform3D());
+ ERR_FAIL_NULL_V(gizmo_plugin, Transform3D());
return gizmo_plugin->get_subgizmo_transform(this, p_id);
}
@@ -182,7 +183,7 @@ void EditorNode3DGizmo::set_subgizmo_transform(int p_id, Transform3D p_transform
return;
}
- ERR_FAIL_COND(!gizmo_plugin);
+ ERR_FAIL_NULL(gizmo_plugin);
gizmo_plugin->set_subgizmo_transform(this, p_id, p_transform);
}
@@ -197,7 +198,7 @@ void EditorNode3DGizmo::commit_subgizmos(const Vector<int> &p_ids, const Vector<
return;
}
- ERR_FAIL_COND(!gizmo_plugin);
+ ERR_FAIL_NULL(gizmo_plugin);
gizmo_plugin->commit_subgizmos(this, p_ids, p_restore, p_cancel);
}
@@ -223,7 +224,7 @@ void EditorNode3DGizmo::Instance::create_instance(Node3D *p_base, bool p_hidden)
}
void EditorNode3DGizmo::add_mesh(const Ref<Mesh> &p_mesh, const Ref<Material> &p_material, const Transform3D &p_xform, const Ref<SkinReference> &p_skin_reference) {
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
ERR_FAIL_COND_MSG(!p_mesh.is_valid(), "EditorNode3DGizmo.add_mesh() requires a valid Mesh resource.");
Instance ins;
@@ -252,7 +253,7 @@ void EditorNode3DGizmo::add_vertices(const Vector<Vector3> &p_vertices, const Re
return;
}
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
Instance ins;
Ref<ArrayMesh> mesh = memnew(ArrayMesh);
@@ -299,7 +300,7 @@ void EditorNode3DGizmo::add_vertices(const Vector<Vector3> &p_vertices, const Re
}
void EditorNode3DGizmo::add_unscaled_billboard(const Ref<Material> &p_material, real_t p_scale, const Color &p_modulate) {
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
Instance ins;
Vector<Vector3> vs = {
@@ -453,7 +454,7 @@ void EditorNode3DGizmo::add_handles(const Vector<Vector3> &p_handles, const Ref<
}
void EditorNode3DGizmo::add_solid_box(const Ref<Material> &p_material, Vector3 p_size, Vector3 p_position, const Transform3D &p_xform) {
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
BoxMesh box_mesh;
box_mesh.set_size(p_size);
@@ -474,7 +475,7 @@ void EditorNode3DGizmo::add_solid_box(const Ref<Material> &p_material, Vector3 p
}
bool EditorNode3DGizmo::intersect_frustum(const Camera3D *p_camera, const Vector<Plane> &p_frustum) {
- ERR_FAIL_COND_V(!spatial_node, false);
+ ERR_FAIL_NULL_V(spatial_node, false);
ERR_FAIL_COND_V(!valid, false);
if (hidden && !gizmo_plugin->is_selectable_when_hidden()) {
@@ -555,7 +556,7 @@ void EditorNode3DGizmo::handles_intersect_ray(Camera3D *p_camera, const Vector2
r_id = -1;
r_secondary = false;
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
ERR_FAIL_COND(!valid);
if (hidden) {
@@ -614,7 +615,7 @@ void EditorNode3DGizmo::handles_intersect_ray(Camera3D *p_camera, const Vector2
}
bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point, Vector3 &r_pos, Vector3 &r_normal) {
- ERR_FAIL_COND_V(!spatial_node, false);
+ ERR_FAIL_NULL_V(spatial_node, false);
ERR_FAIL_COND_V(!valid, false);
if (hidden && !gizmo_plugin->is_selectable_when_hidden()) {
@@ -738,7 +739,7 @@ bool EditorNode3DGizmo::intersect_ray(Camera3D *p_camera, const Point2 &p_point,
bool EditorNode3DGizmo::is_subgizmo_selected(int p_id) const {
Node3DEditor *ed = Node3DEditor::get_singleton();
- ERR_FAIL_COND_V(!ed, false);
+ ERR_FAIL_NULL_V(ed, false);
return ed->is_current_selected_gizmo(this) && ed->is_subgizmo_selected(p_id);
}
@@ -746,7 +747,7 @@ Vector<int> EditorNode3DGizmo::get_subgizmo_selection() const {
Vector<int> ret;
Node3DEditor *ed = Node3DEditor::get_singleton();
- ERR_FAIL_COND_V(!ed, ret);
+ ERR_FAIL_NULL_V(ed, ret);
if (ed->is_current_selected_gizmo(this)) {
ret = ed->get_subgizmo_selection();
@@ -756,7 +757,7 @@ Vector<int> EditorNode3DGizmo::get_subgizmo_selection() const {
}
void EditorNode3DGizmo::create() {
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
ERR_FAIL_COND(valid);
valid = true;
@@ -768,7 +769,7 @@ void EditorNode3DGizmo::create() {
}
void EditorNode3DGizmo::transform() {
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
ERR_FAIL_COND(!valid);
for (int i = 0; i < instances.size(); i++) {
RS::get_singleton()->instance_set_transform(instances[i].instance, spatial_node->get_global_transform() * instances[i].xform);
@@ -777,7 +778,7 @@ void EditorNode3DGizmo::transform() {
void EditorNode3DGizmo::free() {
ERR_FAIL_NULL(RenderingServer::get_singleton());
- ERR_FAIL_COND(!spatial_node);
+ ERR_FAIL_NULL(spatial_node);
ERR_FAIL_COND(!valid);
for (int i = 0; i < instances.size(); i++) {
@@ -940,7 +941,7 @@ void EditorNode3DGizmoPlugin::create_handle_material(const String &p_name, bool
handle_material->set_shading_mode(StandardMaterial3D::SHADING_MODE_UNSHADED);
handle_material->set_flag(StandardMaterial3D::FLAG_USE_POINT_SIZE, true);
- Ref<Texture2D> handle_t = p_icon != nullptr ? p_icon : Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("Editor3DHandle"));
+ Ref<Texture2D> handle_t = p_icon != nullptr ? p_icon : EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Editor3DHandle"), EditorStringName(EditorIcons));
handle_material->set_point_size(handle_t->get_width());
handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle_t);
handle_material->set_albedo(Color(1, 1, 1));
diff --git a/editor/plugins/node_3d_editor_plugin.cpp b/editor/plugins/node_3d_editor_plugin.cpp
index 17c9a097ba..2215c371d0 100644
--- a/editor/plugins/node_3d_editor_plugin.cpp
+++ b/editor/plugins/node_3d_editor_plugin.cpp
@@ -1460,14 +1460,10 @@ Transform3D Node3DEditorViewport::_compute_transform(TransformMode p_mode, const
}
if (p_local) {
- p_motion = p_original.basis.xform(p_motion);
+ return p_original_local.translated_local(p_motion);
}
- // Apply translation
- Transform3D t = p_original;
- t.origin += p_motion;
-
- return t;
+ return p_original.translated(p_motion);
}
case TRANSFORM_ROTATE: {
Transform3D r;
@@ -1981,7 +1977,7 @@ void Node3DEditorViewport::_sinput(const Ref<InputEvent> &p_event) {
nav_mode = NAVIGATION_ORBIT;
} else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_shift_pressed()) {
nav_mode = NAVIGATION_PAN;
- } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_ctrl_pressed()) {
+ } else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed() && m->is_command_or_control_pressed()) {
nav_mode = NAVIGATION_ZOOM;
} else if (nav_scheme == NAVIGATION_MODO && m->is_alt_pressed()) {
nav_mode = NAVIGATION_ORBIT;
@@ -3161,7 +3157,7 @@ void Node3DEditorViewport::_draw() {
get_editor_theme_icon(SNAME("ViewportSpeed")),
get_theme_font(SNAME("font"), SNAME("Label")),
get_theme_font_size(SNAME("font_size"), SNAME("Label")),
- vformat("%s u/s", String::num(freelook_speed).pad_decimals(precision)),
+ vformat("%s m/s", String::num(freelook_speed).pad_decimals(precision)),
Color(1.0, 0.95, 0.7));
}
@@ -3184,7 +3180,7 @@ void Node3DEditorViewport::_draw() {
get_editor_theme_icon(SNAME("ViewportZoom")),
get_theme_font(SNAME("font"), SNAME("Label")),
get_theme_font_size(SNAME("font_size"), SNAME("Label")),
- vformat("%s u", String::num(cursor.distance).pad_decimals(precision)),
+ vformat("%s m", String::num(cursor.distance).pad_decimals(precision)),
Color(0.7, 0.95, 1.0));
}
}
@@ -4957,7 +4953,7 @@ void Node3DEditorViewport::update_transform_numeric() {
apply_transform(motion, extra);
}
-// Perform cleanup after a transform operation is committed or cancelled.
+// Perform cleanup after a transform operation is committed or canceled.
void Node3DEditorViewport::finish_transform() {
_edit.mode = TRANSFORM_NONE;
_edit.instant = false;
@@ -5248,7 +5244,8 @@ Node3DEditorViewport::Node3DEditorViewport(Node3DEditor *p_spatial_editor, int p
preview_material_label_desc = memnew(Label);
preview_material_label_desc->set_anchors_and_offsets_preset(LayoutPreset::PRESET_BOTTOM_LEFT);
preview_material_label_desc->set_offset(Side::SIDE_TOP, -50 * EDSCALE);
- preview_material_label_desc->set_text(TTR("Drag and drop to override the material of any geometry node.\nHold Ctrl when dropping to override a specific surface."));
+ Key key = (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL;
+ preview_material_label_desc->set_text(vformat(TTR("Drag and drop to override the material of any geometry node.\nHold %s when dropping to override a specific surface."), find_keycode_name(key)));
preview_material_label_desc->add_theme_color_override("font_color", Color(0.8, 0.8, 0.8, 1));
preview_material_label_desc->add_theme_constant_override("line_spacing", 0);
preview_material_label_desc->hide();
@@ -7499,7 +7496,7 @@ void Node3DEditor::_add_sun_to_scene(bool p_already_added_environment) {
SceneTreeDock::get_singleton()->add_root_node(memnew(Node3D));
base = get_tree()->get_edited_scene_root();
}
- ERR_FAIL_COND(!base);
+ ERR_FAIL_NULL(base);
Node *new_sun = preview_sun->duplicate();
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
@@ -7528,7 +7525,7 @@ void Node3DEditor::_add_environment_to_scene(bool p_already_added_sun) {
SceneTreeDock::get_singleton()->add_root_node(memnew(Node3D));
base = get_tree()->get_edited_scene_root();
}
- ERR_FAIL_COND(!base);
+ ERR_FAIL_NULL(base);
WorldEnvironment *new_env = memnew(WorldEnvironment);
new_env->set_environment(preview_environment->get_environment()->duplicate(true));
@@ -7581,7 +7578,7 @@ void Node3DEditor::_update_theme() {
environ_sky_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), EditorStringName(Editor))));
environ_ground_color->set_custom_minimum_size(Size2(0, get_theme_constant(SNAME("color_picker_button_height"), EditorStringName(Editor))));
- context_menu_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles)));
+ context_toolbar_panel->add_theme_style_override("panel", get_theme_stylebox(SNAME("ContextualToolbar"), EditorStringName(EditorStyles)));
}
void Node3DEditor::_notification(int p_what) {
@@ -7679,11 +7676,51 @@ Vector<int> Node3DEditor::get_subgizmo_selection() {
}
void Node3DEditor::add_control_to_menu_panel(Control *p_control) {
- context_menu_hbox->add_child(p_control);
+ ERR_FAIL_NULL(p_control);
+ ERR_FAIL_COND(p_control->get_parent());
+
+ VSeparator *sep = memnew(VSeparator);
+ context_toolbar_hbox->add_child(sep);
+ context_toolbar_hbox->add_child(p_control);
+ context_toolbar_separators[p_control] = sep;
+
+ p_control->connect("visibility_changed", callable_mp(this, &Node3DEditor::_update_context_toolbar));
+
+ _update_context_toolbar();
}
void Node3DEditor::remove_control_from_menu_panel(Control *p_control) {
- context_menu_hbox->remove_child(p_control);
+ ERR_FAIL_NULL(p_control);
+ ERR_FAIL_COND(p_control->get_parent() != context_toolbar_hbox);
+
+ p_control->disconnect("visibility_changed", callable_mp(this, &Node3DEditor::_update_context_toolbar));
+
+ context_toolbar_hbox->remove_child(context_toolbar_separators[p_control]);
+ context_toolbar_hbox->remove_child(p_control);
+ context_toolbar_separators.erase(p_control);
+
+ _update_context_toolbar();
+}
+
+void Node3DEditor::_update_context_toolbar() {
+ bool has_visible = false;
+ bool first_visible = false;
+
+ for (int i = 0; i < context_toolbar_hbox->get_child_count(); i++) {
+ Control *child = Object::cast_to<Control>(context_toolbar_hbox->get_child(i));
+ if (!child || !context_toolbar_separators.has(child)) {
+ continue;
+ }
+ if (child->is_visible()) {
+ first_visible = !has_visible;
+ has_visible = true;
+ }
+
+ VSeparator *sep = context_toolbar_separators[child];
+ sep->set_visible(!first_visible && child->is_visible());
+ }
+
+ context_toolbar_panel->set_visible(has_visible);
}
void Node3DEditor::set_can_preview(Camera3D *p_preview) {
@@ -8161,9 +8198,17 @@ Node3DEditor::Node3DEditor() {
camera_override_viewport_id = 0;
+ // Add some margin to the sides for better esthetics.
+ // This prevents the first button's hover/pressed effect from "touching" the panel's border,
+ // which looks ugly.
+ MarginContainer *toolbar_margin = memnew(MarginContainer);
+ toolbar_margin->add_theme_constant_override("margin_left", 4 * EDSCALE);
+ toolbar_margin->add_theme_constant_override("margin_right", 4 * EDSCALE);
+ vbc->add_child(toolbar_margin);
+
// A fluid container for all toolbars.
HFlowContainer *main_flow = memnew(HFlowContainer);
- vbc->add_child(main_flow);
+ toolbar_margin->add_child(main_flow);
// Main toolbars.
HBoxContainer *main_menu_hbox = memnew(HBoxContainer);
@@ -8171,13 +8216,6 @@ Node3DEditor::Node3DEditor() {
String sct;
- // Add some margin to the left for better esthetics.
- // This prevents the first button's hover/pressed effect from "touching" the panel's border,
- // which looks ugly.
- Control *margin_left = memnew(Control);
- main_menu_hbox->add_child(margin_left);
- margin_left->set_custom_minimum_size(Size2(2, 0) * EDSCALE);
-
tool_button[TOOL_MODE_SELECT] = memnew(Button);
main_menu_hbox->add_child(tool_button[TOOL_MODE_SELECT]);
tool_button[TOOL_MODE_SELECT]->set_toggle_mode(true);
@@ -8365,10 +8403,10 @@ Node3DEditor::Node3DEditor() {
main_menu_hbox->add_child(memnew(VSeparator));
- context_menu_panel = memnew(PanelContainer);
- context_menu_hbox = memnew(HBoxContainer);
- context_menu_panel->add_child(context_menu_hbox);
- main_flow->add_child(context_menu_panel);
+ context_toolbar_panel = memnew(PanelContainer);
+ context_toolbar_hbox = memnew(HBoxContainer);
+ context_toolbar_panel->add_child(context_toolbar_hbox);
+ main_flow->add_child(context_toolbar_panel);
// Get the view menu popup and have it stay open when a checkable item is selected
p = view_menu->get_popup();
diff --git a/editor/plugins/node_3d_editor_plugin.h b/editor/plugins/node_3d_editor_plugin.h
index e58e224ff4..2fb7804a67 100644
--- a/editor/plugins/node_3d_editor_plugin.h
+++ b/editor/plugins/node_3d_editor_plugin.h
@@ -56,9 +56,10 @@ class PanelContainer;
class ProceduralSkyMaterial;
class SubViewport;
class SubViewportContainer;
+class VSeparator;
class VSplitContainer;
-class WorldEnvironment;
class ViewportNavigationControl;
+class WorldEnvironment;
class ViewportRotationControl : public Control {
GDCLASS(ViewportRotationControl, Control);
@@ -715,8 +716,11 @@ private:
void _update_camera_override_viewport(Object *p_viewport);
// Used for secondary menu items which are displayed depending on the currently selected node
// (such as MeshInstance's "Mesh" menu).
- PanelContainer *context_menu_panel = nullptr;
- HBoxContainer *context_menu_hbox = nullptr;
+ PanelContainer *context_toolbar_panel = nullptr;
+ HBoxContainer *context_toolbar_hbox = nullptr;
+ HashMap<Control *, VSeparator *> context_toolbar_separators;
+
+ void _update_context_toolbar();
void _generate_selection_boxes();
diff --git a/editor/plugins/occluder_instance_3d_editor_plugin.cpp b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
index 3a05352ecf..321c330816 100644
--- a/editor/plugins/occluder_instance_3d_editor_plugin.cpp
+++ b/editor/plugins/occluder_instance_3d_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "occluder_instance_3d_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/gui/editor_file_dialog.h"
void OccluderInstance3DEditorPlugin::_bake_select_file(const String &p_file) {
@@ -104,7 +105,7 @@ void OccluderInstance3DEditorPlugin::_bind_methods() {
OccluderInstance3DEditorPlugin::OccluderInstance3DEditorPlugin() {
bake = memnew(Button);
bake->set_flat(true);
- bake->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Bake")));
+ bake->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
bake->set_text(TTR("Bake Occluders"));
bake->hide();
bake->connect("pressed", Callable(this, "_bake"));
diff --git a/editor/plugins/path_2d_editor_plugin.cpp b/editor/plugins/path_2d_editor_plugin.cpp
index 3a7805ba4c..61617bfd4f 100644
--- a/editor/plugins/path_2d_editor_plugin.cpp
+++ b/editor/plugins/path_2d_editor_plugin.cpp
@@ -532,19 +532,14 @@ Path2DEditor::Path2DEditor() {
mode = MODE_EDIT;
action = ACTION_NONE;
- base_hb = memnew(HBoxContainer);
- CanvasItemEditor::get_singleton()->add_control_to_menu_panel(base_hb);
-
- sep = memnew(VSeparator);
- base_hb->add_child(sep);
-
curve_edit = memnew(Button);
curve_edit->set_flat(true);
curve_edit->set_toggle_mode(true);
+ curve_edit->set_pressed(true);
curve_edit->set_focus_mode(Control::FOCUS_NONE);
curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Click: Add Point") + "\n" + TTR("Left Click: Split Segment (in curve)") + "\n" + TTR("Right Click: Delete Point"));
curve_edit->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_EDIT));
- base_hb->add_child(curve_edit);
+ add_child(curve_edit);
curve_edit_curve = memnew(Button);
curve_edit_curve->set_flat(true);
@@ -552,7 +547,7 @@ Path2DEditor::Path2DEditor() {
curve_edit_curve->set_focus_mode(Control::FOCUS_NONE);
curve_edit_curve->set_tooltip_text(TTR("Select Control Points (Shift+Drag)"));
curve_edit_curve->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_EDIT_CURVE));
- base_hb->add_child(curve_edit_curve);
+ add_child(curve_edit_curve);
curve_create = memnew(Button);
curve_create->set_flat(true);
@@ -560,7 +555,7 @@ Path2DEditor::Path2DEditor() {
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip_text(TTR("Add Point (in empty space)"));
curve_create->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_CREATE));
- base_hb->add_child(curve_create);
+ add_child(curve_create);
curve_del = memnew(Button);
curve_del->set_flat(true);
@@ -568,20 +563,20 @@ Path2DEditor::Path2DEditor() {
curve_del->set_focus_mode(Control::FOCUS_NONE);
curve_del->set_tooltip_text(TTR("Delete Point"));
curve_del->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(MODE_DELETE));
- base_hb->add_child(curve_del);
+ add_child(curve_del);
curve_close = memnew(Button);
curve_close->set_flat(true);
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip_text(TTR("Close Curve"));
curve_close->connect("pressed", callable_mp(this, &Path2DEditor::_mode_selected).bind(ACTION_CLOSE));
- base_hb->add_child(curve_close);
+ add_child(curve_close);
PopupMenu *menu;
handle_menu = memnew(MenuButton);
handle_menu->set_text(TTR("Options"));
- base_hb->add_child(handle_menu);
+ add_child(handle_menu);
menu = handle_menu->get_popup();
menu->add_check_item(TTR("Mirror Handle Angles"));
@@ -589,10 +584,6 @@ Path2DEditor::Path2DEditor() {
menu->add_check_item(TTR("Mirror Handle Lengths"));
menu->set_item_checked(HANDLE_OPTION_LENGTH, mirror_handle_length);
menu->connect("id_pressed", callable_mp(this, &Path2DEditor::_handle_option_pressed));
-
- base_hb->hide();
-
- curve_edit->set_pressed(true);
}
void Path2DEditorPlugin::edit(Object *p_object) {
@@ -606,11 +597,9 @@ bool Path2DEditorPlugin::handles(Object *p_object) const {
void Path2DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
path2d_editor->show();
- path2d_editor->base_hb->show();
} else {
path2d_editor->hide();
- path2d_editor->base_hb->hide();
path2d_editor->edit(nullptr);
}
}
diff --git a/editor/plugins/path_2d_editor_plugin.h b/editor/plugins/path_2d_editor_plugin.h
index 25af0bf616..b8816d9b1e 100644
--- a/editor/plugins/path_2d_editor_plugin.h
+++ b/editor/plugins/path_2d_editor_plugin.h
@@ -34,7 +34,6 @@
#include "editor/editor_plugin.h"
#include "scene/2d/path_2d.h"
#include "scene/gui/box_container.h"
-#include "scene/gui/separator.h"
class CanvasItemEditor;
class MenuButton;
@@ -47,7 +46,6 @@ class Path2DEditor : public HBoxContainer {
Path2D *node = nullptr;
HBoxContainer *base_hb = nullptr;
- Separator *sep = nullptr;
enum Mode {
MODE_CREATE,
diff --git a/editor/plugins/path_3d_editor_plugin.cpp b/editor/plugins/path_3d_editor_plugin.cpp
index f4c36f3816..e1b402475a 100644
--- a/editor/plugins/path_3d_editor_plugin.cpp
+++ b/editor/plugins/path_3d_editor_plugin.cpp
@@ -35,6 +35,7 @@
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "node_3d_editor_plugin.h"
#include "scene/gui/menu_button.h"
@@ -454,7 +455,7 @@ EditorPlugin::AfterGUIInput Path3DEditorPlugin::forward_3d_gui_input(Camera3D *p
set_handle_clicked(false);
}
- if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->is_ctrl_pressed()))) {
+ if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT && (curve_create->is_pressed() || (curve_edit->is_pressed() && mb->is_command_or_control_pressed()))) {
//click into curve, break it down
Vector<Vector3> v3a = c->tessellate();
int rc = v3a.size();
@@ -623,21 +624,9 @@ bool Path3DEditorPlugin::handles(Object *p_object) const {
void Path3DEditorPlugin::make_visible(bool p_visible) {
if (p_visible) {
- curve_create->show();
- curve_edit->show();
- curve_edit_curve->show();
- curve_del->show();
- curve_close->show();
- handle_menu->show();
- sep->show();
+ topmenu_bar->show();
} else {
- curve_create->hide();
- curve_edit->hide();
- curve_edit_curve->hide();
- curve_del->hide();
- curve_close->hide();
- handle_menu->hide();
- sep->hide();
+ topmenu_bar->hide();
{
Path3D *pre = path;
@@ -696,11 +685,11 @@ void Path3DEditorPlugin::_handle_option_pressed(int p_option) {
void Path3DEditorPlugin::_update_theme() {
// TODO: Split the EditorPlugin instance from the UI instance and connect this properly.
// See the 2D path editor for inspiration.
- curve_edit->set_icon(Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("CurveEdit")));
- curve_edit_curve->set_icon(Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("CurveCurve")));
- curve_create->set_icon(Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("CurveCreate")));
- curve_del->set_icon(Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("CurveDelete")));
- curve_close->set_icon(Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("CurveClose")));
+ curve_edit->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveEdit"), EditorStringName(EditorIcons)));
+ curve_edit_curve->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveCurve"), EditorStringName(EditorIcons)));
+ curve_create->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveCreate"), EditorStringName(EditorIcons)));
+ curve_del->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveDelete"), EditorStringName(EditorIcons)));
+ curve_close->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("CurveClose"), EditorStringName(EditorIcons)));
}
void Path3DEditorPlugin::_notification(int p_what) {
@@ -736,55 +725,49 @@ Path3DEditorPlugin::Path3DEditorPlugin() {
gizmo_plugin.instantiate();
Node3DEditor::get_singleton()->add_gizmo_plugin(gizmo_plugin);
- sep = memnew(VSeparator);
- sep->hide();
- Node3DEditor::get_singleton()->add_control_to_menu_panel(sep);
+ topmenu_bar = memnew(HBoxContainer);
+ topmenu_bar->hide();
+ Node3DEditor::get_singleton()->add_control_to_menu_panel(topmenu_bar);
curve_edit = memnew(Button);
curve_edit->set_flat(true);
curve_edit->set_toggle_mode(true);
- curve_edit->hide();
curve_edit->set_focus_mode(Control::FOCUS_NONE);
curve_edit->set_tooltip_text(TTR("Select Points") + "\n" + TTR("Shift+Drag: Select Control Points") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Click: Add Point") + "\n" + TTR("Right Click: Delete Point"));
- Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit);
+ topmenu_bar->add_child(curve_edit);
curve_edit_curve = memnew(Button);
curve_edit_curve->set_flat(true);
curve_edit_curve->set_toggle_mode(true);
- curve_edit_curve->hide();
curve_edit_curve->set_focus_mode(Control::FOCUS_NONE);
curve_edit_curve->set_tooltip_text(TTR("Select Control Points (Shift+Drag)"));
- Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_edit_curve);
+ topmenu_bar->add_child(curve_edit_curve);
curve_create = memnew(Button);
curve_create->set_flat(true);
curve_create->set_toggle_mode(true);
- curve_create->hide();
curve_create->set_focus_mode(Control::FOCUS_NONE);
curve_create->set_tooltip_text(TTR("Add Point (in empty space)") + "\n" + TTR("Split Segment (in curve)"));
- Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_create);
+ topmenu_bar->add_child(curve_create);
curve_del = memnew(Button);
curve_del->set_flat(true);
curve_del->set_toggle_mode(true);
- curve_del->hide();
curve_del->set_focus_mode(Control::FOCUS_NONE);
curve_del->set_tooltip_text(TTR("Delete Point"));
- Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_del);
+ topmenu_bar->add_child(curve_del);
curve_close = memnew(Button);
curve_close->set_flat(true);
- curve_close->hide();
curve_close->set_focus_mode(Control::FOCUS_NONE);
curve_close->set_tooltip_text(TTR("Close Curve"));
- Node3DEditor::get_singleton()->add_control_to_menu_panel(curve_close);
+ topmenu_bar->add_child(curve_close);
PopupMenu *menu;
handle_menu = memnew(MenuButton);
handle_menu->set_text(TTR("Options"));
- handle_menu->hide();
- Node3DEditor::get_singleton()->add_control_to_menu_panel(handle_menu);
+ topmenu_bar->add_child(handle_menu);
menu = handle_menu->get_popup();
menu->add_check_item(TTR("Mirror Handle Angles"));
@@ -822,6 +805,6 @@ Path3DGizmoPlugin::Path3DGizmoPlugin() {
Color path_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/path", Color(0.5, 0.5, 1.0, 0.8));
create_material("path_material", path_color);
create_material("path_thin_material", Color(0.5, 0.5, 0.5));
- create_handle_material("handles", false, Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("EditorPathSmoothHandle")));
- create_handle_material("sec_handles", false, Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("EditorCurveHandle")));
+ create_handle_material("handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorPathSmoothHandle"), EditorStringName(EditorIcons)));
+ create_handle_material("sec_handles", false, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorCurveHandle"), EditorStringName(EditorIcons)));
}
diff --git a/editor/plugins/path_3d_editor_plugin.h b/editor/plugins/path_3d_editor_plugin.h
index 9cac6e395a..871e6a1563 100644
--- a/editor/plugins/path_3d_editor_plugin.h
+++ b/editor/plugins/path_3d_editor_plugin.h
@@ -35,8 +35,8 @@
#include "editor/plugins/node_3d_editor_gizmos.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/path_3d.h"
-#include "scene/gui/separator.h"
+class HBoxContainer;
class MenuButton;
class Path3DGizmo : public EditorNode3DGizmo {
@@ -87,7 +87,7 @@ public:
class Path3DEditorPlugin : public EditorPlugin {
GDCLASS(Path3DEditorPlugin, EditorPlugin);
- Separator *sep = nullptr;
+ HBoxContainer *topmenu_bar = nullptr;
Button *curve_create = nullptr;
Button *curve_edit = nullptr;
Button *curve_edit_curve = nullptr;
diff --git a/editor/plugins/physical_bone_3d_editor_plugin.cpp b/editor/plugins/physical_bone_3d_editor_plugin.cpp
index c9b77b3edb..d01725fc42 100644
--- a/editor/plugins/physical_bone_3d_editor_plugin.cpp
+++ b/editor/plugins/physical_bone_3d_editor_plugin.cpp
@@ -30,6 +30,8 @@
#include "physical_bone_3d_editor_plugin.h"
+#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/gui/separator.h"
@@ -53,14 +55,14 @@ PhysicalBone3DEditor::PhysicalBone3DEditor() {
spatial_editor_hb->set_alignment(BoxContainer::ALIGNMENT_BEGIN);
Node3DEditor::get_singleton()->add_control_to_menu_panel(spatial_editor_hb);
- spatial_editor_hb->add_child(memnew(VSeparator));
-
button_transform_joint = memnew(Button);
button_transform_joint->set_flat(true);
spatial_editor_hb->add_child(button_transform_joint);
button_transform_joint->set_text(TTR("Move Joint"));
- button_transform_joint->set_icon(Node3DEditor::get_singleton()->get_editor_theme_icon(SNAME("PhysicalBone3D")));
+ // TODO: Rework this as a dedicated toolbar control so we can hook into theme changes and update it
+ // when the editor theme updates.
+ button_transform_joint->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("PhysicalBone3D"), EditorStringName(EditorIcons)));
button_transform_joint->set_toggle_mode(true);
button_transform_joint->connect("toggled", callable_mp(this, &PhysicalBone3DEditor::_on_toggle_button_transform_joint));
diff --git a/editor/plugins/polygon_2d_editor_plugin.cpp b/editor/plugins/polygon_2d_editor_plugin.cpp
index 5ed9f4946d..e700d28afb 100644
--- a/editor/plugins/polygon_2d_editor_plugin.cpp
+++ b/editor/plugins/polygon_2d_editor_plugin.cpp
@@ -1304,7 +1304,8 @@ Polygon2DEditor::Polygon2DEditor() {
uv_button[UV_MODE_CREATE]->set_tooltip_text(TTR("Create Polygon"));
uv_button[UV_MODE_CREATE_INTERNAL]->set_tooltip_text(TTR("Create Internal Vertex"));
uv_button[UV_MODE_REMOVE_INTERNAL]->set_tooltip_text(TTR("Remove Internal Vertex"));
- uv_button[UV_MODE_EDIT_POINT]->set_tooltip_text(TTR("Move Points") + "\n" + TTR("Ctrl: Rotate") + "\n" + TTR("Shift: Move All") + "\n" + TTR("Shift+Ctrl: Scale"));
+ Key key = (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL;
+ uv_button[UV_MODE_EDIT_POINT]->set_tooltip_text(TTR("Move Points") + "\n" + find_keycode_name(key) + TTR(": Rotate") + "\n" + TTR("Shift: Move All") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Shift: Scale"));
uv_button[UV_MODE_MOVE]->set_tooltip_text(TTR("Move Polygon"));
uv_button[UV_MODE_ROTATE]->set_tooltip_text(TTR("Rotate Polygon"));
uv_button[UV_MODE_SCALE]->set_tooltip_text(TTR("Scale Polygon"));
diff --git a/editor/plugins/polygon_3d_editor_plugin.cpp b/editor/plugins/polygon_3d_editor_plugin.cpp
index 451bd7a738..fa5413787c 100644
--- a/editor/plugins/polygon_3d_editor_plugin.cpp
+++ b/editor/plugins/polygon_3d_editor_plugin.cpp
@@ -36,6 +36,7 @@
#include "core/os/keyboard.h"
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "editor/plugins/node_3d_editor_plugin.h"
@@ -94,7 +95,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.");
+ ERR_FAIL_NULL_MSG(obj, "Edited object is not valid.");
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"));
@@ -183,7 +184,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
case MODE_EDIT: {
if (mb->get_button_index() == MouseButton::LEFT) {
if (mb->is_pressed()) {
- if (mb->is_ctrl_pressed()) {
+ if (mb->is_command_or_control_pressed()) {
if (poly.size() < 3) {
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Edit Poly"));
@@ -328,7 +329,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
Vector2 cpoint(spoint.x, spoint.y);
- if (snap_ignore && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (snap_ignore && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
snap_ignore = false;
}
@@ -348,7 +349,7 @@ EditorPlugin::AfterGUIInput Polygon3DEditor::forward_3d_gui_input(Camera3D *p_ca
float Polygon3DEditor::_get_depth() {
Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
- ERR_FAIL_COND_V_MSG(!obj, 0.0f, "Edited object is not valid.");
+ ERR_FAIL_NULL_V_MSG(obj, 0.0f, "Edited object is not valid.");
if (bool(obj->call("_has_editable_3d_polygon_no_depth"))) {
return 0.0f;
@@ -359,13 +360,13 @@ float Polygon3DEditor::_get_depth() {
PackedVector2Array Polygon3DEditor::_get_polygon() {
Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
- ERR_FAIL_COND_V_MSG(!obj, PackedVector2Array(), "Edited object is not valid.");
+ ERR_FAIL_NULL_V_MSG(obj, PackedVector2Array(), "Edited object is not valid.");
return PackedVector2Array(obj->call("get_polygon"));
}
void Polygon3DEditor::_set_polygon(PackedVector2Array p_poly) {
Object *obj = node_resource.is_valid() ? (Object *)node_resource.ptr() : node;
- ERR_FAIL_COND_MSG(!obj, "Edited object is not valid.");
+ ERR_FAIL_NULL_MSG(obj, "Edited object is not valid.");
obj->call("set_polygon", p_poly);
}
@@ -536,7 +537,6 @@ void Polygon3DEditor::_bind_methods() {
Polygon3DEditor::Polygon3DEditor() {
node = nullptr;
- add_child(memnew(VSeparator));
button_create = memnew(Button);
button_create->set_flat(true);
add_child(button_create);
@@ -569,7 +569,7 @@ Polygon3DEditor::Polygon3DEditor() {
handle_material->set_transparency(StandardMaterial3D::TRANSPARENCY_ALPHA);
handle_material->set_flag(StandardMaterial3D::FLAG_ALBEDO_FROM_VERTEX_COLOR, true);
handle_material->set_flag(StandardMaterial3D::FLAG_SRGB_VERTEX_COLOR, true);
- Ref<Texture2D> handle = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Editor3DHandle"));
+ Ref<Texture2D> handle = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Editor3DHandle"), EditorStringName(EditorIcons));
handle_material->set_point_size(handle->get_width());
handle_material->set_texture(StandardMaterial3D::TEXTURE_ALBEDO, handle);
diff --git a/editor/plugins/resource_preloader_editor_plugin.cpp b/editor/plugins/resource_preloader_editor_plugin.cpp
index e352fd27ad..ee7ad739b8 100644
--- a/editor/plugins/resource_preloader_editor_plugin.cpp
+++ b/editor/plugins/resource_preloader_editor_plugin.cpp
@@ -225,7 +225,7 @@ void ResourcePreloaderEditor::_cell_button_pressed(Object *p_item, int p_column,
}
TreeItem *item = Object::cast_to<TreeItem>(p_item);
- ERR_FAIL_COND(!item);
+ ERR_FAIL_NULL(item);
if (p_id == BUTTON_OPEN_SCENE) {
String rpath = item->get_text(p_column);
diff --git a/editor/plugins/script_editor_plugin.cpp b/editor/plugins/script_editor_plugin.cpp
index 2fe607a08c..901ac91a46 100644
--- a/editor/plugins/script_editor_plugin.cpp
+++ b/editor/plugins/script_editor_plugin.cpp
@@ -2376,7 +2376,7 @@ bool ScriptEditor::edit(const Ref<Resource> &p_resource, int p_line, int p_col,
break;
}
}
- ERR_FAIL_COND_V(!se, false);
+ ERR_FAIL_NULL_V(se, false);
se->set_edited_resource(p_resource);
@@ -2695,7 +2695,7 @@ void ScriptEditor::_editor_stop() {
}
void ScriptEditor::_add_callback(Object *p_obj, const String &p_function, const PackedStringArray &p_args) {
- ERR_FAIL_COND(!p_obj);
+ ERR_FAIL_NULL(p_obj);
Ref<Script> scr = p_obj->get_script();
ERR_FAIL_COND(!scr.is_valid());
@@ -3876,7 +3876,7 @@ ScriptEditor::ScriptEditor(WindowWrapper *p_wrapper) {
filename = memnew(Label);
filename->set_clip_text(true);
filename->set_h_size_flags(SIZE_EXPAND_FILL);
- filename->add_theme_style_override("normal", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("normal"), SNAME("LineEdit")));
+ filename->add_theme_style_override("normal", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("normal"), SNAME("LineEdit")));
buttons_hbox->add_child(filename);
members_overview_alphabeta_sort_button = memnew(Button);
diff --git a/editor/plugins/script_text_editor.cpp b/editor/plugins/script_text_editor.cpp
index 511e4dfd15..d5ad21e346 100644
--- a/editor/plugins/script_text_editor.cpp
+++ b/editor/plugins/script_text_editor.cpp
@@ -181,10 +181,12 @@ void ScriptTextEditor::_load_theme_settings() {
Color updated_marked_line_color = EDITOR_GET("text_editor/theme/highlighting/mark_color");
Color updated_safe_line_number_color = EDITOR_GET("text_editor/theme/highlighting/safe_line_number_color");
+ Color updated_folded_code_region_color = EDITOR_GET("text_editor/theme/highlighting/folded_code_region_color");
bool safe_line_number_color_updated = updated_safe_line_number_color != safe_line_number_color;
bool marked_line_color_updated = updated_marked_line_color != marked_line_color;
- if (safe_line_number_color_updated || marked_line_color_updated) {
+ bool folded_code_region_color_updated = updated_folded_code_region_color != folded_code_region_color;
+ if (safe_line_number_color_updated || marked_line_color_updated || folded_code_region_color_updated) {
safe_line_number_color = updated_safe_line_number_color;
for (int i = 0; i < text_edit->get_line_count(); i++) {
if (marked_line_color_updated && text_edit->get_line_background_color(i) == marked_line_color) {
@@ -194,8 +196,13 @@ void ScriptTextEditor::_load_theme_settings() {
if (safe_line_number_color_updated && text_edit->get_line_gutter_item_color(i, line_number_gutter) != default_line_number_color) {
text_edit->set_line_gutter_item_color(i, line_number_gutter, safe_line_number_color);
}
+
+ if (folded_code_region_color_updated && text_edit->get_line_background_color(i) == folded_code_region_color) {
+ text_edit->set_line_background_color(i, updated_folded_code_region_color);
+ }
}
marked_line_color = updated_marked_line_color;
+ folded_code_region_color = updated_folded_code_region_color;
}
theme_loaded = true;
@@ -647,7 +654,8 @@ void ScriptTextEditor::_update_errors() {
bool last_is_safe = false;
for (int i = 0; i < te->get_line_count(); i++) {
if (errors.is_empty()) {
- te->set_line_background_color(i, Color(0, 0, 0, 0));
+ bool is_folded_code_region = te->is_line_code_region_start(i) && te->is_line_folded(i);
+ te->set_line_background_color(i, is_folded_code_region ? folded_code_region_color : Color(0, 0, 0, 0));
} else {
for (const ScriptLanguage::ScriptError &E : errors) {
bool error_line = i == E.line - 1;
@@ -882,14 +890,19 @@ void ScriptTextEditor::_lookup_symbol(const String &p_symbol, int p_row, int p_c
Error lc_error = script->get_language()->lookup_code(code_text, p_symbol, script->get_path(), base, result);
if (ScriptServer::is_global_class(p_symbol)) {
EditorNode::get_singleton()->load_resource(ScriptServer::get_global_class_path(p_symbol));
- } else if (p_symbol.is_resource_file()) {
+ } else if (p_symbol.is_resource_file() || p_symbol.begins_with("uid://")) {
+ String symbol = p_symbol;
+ if (symbol.begins_with("uid://")) {
+ symbol = ResourceUID::get_singleton()->get_id_path(ResourceUID::get_singleton()->text_to_id(symbol));
+ }
+
List<String> scene_extensions;
ResourceLoader::get_recognized_extensions_for_type("PackedScene", &scene_extensions);
- if (scene_extensions.find(p_symbol.get_extension())) {
- EditorNode::get_singleton()->load_scene(p_symbol);
+ if (scene_extensions.find(symbol.get_extension())) {
+ EditorNode::get_singleton()->load_scene(symbol);
} else {
- EditorNode::get_singleton()->load_resource(p_symbol);
+ EditorNode::get_singleton()->load_resource(symbol);
}
} else if (lc_error == OK) {
@@ -1016,7 +1029,7 @@ void ScriptTextEditor::_validate_symbol(const String &p_symbol) {
String lc_text = code_editor->get_text_editor()->get_text_for_symbol_lookup();
Error lc_error = script->get_language()->lookup_code(lc_text, p_symbol, script->get_path(), base, result);
bool is_singleton = ProjectSettings::get_singleton()->has_autoload(p_symbol) && ProjectSettings::get_singleton()->get_autoload(p_symbol).is_singleton;
- if (ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || lc_error == OK || is_singleton) {
+ if (lc_error == OK || is_singleton || ScriptServer::is_global_class(p_symbol) || p_symbol.is_resource_file() || p_symbol.begins_with("uid://")) {
text_edit->set_symbol_lookup_word_as_valid(true);
} else if (p_symbol.is_relative_path()) {
String path = _get_absolute_path(p_symbol);
@@ -1312,6 +1325,9 @@ void ScriptTextEditor::_edit_option(int p_op) {
tx->unfold_all_lines();
tx->queue_redraw();
} break;
+ case EDIT_CREATE_CODE_REGION: {
+ tx->create_code_region();
+ } break;
case EDIT_TOGGLE_COMMENT: {
_edit_option_toggle_inline_comment();
} break;
@@ -1736,7 +1752,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
Array files = d["files"];
String text_to_drop;
- bool preload = Input::get_singleton()->is_key_pressed(Key::CTRL);
+ bool preload = Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL);
for (int i = 0; i < files.size(); i++) {
if (i > 0) {
text_to_drop += ", ";
@@ -1776,7 +1792,7 @@ void ScriptTextEditor::drop_data_fw(const Point2 &p_point, const Variant &p_data
Array nodes = d["nodes"];
String text_to_drop;
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
bool use_type = EDITOR_GET("text_editor/completion/add_type_hints");
for (int i = 0; i < nodes.size(); i++) {
NodePath np = nodes[i];
@@ -2064,6 +2080,7 @@ void ScriptTextEditor::_make_context_menu(bool p_selection, bool p_color, bool p
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_uppercase"), EDIT_TO_UPPERCASE);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/convert_to_lowercase"), EDIT_TO_LOWERCASE);
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/evaluate_selection"), EDIT_EVALUATE);
+ context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/create_code_region"), EDIT_CREATE_CODE_REGION);
}
if (p_foldable) {
context_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
@@ -2112,16 +2129,16 @@ void ScriptTextEditor::_enable_code_editor() {
editor_box->add_child(warnings_panel);
warnings_panel->add_theme_font_override(
- "normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("main"), EditorStringName(EditorFonts)));
+ "normal_font", EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("main"), EditorStringName(EditorFonts)));
warnings_panel->add_theme_font_size_override(
- "normal_font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("main_size"), EditorStringName(EditorFonts)));
+ "normal_font_size", EditorNode::get_singleton()->get_editor_theme()->get_font_size(SNAME("main_size"), EditorStringName(EditorFonts)));
warnings_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_warning_clicked));
editor_box->add_child(errors_panel);
errors_panel->add_theme_font_override(
- "normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("main"), EditorStringName(EditorFonts)));
+ "normal_font", EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("main"), EditorStringName(EditorFonts)));
errors_panel->add_theme_font_size_override(
- "normal_font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("main_size"), EditorStringName(EditorFonts)));
+ "normal_font_size", EditorNode::get_singleton()->get_editor_theme()->get_font_size(SNAME("main_size"), EditorStringName(EditorFonts)));
errors_panel->connect("meta_clicked", callable_mp(this, &ScriptTextEditor::_error_clicked));
add_child(context_menu);
@@ -2178,6 +2195,7 @@ void ScriptTextEditor::_enable_code_editor() {
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/toggle_fold_line"), EDIT_TOGGLE_FOLD_LINE);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/fold_all_lines"), EDIT_FOLD_ALL_LINES);
sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/unfold_all_lines"), EDIT_UNFOLD_ALL_LINES);
+ sub_menu->add_shortcut(ED_GET_SHORTCUT("script_text_editor/create_code_region"), EDIT_CREATE_CODE_REGION);
sub_menu->connect("id_pressed", callable_mp(this, &ScriptTextEditor::_edit_option));
edit_menu->get_popup()->add_child(sub_menu);
edit_menu->get_popup()->add_submenu_item(TTR("Folding"), "folding_menu");
@@ -2373,6 +2391,7 @@ void ScriptTextEditor::register_editor() {
ED_SHORTCUT("script_text_editor/toggle_fold_line", TTR("Fold/Unfold Line"), KeyModifierMask::ALT | Key::F);
ED_SHORTCUT_OVERRIDE("script_text_editor/toggle_fold_line", "macos", KeyModifierMask::CTRL | KeyModifierMask::META | Key::F);
ED_SHORTCUT("script_text_editor/fold_all_lines", TTR("Fold All Lines"), Key::NONE);
+ ED_SHORTCUT("script_text_editor/create_code_region", TTR("Create Code Region"), KeyModifierMask::ALT | Key::R);
ED_SHORTCUT("script_text_editor/unfold_all_lines", TTR("Unfold All Lines"), Key::NONE);
ED_SHORTCUT("script_text_editor/duplicate_selection", TTR("Duplicate Selection"), KeyModifierMask::SHIFT | KeyModifierMask::CTRL | Key::D);
ED_SHORTCUT_OVERRIDE("script_text_editor/duplicate_selection", "macos", KeyModifierMask::SHIFT | KeyModifierMask::META | Key::C);
diff --git a/editor/plugins/script_text_editor.h b/editor/plugins/script_text_editor.h
index d275013b91..0efe7d54e3 100644
--- a/editor/plugins/script_text_editor.h
+++ b/editor/plugins/script_text_editor.h
@@ -98,6 +98,7 @@ class ScriptTextEditor : public ScriptEditorBase {
Color safe_line_number_color = Color(1, 1, 1);
Color marked_line_color = Color(1, 1, 1);
+ Color folded_code_region_color = Color(1, 1, 1);
PopupPanel *color_panel = nullptr;
ColorPicker *color_picker = nullptr;
@@ -133,6 +134,7 @@ class ScriptTextEditor : public ScriptEditorBase {
EDIT_TOGGLE_WORD_WRAP,
EDIT_TOGGLE_FOLD_LINE,
EDIT_FOLD_ALL_LINES,
+ EDIT_CREATE_CODE_REGION,
EDIT_UNFOLD_ALL_LINES,
SEARCH_FIND,
SEARCH_FIND_NEXT,
diff --git a/editor/plugins/skeleton_2d_editor_plugin.cpp b/editor/plugins/skeleton_2d_editor_plugin.cpp
index 9b67648322..44543ffa9f 100644
--- a/editor/plugins/skeleton_2d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_2d_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "skeleton_2d_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/editor_undo_redo_manager.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/mesh_instance_2d.h"
@@ -98,7 +99,7 @@ Skeleton2DEditor::Skeleton2DEditor() {
CanvasItemEditor::get_singleton()->add_control_to_menu_panel(options);
options->set_text(TTR("Skeleton2D"));
- options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Skeleton2D")));
+ options->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Skeleton2D"), EditorStringName(EditorIcons)));
options->get_popup()->add_item(TTR("Reset to Rest Pose"), MENU_OPTION_SET_REST);
options->get_popup()->add_separator();
diff --git a/editor/plugins/skeleton_3d_editor_plugin.cpp b/editor/plugins/skeleton_3d_editor_plugin.cpp
index 7aa333c198..4a44cea5ba 100644
--- a/editor/plugins/skeleton_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_3d_editor_plugin.cpp
@@ -712,12 +712,12 @@ void Skeleton3DEditor::create_editors() {
add_child(file_dialog);
// Create Top Menu Bar.
- separator = memnew(VSeparator);
- ne->add_control_to_menu_panel(separator);
+ HBoxContainer *topmenu_bar = memnew(HBoxContainer);
+ ne->add_control_to_menu_panel(topmenu_bar);
// Create Skeleton Option in Top Menu Bar.
skeleton_options = memnew(MenuButton);
- ne->add_control_to_menu_panel(skeleton_options);
+ topmenu_bar->add_child(skeleton_options);
skeleton_options->set_text(TTR("Skeleton3D"));
@@ -737,7 +737,7 @@ void Skeleton3DEditor::create_editors() {
button_binds.resize(1);
edit_mode_button = memnew(Button);
- ne->add_control_to_menu_panel(edit_mode_button);
+ topmenu_bar->add_child(edit_mode_button);
edit_mode_button->set_flat(true);
edit_mode_button->set_toggle_mode(true);
edit_mode_button->set_focus_mode(FOCUS_NONE);
@@ -753,7 +753,7 @@ void Skeleton3DEditor::create_editors() {
// Keying buttons.
animation_hb = memnew(HBoxContainer);
- ne->add_control_to_menu_panel(animation_hb);
+ topmenu_bar->add_child(animation_hb);
animation_hb->add_child(memnew(VSeparator));
animation_hb->hide();
@@ -936,7 +936,7 @@ void fragment() {
}
)");
handle_material->set_shader(handle_shader);
- Ref<Texture2D> handle = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("EditorBoneHandle"));
+ Ref<Texture2D> handle = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("EditorBoneHandle"), EditorStringName(EditorIcons));
handle_material->set_shader_parameter("point_size", handle->get_width());
handle_material->set_shader_parameter("texture_albedo", handle);
@@ -1122,7 +1122,7 @@ bool EditorInspectorPluginSkeleton::can_handle(Object *p_object) {
void EditorInspectorPluginSkeleton::parse_begin(Object *p_object) {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_object);
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
skel_editor = memnew(Skeleton3DEditor(this, skeleton));
add_custom_control(skel_editor);
@@ -1244,7 +1244,7 @@ int Skeleton3DGizmoPlugin::get_priority() const {
int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gizmo, Camera3D *p_camera, const Vector2 &p_point) const {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
- ERR_FAIL_COND_V(!skeleton, -1);
+ ERR_FAIL_NULL_V(skeleton, -1);
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
@@ -1285,14 +1285,14 @@ int Skeleton3DGizmoPlugin::subgizmos_intersect_ray(const EditorNode3DGizmo *p_gi
Transform3D Skeleton3DGizmoPlugin::get_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id) const {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
- ERR_FAIL_COND_V(!skeleton, Transform3D());
+ ERR_FAIL_NULL_V(skeleton, Transform3D());
return skeleton->get_bone_global_pose(p_id);
}
void Skeleton3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gizmo, int p_id, Transform3D p_transform) {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
// Prepare for global to local.
Transform3D original_to_local;
@@ -1321,7 +1321,7 @@ void Skeleton3DGizmoPlugin::set_subgizmo_transform(const EditorNode3DGizmo *p_gi
void Skeleton3DGizmoPlugin::commit_subgizmos(const EditorNode3DGizmo *p_gizmo, const Vector<int> &p_ids, const Vector<Transform3D> &p_restore, bool p_cancel) {
Skeleton3D *skeleton = Object::cast_to<Skeleton3D>(p_gizmo->get_node_3d());
- ERR_FAIL_COND(!skeleton);
+ ERR_FAIL_NULL(skeleton);
Skeleton3DEditor *se = Skeleton3DEditor::get_singleton();
Node3DEditor *ne = Node3DEditor::get_singleton();
diff --git a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
index d081dd7c06..74b60c132e 100644
--- a/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
+++ b/editor/plugins/skeleton_ik_3d_editor_plugin.cpp
@@ -31,6 +31,7 @@
#include "skeleton_ik_3d_editor_plugin.h"
#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "scene/3d/skeleton_ik_3d.h"
#include "scene/gui/button.h"
@@ -84,7 +85,7 @@ void SkeletonIK3DEditorPlugin::_bind_methods() {
SkeletonIK3DEditorPlugin::SkeletonIK3DEditorPlugin() {
play_btn = memnew(Button);
- play_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Play")));
+ play_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Play"), EditorStringName(EditorIcons)));
play_btn->set_text(TTR("Play IK"));
play_btn->set_toggle_mode(true);
play_btn->hide();
diff --git a/editor/plugins/sprite_2d_editor_plugin.cpp b/editor/plugins/sprite_2d_editor_plugin.cpp
index 1363669928..e90609cd2f 100644
--- a/editor/plugins/sprite_2d_editor_plugin.cpp
+++ b/editor/plugins/sprite_2d_editor_plugin.cpp
@@ -74,7 +74,7 @@ Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float
ClipperLib::PolyNode *p = solution.GetFirst();
- ERR_FAIL_COND_V(!p, points);
+ ERR_FAIL_NULL_V(p, points);
while (p->IsHole()) {
p = p->GetNext();
@@ -97,7 +97,7 @@ Vector<Vector2> expand(const Vector<Vector2> &points, const Rect2i &rect, float
Vector<Vector2> outPoints;
ClipperLib::PolyNode *p2 = out.GetFirst();
- ERR_FAIL_COND_V(!p2, points);
+ ERR_FAIL_NULL_V(p2, points);
while (p2->IsHole()) {
p2 = p2->GetNext();
diff --git a/editor/plugins/sprite_frames_editor_plugin.cpp b/editor/plugins/sprite_frames_editor_plugin.cpp
index 54b72b6b3e..1844358069 100644
--- a/editor/plugins/sprite_frames_editor_plugin.cpp
+++ b/editor/plugins/sprite_frames_editor_plugin.cpp
@@ -188,7 +188,7 @@ void SpriteFramesEditor::_sheet_preview_input(const Ref<InputEvent> &p_event) {
// Prevent double-toggling the same frame when moving the mouse when the mouse button is still held.
frames_toggled_by_mouse_hover.insert(this_idx);
- if (mb->is_ctrl_pressed()) {
+ if (mb->is_command_or_control_pressed()) {
frames_selected.erase(this_idx);
} else if (!frames_selected.has(this_idx)) {
frames_selected.insert(this_idx, selected_count);
@@ -255,6 +255,7 @@ void SpriteFramesEditor::_sheet_scroll_input(const Ref<InputEvent> &p_event) {
// Zoom in/out using Ctrl + mouse wheel. This is done on the ScrollContainer
// to allow performing this action anywhere, even if the cursor isn't
// hovering the texture in the workspace.
+ // keep CTRL and not CMD_OR_CTRL as CTRL is expected even on MacOS.
if (mb->get_button_index() == MouseButton::WHEEL_UP && mb->is_pressed() && mb->is_ctrl_pressed()) {
_sheet_zoom_on_position(scale_ratio, mb->get_position());
// Don't scroll up after zooming in.
@@ -855,7 +856,7 @@ void SpriteFramesEditor::_animation_selected() {
}
TreeItem *selected = animations->get_selected();
- ERR_FAIL_COND(!selected);
+ ERR_FAIL_NULL(selected);
edited_anim = selected->get_text(0);
if (animated_sprite) {
@@ -1485,7 +1486,7 @@ void SpriteFramesEditor::drop_data_fw(const Point2 &p_point, const Variant &p_da
if (String(d["type"]) == "files") {
Vector<String> files = d["files"];
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
_prepare_sprite_sheet(files[0]);
} else {
_file_load_request(files, at_pos);
diff --git a/editor/plugins/text_shader_editor.cpp b/editor/plugins/text_shader_editor.cpp
index 27e32cc8f7..b68b283a61 100644
--- a/editor/plugins/text_shader_editor.cpp
+++ b/editor/plugins/text_shader_editor.cpp
@@ -327,8 +327,8 @@ void ShaderTextEditor::_load_theme_settings() {
if (warnings_panel) {
// Warnings panel.
- warnings_panel->add_theme_font_override("normal_font", EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("main"), EditorStringName(EditorFonts)));
- warnings_panel->add_theme_font_size_override("normal_font_size", EditorNode::get_singleton()->get_gui_base()->get_theme_font_size(SNAME("main_size"), EditorStringName(EditorFonts)));
+ warnings_panel->add_theme_font_override("normal_font", EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("main"), EditorStringName(EditorFonts)));
+ warnings_panel->add_theme_font_size_override("normal_font_size", EditorNode::get_singleton()->get_editor_theme()->get_font_size(SNAME("main_size"), EditorStringName(EditorFonts)));
}
}
@@ -1167,7 +1167,7 @@ TextShaderEditor::TextShaderEditor() {
hbc->add_child(edit_menu);
hbc->add_child(goto_menu);
hbc->add_child(help_menu);
- hbc->add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("ScriptEditorPanel"), EditorStringName(EditorStyles)));
+ hbc->add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("ScriptEditorPanel"), EditorStringName(EditorStyles)));
VSplitContainer *editor_box = memnew(VSplitContainer);
main_container->add_child(editor_box);
diff --git a/editor/plugins/texture_editor_plugin.cpp b/editor/plugins/texture_editor_plugin.cpp
index 74a03c1e97..ec5785e605 100644
--- a/editor/plugins/texture_editor_plugin.cpp
+++ b/editor/plugins/texture_editor_plugin.cpp
@@ -167,7 +167,7 @@ void EditorInspectorPluginTexture::parse_begin(Object *p_object) {
Ref<Image> image(Object::cast_to<Image>(p_object));
texture = ImageTexture::create_from_image(image);
- ERR_FAIL_COND_MSG(texture == nullptr, "Failed to create the texture from an invalid image.");
+ ERR_FAIL_NULL_MSG(texture, "Failed to create the texture from an invalid image.");
}
add_custom_control(memnew(TexturePreview(texture, true)));
diff --git a/editor/plugins/theme_editor_plugin.cpp b/editor/plugins/theme_editor_plugin.cpp
index ffe6c01ef0..f52a0913e2 100644
--- a/editor/plugins/theme_editor_plugin.cpp
+++ b/editor/plugins/theme_editor_plugin.cpp
@@ -3548,7 +3548,7 @@ void ThemeEditor::_add_preview_tab(ThemeEditorPreview *p_preview_tab, const Stri
preview_tabs->add_tab(p_preview_name, p_icon);
preview_tabs_content->add_child(p_preview_tab);
- preview_tabs->set_tab_button_icon(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_gui_base()->get_theme_icon(SNAME("close"), SNAME("TabBar")));
+ preview_tabs->set_tab_button_icon(preview_tabs->get_tab_count() - 1, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("close"), SNAME("TabBar")));
p_preview_tab->connect("control_picked", callable_mp(this, &ThemeEditor::_preview_control_picked));
preview_tabs->set_current_tab(preview_tabs->get_tab_count() - 1);
diff --git a/editor/plugins/theme_editor_preview.cpp b/editor/plugins/theme_editor_preview.cpp
index 61bce0a89c..14a25e4e29 100644
--- a/editor/plugins/theme_editor_preview.cpp
+++ b/editor/plugins/theme_editor_preview.cpp
@@ -217,7 +217,7 @@ void ThemeEditorPreview::_notification(int p_what) {
theme_cache.preview_picker_overlay_color = get_theme_color(SNAME("preview_picker_overlay_color"), SNAME("ThemeEditor"));
theme_cache.preview_picker_label = get_theme_stylebox(SNAME("preview_picker_label"), SNAME("ThemeEditor"));
theme_cache.preview_picker_font = get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"), EditorStringName(EditorFonts));
+ theme_cache.font_size = get_theme_default_font_size();
} break;
case NOTIFICATION_PROCESS: {
diff --git a/editor/plugins/tiles/tile_data_editors.cpp b/editor/plugins/tiles/tile_data_editors.cpp
index 26487e8dfd..19dd2d51c0 100644
--- a/editor/plugins/tiles/tile_data_editors.cpp
+++ b/editor/plugins/tiles/tile_data_editors.cpp
@@ -883,10 +883,10 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
button_advanced_menu->get_popup()->add_item(TTR("Reset to default tile shape"), RESET_TO_DEFAULT_TILE, Key::F);
button_advanced_menu->get_popup()->add_item(TTR("Clear"), CLEAR_TILE, Key::C);
button_advanced_menu->get_popup()->add_separator();
- button_advanced_menu->get_popup()->add_icon_item(get_editor_theme_icon(SNAME("RotateRight")), TTR("Rotate Right"), ROTATE_RIGHT, Key::R);
- button_advanced_menu->get_popup()->add_icon_item(get_editor_theme_icon(SNAME("RotateLeft")), TTR("Rotate Left"), ROTATE_LEFT, Key::E);
- button_advanced_menu->get_popup()->add_icon_item(get_editor_theme_icon(SNAME("MirrorX")), TTR("Flip Horizontally"), FLIP_HORIZONTALLY, Key::H);
- button_advanced_menu->get_popup()->add_icon_item(get_editor_theme_icon(SNAME("MirrorY")), TTR("Flip Vertically"), FLIP_VERTICALLY, Key::V);
+ button_advanced_menu->get_popup()->add_item(TTR("Rotate Right"), ROTATE_RIGHT, Key::R);
+ button_advanced_menu->get_popup()->add_item(TTR("Rotate Left"), ROTATE_LEFT, Key::E);
+ button_advanced_menu->get_popup()->add_item(TTR("Flip Horizontally"), FLIP_HORIZONTALLY, Key::H);
+ button_advanced_menu->get_popup()->add_item(TTR("Flip Vertically"), FLIP_VERTICALLY, Key::V);
button_advanced_menu->get_popup()->connect("id_pressed", callable_mp(this, &GenericTilePolygonEditor::_advanced_menu_item_pressed));
button_advanced_menu->set_focus_mode(FOCUS_ALL);
toolbar->add_child(button_advanced_menu);
@@ -937,7 +937,6 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
root->add_child(editor_zoom_widget);
button_center_view = memnew(Button);
- button_center_view->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("CenterView")));
button_center_view->set_anchors_and_offsets_preset(Control::PRESET_TOP_RIGHT, Control::PRESET_MODE_MINSIZE, 5);
button_center_view->connect("pressed", callable_mp(this, &GenericTilePolygonEditor::_center_view));
button_center_view->set_flat(true);
@@ -949,19 +948,19 @@ GenericTilePolygonEditor::GenericTilePolygonEditor() {
}
void TileDataDefaultEditor::_property_value_changed(StringName p_property, Variant p_value, StringName p_field) {
- ERR_FAIL_COND(!dummy_object);
+ ERR_FAIL_NULL(dummy_object);
dummy_object->set(p_property, p_value);
emit_signal(SNAME("needs_redraw"));
}
Variant TileDataDefaultEditor::_get_painted_value() {
- ERR_FAIL_COND_V(!dummy_object, Variant());
+ ERR_FAIL_NULL_V(dummy_object, Variant());
return dummy_object->get(property);
}
void TileDataDefaultEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Variant value = tile_data->get(property);
dummy_object->set(property, value);
if (property_editor) {
@@ -971,13 +970,13 @@ void TileDataDefaultEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_at
void TileDataDefaultEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
tile_data->set(property, p_value);
}
Variant TileDataDefaultEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND_V(!tile_data, Variant());
+ ERR_FAIL_NULL_V(tile_data, Variant());
return tile_data->get(property);
}
@@ -1187,7 +1186,7 @@ void TileDataDefaultEditor::forward_painting_alternatives_gui_input(TileAtlasVie
void TileDataDefaultEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
bool valid;
Variant value = tile_data->get(property, &valid);
@@ -1316,7 +1315,7 @@ TileDataDefaultEditor::~TileDataDefaultEditor() {
void TileDataTextureOriginEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Vector2i tile_set_tile_size = tile_set->get_tile_size();
Color color = Color(1.0, 1.0, 1.0);
@@ -1350,7 +1349,7 @@ void TileDataTextureOriginEditor::draw_over_tile(CanvasItem *p_canvas_item, Tran
void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
bool valid;
Variant value = tile_data->get(property, &valid);
@@ -1371,7 +1370,7 @@ void TileDataPositionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform
void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Color color = Color(1.0, 1.0, 1.0);
if (p_selected) {
@@ -1398,7 +1397,7 @@ void TileDataYSortEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D
void TileDataOcclusionShapeEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Color grid_color = EDITOR_GET("editors/tiles_editor/grid_color");
Color selection_color = Color().from_hsv(Math::fposmod(grid_color.get_h() + 0.5, 1.0), grid_color.get_s(), grid_color.get_v(), 1.0);
@@ -1430,7 +1429,7 @@ Variant TileDataOcclusionShapeEditor::_get_painted_value() {
void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Ref<OccluderPolygon2D> occluder_polygon = tile_data->get_occluder(occlusion_layer);
polygon_editor->clear_polygons();
@@ -1442,7 +1441,7 @@ void TileDataOcclusionShapeEditor::_set_painted_value(TileSetAtlasSource *p_tile
void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Ref<OccluderPolygon2D> occluder_polygon = p_value;
tile_data->set_occluder(occlusion_layer, occluder_polygon);
@@ -1451,7 +1450,7 @@ void TileDataOcclusionShapeEditor::_set_value(TileSetAtlasSource *p_tile_set_atl
Variant TileDataOcclusionShapeEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND_V(!tile_data, Variant());
+ ERR_FAIL_NULL_V(tile_data, Variant());
return tile_data->get_occluder(occlusion_layer);
}
@@ -1572,7 +1571,7 @@ Variant TileDataCollisionEditor::_get_painted_value() {
void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
polygon_editor->clear_polygons();
for (int i = 0; i < tile_data->get_collision_polygons_count(physics_layer); i++) {
@@ -1598,7 +1597,7 @@ void TileDataCollisionEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_
void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Dictionary dict = p_value;
tile_data->set_constant_linear_velocity(physics_layer, dict["linear_velocity"]);
@@ -1617,7 +1616,7 @@ void TileDataCollisionEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_so
Variant TileDataCollisionEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND_V(!tile_data, Variant());
+ ERR_FAIL_NULL_V(tile_data, Variant());
Dictionary dict;
dict["linear_velocity"] = tile_data->get_constant_linear_velocity(physics_layer);
@@ -1718,7 +1717,7 @@ TileDataCollisionEditor::~TileDataCollisionEditor() {
void TileDataCollisionEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
// Draw all shapes.
Vector<Color> color;
@@ -2768,7 +2767,7 @@ void TileDataTerrainsEditor::forward_painting_alternatives_gui_input(TileAtlasVi
void TileDataTerrainsEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
tile_set->draw_terrains(p_canvas_item, p_transform, tile_data);
}
@@ -2836,7 +2835,7 @@ Variant TileDataNavigationEditor::_get_painted_value() {
void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Ref<NavigationPolygon> nav_polygon = tile_data->get_navigation_polygon(navigation_layer);
polygon_editor->clear_polygons();
@@ -2850,7 +2849,7 @@ void TileDataNavigationEditor::_set_painted_value(TileSetAtlasSource *p_tile_set
void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile, Variant p_value) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
Ref<NavigationPolygon> nav_polygon = p_value;
tile_data->set_navigation_polygon(navigation_layer, nav_polygon);
@@ -2859,7 +2858,7 @@ void TileDataNavigationEditor::_set_value(TileSetAtlasSource *p_tile_set_atlas_s
Variant TileDataNavigationEditor::_get_value(TileSetAtlasSource *p_tile_set_atlas_source, Vector2 p_coords, int p_alternative_tile) {
TileData *tile_data = p_tile_set_atlas_source->get_tile_data(p_coords, p_alternative_tile);
- ERR_FAIL_COND_V(!tile_data, Variant());
+ ERR_FAIL_NULL_V(tile_data, Variant());
return tile_data->get_navigation_polygon(navigation_layer);
}
@@ -2894,7 +2893,7 @@ TileDataNavigationEditor::TileDataNavigationEditor() {
void TileDataNavigationEditor::draw_over_tile(CanvasItem *p_canvas_item, Transform2D p_transform, TileMapCell p_cell, bool p_selected) {
TileData *tile_data = _get_tile_data(p_cell);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
// Draw all shapes.
RenderingServer::get_singleton()->canvas_item_add_set_transform(p_canvas_item->get_canvas_item(), p_transform);
diff --git a/editor/plugins/tiles/tile_map_editor.cpp b/editor/plugins/tiles/tile_map_editor.cpp
index fa35a03a22..69b702bf3f 100644
--- a/editor/plugins/tiles/tile_map_editor.cpp
+++ b/editor/plugins/tiles/tile_map_editor.cpp
@@ -73,34 +73,21 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
// Show only the correct settings.
if (tool_buttons_group->get_pressed_button() == select_tool_button) {
- } else if (tool_buttons_group->get_pressed_button() == paint_tool_button) {
+ transform_toolbar->show();
+ } else if (tool_buttons_group->get_pressed_button() != bucket_tool_button) {
tools_settings_vsep->show();
picker_button->show();
erase_button->show();
+ transform_toolbar->show();
tools_settings_vsep_2->show();
random_tile_toggle->show();
scatter_label->show();
scatter_spinbox->show();
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
- tools_settings_vsep->show();
- picker_button->show();
- erase_button->show();
- tools_settings_vsep_2->show();
- random_tile_toggle->show();
- scatter_label->show();
- scatter_spinbox->show();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button) {
- tools_settings_vsep->show();
- picker_button->show();
- erase_button->show();
- tools_settings_vsep_2->show();
- random_tile_toggle->show();
- scatter_label->show();
- scatter_spinbox->show();
- } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button) {
+ } else {
tools_settings_vsep->show();
picker_button->show();
erase_button->show();
+ transform_toolbar->show();
tools_settings_vsep_2->show();
bucket_contiguous_checkbox->show();
random_tile_toggle->show();
@@ -109,6 +96,47 @@ void TileMapEditorTilesPlugin::_update_toolbar() {
}
}
+void TileMapEditorTilesPlugin::_update_transform_buttons() {
+ TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
+ if (!tile_map) {
+ return;
+ }
+
+ Ref<TileSet> tile_set = tile_map->get_tileset();
+ if (tile_set.is_null() || selection_pattern.is_null()) {
+ return;
+ }
+
+ bool has_scene_tile = false;
+ for (const KeyValue<Vector2i, TileMapCell> &E : selection_pattern->get_pattern()) {
+ if (Object::cast_to<TileSetScenesCollectionSource>(tile_set->get_source(E.value.source_id).ptr())) {
+ has_scene_tile = true;
+ break;
+ }
+ }
+
+ if (has_scene_tile) {
+ _set_transform_buttons_state({}, { transform_button_rotate_left, transform_button_rotate_right, transform_button_flip_h, transform_button_flip_v },
+ TTR("Can't transform scene tiles."));
+ } else if (tile_set->get_tile_shape() != TileSet::TILE_SHAPE_SQUARE && selection_pattern->get_size() != Vector2i(1, 1)) {
+ _set_transform_buttons_state({ transform_button_flip_h, transform_button_flip_v }, { transform_button_rotate_left, transform_button_rotate_right },
+ TTR("Can't rotate patterns when using non-square tile grid."));
+ } else {
+ _set_transform_buttons_state({ transform_button_rotate_left, transform_button_rotate_right, transform_button_flip_h, transform_button_flip_v }, {}, "");
+ }
+}
+
+void TileMapEditorTilesPlugin::_set_transform_buttons_state(const Vector<Button *> &p_enabled_buttons, const Vector<Button *> &p_disabled_buttons, const String &p_why_disabled) {
+ for (Button *button : p_enabled_buttons) {
+ button->set_disabled(false);
+ button->set_tooltip_text("");
+ }
+ for (Button *button : p_disabled_buttons) {
+ button->set_disabled(true);
+ button->set_tooltip_text(p_why_disabled);
+ }
+}
+
Vector<TileMapSubEditorPlugin::TabData> TileMapEditorTilesPlugin::get_tabs() const {
Vector<TileMapSubEditorPlugin::TabData> tabs;
tabs.push_back({ toolbar, tiles_bottom_panel });
@@ -355,7 +383,7 @@ void TileMapEditorTilesPlugin::_update_atlas_view() {
int source_id = sources_list->get_item_metadata(sources_list->get_current());
TileSetSource *source = *tile_set->get_source(source_id);
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
- ERR_FAIL_COND(!atlas_source);
+ ERR_FAIL_NULL(atlas_source);
tile_atlas_view->set_atlas_source(*tile_map->get_tileset(), atlas_source, source_id);
TilesEditorUtils::get_singleton()->synchronize_atlas_view(tile_atlas_view);
@@ -376,7 +404,7 @@ void TileMapEditorTilesPlugin::_update_scenes_collection_view() {
int source_id = sources_list->get_item_metadata(sources_list->get_current());
TileSetSource *source = *tile_set->get_source(source_id);
TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
- ERR_FAIL_COND(!scenes_collection_source);
+ ERR_FAIL_NULL(scenes_collection_source);
// Clear the list.
scene_tiles_list->clear();
@@ -436,7 +464,7 @@ void TileMapEditorTilesPlugin::_scenes_list_multi_selected(int p_index, bool p_s
int source_id = sources_list->get_item_metadata(sources_list->get_current());
TileSetSource *source = *tile_set->get_source(source_id);
TileSetScenesCollectionSource *scenes_collection_source = Object::cast_to<TileSetScenesCollectionSource>(source);
- ERR_FAIL_COND(!scenes_collection_source);
+ ERR_FAIL_NULL(scenes_collection_source);
TileMapCell selected = TileMapCell(source_id, Vector2i(), scene_id);
@@ -480,6 +508,11 @@ void TileMapEditorTilesPlugin::_update_theme() {
erase_button->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("Eraser")));
random_tile_toggle->set_icon(tiles_bottom_panel->get_editor_theme_icon(SNAME("RandomNumberGenerator")));
+ transform_button_rotate_left->set_icon(tiles_bottom_panel->get_editor_theme_icon("RotateLeft"));
+ transform_button_rotate_right->set_icon(tiles_bottom_panel->get_editor_theme_icon("RotateRight"));
+ transform_button_flip_h->set_icon(tiles_bottom_panel->get_editor_theme_icon("MirrorX"));
+ transform_button_flip_v->set_icon(tiles_bottom_panel->get_editor_theme_icon("MirrorY"));
+
missing_atlas_texture_icon = tiles_bottom_panel->get_editor_theme_icon(SNAME("TileSet"));
_update_tile_set_sources_list();
}
@@ -573,8 +606,17 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
Ref<InputEventKey> k = p_event;
if (k.is_valid() && k->is_pressed() && !k->is_echo()) {
for (BaseButton *b : viewport_shortcut_buttons) {
+ if (b->is_disabled()) {
+ continue;
+ }
+
if (b->get_shortcut().is_valid() && b->get_shortcut()->matches_event(p_event)) {
- b->set_pressed(b->get_button_group().is_valid() || !b->is_pressed());
+ if (b->is_toggle_mode()) {
+ b->set_pressed(b->get_button_group().is_valid() || !b->is_pressed());
+ } else {
+ // Can't press a button without toggle mode, so just emit the signal directly.
+ b->emit_signal(SNAME("pressed"));
+ }
return true;
}
}
@@ -649,7 +691,7 @@ bool TileMapEditorTilesPlugin::forward_canvas_gui_input(const Ref<InputEvent> &p
}
} else if (tool_buttons_group->get_pressed_button() == select_tool_button) {
drag_start_mouse_pos = mpos;
- if (tile_map_selection.has(tile_map->local_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed()) {
+ if (tile_map_selection.has(tile_map->local_to_map(drag_start_mouse_pos)) && !mb->is_shift_pressed() && !mb->is_command_or_control_pressed()) {
// Move the selection
_update_selection_pattern_from_tilemap_selection(); // Make sure the pattern is up to date before moving.
drag_type = DRAG_TYPE_MOVE;
@@ -924,18 +966,18 @@ void TileMapEditorTilesPlugin::forward_canvas_draw_over_viewport(Control *p_over
Rect2 dest_rect;
dest_rect.size = source_rect.size;
- bool transpose = tile_data->get_transpose();
+ bool transpose = tile_data->get_transpose() ^ bool(E.value.alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
if (transpose) {
dest_rect.position = (tile_map->map_to_local(E.key) - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
} else {
dest_rect.position = (tile_map->map_to_local(E.key) - dest_rect.size / 2 - tile_offset);
}
- if (tile_data->get_flip_h()) {
+ if (tile_data->get_flip_h() ^ bool(E.value.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H)) {
dest_rect.size.x = -dest_rect.size.x;
}
- if (tile_data->get_flip_v()) {
+ if (tile_data->get_flip_v() ^ bool(E.value.alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V)) {
dest_rect.size.y = -dest_rect.size.y;
}
@@ -1002,7 +1044,7 @@ TileMapCell TileMapEditorTilesPlugin::_pick_random_tile(Ref<TileMapPattern> p_pa
TileSetAtlasSource *atlas_source = Object::cast_to<TileSetAtlasSource>(source);
if (atlas_source) {
TileData *tile_data = atlas_source->get_tile_data(atlas_coords, alternative_tile);
- ERR_FAIL_COND_V(!tile_data, TileMapCell());
+ ERR_FAIL_NULL_V(tile_data, TileMapCell());
sum += tile_data->get_probability();
} else {
sum += 1.0;
@@ -1475,6 +1517,94 @@ void TileMapEditorTilesPlugin::_stop_dragging() {
drag_type = DRAG_TYPE_NONE;
}
+void TileMapEditorTilesPlugin::_apply_transform(int p_type) {
+ if (selection_pattern.is_null() || selection_pattern->is_empty()) {
+ return;
+ }
+
+ Ref<TileMapPattern> transformed_pattern;
+ transformed_pattern.instantiate();
+ bool keep_shape = selection_pattern->get_size() == Vector2i(1, 1);
+
+ Vector2i size = selection_pattern->get_size();
+ for (int y = 0; y < size.y; y++) {
+ for (int x = 0; x < size.x; x++) {
+ Vector2i src_coords = Vector2i(x, y);
+ if (!selection_pattern->has_cell(src_coords)) {
+ continue;
+ }
+
+ Vector2i dst_coords;
+
+ if (keep_shape) {
+ dst_coords = src_coords;
+ } else if (p_type == TRANSFORM_ROTATE_LEFT) {
+ dst_coords = Vector2i(y, size.x - x - 1);
+ } else if (p_type == TRANSFORM_ROTATE_RIGHT) {
+ dst_coords = Vector2i(size.y - y - 1, x);
+ } else if (p_type == TRANSFORM_FLIP_H) {
+ dst_coords = Vector2i(size.x - x - 1, y);
+ } else if (p_type == TRANSFORM_FLIP_V) {
+ dst_coords = Vector2i(x, size.y - y - 1);
+ }
+
+ transformed_pattern->set_cell(dst_coords,
+ selection_pattern->get_cell_source_id(src_coords), selection_pattern->get_cell_atlas_coords(src_coords),
+ _get_transformed_alternative(selection_pattern->get_cell_alternative_tile(src_coords), p_type));
+ }
+ }
+ selection_pattern = transformed_pattern;
+ CanvasItemEditor::get_singleton()->update_viewport();
+}
+
+int TileMapEditorTilesPlugin::_get_transformed_alternative(int p_alternative_id, int p_transform) {
+ bool transform_flip_h = p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H;
+ bool transform_flip_v = p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V;
+ bool transform_transpose = p_alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE;
+
+ switch (p_transform) {
+ case TRANSFORM_ROTATE_LEFT:
+ case TRANSFORM_ROTATE_RIGHT: {
+ // A matrix with every possible flip/transpose combination, sorted by what comes next when you rotate.
+ const LocalVector<bool> rotation_matrix = {
+ 0, 0, 0,
+ 0, 1, 1,
+ 1, 1, 0,
+ 1, 0, 1,
+ 1, 0, 0,
+ 0, 0, 1,
+ 0, 1, 0,
+ 1, 1, 1
+ };
+
+ for (int i = 0; i < 8; i++) {
+ if (transform_flip_h == rotation_matrix[i * 3] && transform_flip_v == rotation_matrix[i * 3 + 1] && transform_transpose == rotation_matrix[i * 3 + 2]) {
+ if (p_transform == TRANSFORM_ROTATE_LEFT) {
+ i = i / 4 * 4 + (i + 1) % 4;
+ } else {
+ i = i / 4 * 4 + Math::posmod(i - 1, 4);
+ }
+ transform_flip_h = rotation_matrix[i * 3];
+ transform_flip_v = rotation_matrix[i * 3 + 1];
+ transform_transpose = rotation_matrix[i * 3 + 2];
+ break;
+ }
+ }
+ } break;
+ case TRANSFORM_FLIP_H: {
+ transform_flip_h = !transform_flip_h;
+ } break;
+ case TRANSFORM_FLIP_V: {
+ transform_flip_v = !transform_flip_v;
+ } break;
+ }
+
+ return TileSetAtlasSource::alternative_no_transform(p_alternative_id) |
+ int(transform_flip_h) * TileSetAtlasSource::TRANSFORM_FLIP_H |
+ int(transform_flip_v) * TileSetAtlasSource::TRANSFORM_FLIP_V |
+ int(transform_transpose) * TileSetAtlasSource::TRANSFORM_TRANSPOSE;
+}
+
void TileMapEditorTilesPlugin::_update_fix_selected_and_hovered() {
TileMap *tile_map = Object::cast_to<TileMap>(ObjectDB::get_instance(tile_map_id));
if (!tile_map) {
@@ -1589,6 +1719,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tilemap_selection(
coords_array.push_back(E);
}
selection_pattern = tile_map->get_pattern(tile_map_layer, coords_array);
+ _update_transform_buttons();
}
void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles_selection() {
@@ -1662,6 +1793,7 @@ void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_tiles_sele
vertical_offset += MAX(organized_size.y, 1);
}
CanvasItemEditor::get_singleton()->update_viewport();
+ _update_transform_buttons();
}
void TileMapEditorTilesPlugin::_update_selection_pattern_from_tileset_pattern_selection() {
@@ -1700,6 +1832,7 @@ void TileMapEditorTilesPlugin::_update_tileset_selection_from_selection_pattern(
_update_source_display();
tile_atlas_control->queue_redraw();
alternative_tiles_control->queue_redraw();
+ _update_transform_buttons();
}
void TileMapEditorTilesPlugin::_tile_atlas_control_draw() {
@@ -2100,7 +2233,7 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
paint_tool_button->set_toggle_mode(true);
paint_tool_button->set_button_group(tool_buttons_group);
paint_tool_button->set_shortcut(ED_SHORTCUT("tiles_editor/paint_tool", TTR("Paint"), Key::D));
- paint_tool_button->set_tooltip_text(TTR("Shift: Draw line.") + "\n" + TTR("Shift+Ctrl: Draw rectangle."));
+ paint_tool_button->set_tooltip_text(TTR("Shift: Draw line.") + "\n" + keycode_get_string((Key)KeyModifierMask::CMD_OR_CTRL) + TTR("Shift: Draw rectangle."));
paint_tool_button->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_update_toolbar));
tilemap_tiles_tools_buttons->add_child(paint_tool_button);
viewport_shortcut_buttons.push_back(paint_tool_button);
@@ -2146,7 +2279,8 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
picker_button->set_flat(true);
picker_button->set_toggle_mode(true);
picker_button->set_shortcut(ED_SHORTCUT("tiles_editor/picker", TTR("Picker"), Key::P));
- picker_button->set_tooltip_text(TTR("Alternatively hold Ctrl with other tools to pick tile."));
+ Key key = (OS::get_singleton()->has_feature("macos") || OS::get_singleton()->has_feature("web_macos") || OS::get_singleton()->has_feature("web_ios")) ? Key::META : Key::CTRL;
+ picker_button->set_tooltip_text(vformat(TTR("Alternatively hold %s with other tools to pick tile."), find_keycode_name(key)));
picker_button->connect("pressed", callable_mp(CanvasItemEditor::get_singleton(), &CanvasItemEditor::update_viewport));
tools_settings->add_child(picker_button);
viewport_shortcut_buttons.push_back(picker_button);
@@ -2161,6 +2295,39 @@ TileMapEditorTilesPlugin::TileMapEditorTilesPlugin() {
tools_settings->add_child(erase_button);
viewport_shortcut_buttons.push_back(erase_button);
+ // Transform toolbar.
+ transform_toolbar = memnew(HBoxContainer);
+ tools_settings->add_child(transform_toolbar);
+ transform_toolbar->add_child(memnew(VSeparator));
+
+ transform_button_rotate_left = memnew(Button);
+ transform_button_rotate_left->set_flat(true);
+ transform_button_rotate_left->set_shortcut(ED_SHORTCUT("tiles_editor/rotate_tile_left", TTR("Rotate Tile Left"), Key::Z));
+ transform_toolbar->add_child(transform_button_rotate_left);
+ transform_button_rotate_left->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_apply_transform).bind(TRANSFORM_ROTATE_LEFT));
+ viewport_shortcut_buttons.push_back(transform_button_rotate_left);
+
+ transform_button_rotate_right = memnew(Button);
+ transform_button_rotate_right->set_flat(true);
+ transform_button_rotate_right->set_shortcut(ED_SHORTCUT("tiles_editor/rotate_tile_right", TTR("Rotate Tile Right"), Key::X));
+ transform_toolbar->add_child(transform_button_rotate_right);
+ transform_button_rotate_right->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_apply_transform).bind(TRANSFORM_ROTATE_RIGHT));
+ viewport_shortcut_buttons.push_back(transform_button_rotate_right);
+
+ transform_button_flip_h = memnew(Button);
+ transform_button_flip_h->set_flat(true);
+ transform_button_flip_h->set_shortcut(ED_SHORTCUT("tiles_editor/flip_tile_horizontal", TTR("Flip Tile Horizontally"), Key::C));
+ transform_toolbar->add_child(transform_button_flip_h);
+ transform_button_flip_h->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_apply_transform).bind(TRANSFORM_FLIP_H));
+ viewport_shortcut_buttons.push_back(transform_button_flip_h);
+
+ transform_button_flip_v = memnew(Button);
+ transform_button_flip_v->set_flat(true);
+ transform_button_flip_v->set_shortcut(ED_SHORTCUT("tiles_editor/flip_tile_vertical", TTR("Flip Tile Vertically"), Key::V));
+ transform_toolbar->add_child(transform_button_flip_v);
+ transform_button_flip_v->connect("pressed", callable_mp(this, &TileMapEditorTilesPlugin::_apply_transform).bind(TRANSFORM_FLIP_V));
+ viewport_shortcut_buttons.push_back(transform_button_flip_v);
+
// Separator 2.
tools_settings_vsep_2 = memnew(VSeparator);
tools_settings->add_child(tools_settings_vsep_2);
@@ -2352,25 +2519,11 @@ void TileMapEditorTerrainsPlugin::_update_toolbar() {
}
// Show only the correct settings.
- if (tool_buttons_group->get_pressed_button() == paint_tool_button) {
- tools_settings_vsep->show();
- picker_button->show();
- erase_button->show();
- tools_settings_vsep_2->hide();
- bucket_contiguous_checkbox->hide();
- } else if (tool_buttons_group->get_pressed_button() == line_tool_button) {
+ if (tool_buttons_group->get_pressed_button() != bucket_tool_button) {
tools_settings_vsep->show();
picker_button->show();
erase_button->show();
- tools_settings_vsep_2->hide();
- bucket_contiguous_checkbox->hide();
- } else if (tool_buttons_group->get_pressed_button() == rect_tool_button) {
- tools_settings_vsep->show();
- picker_button->show();
- erase_button->show();
- tools_settings_vsep_2->hide();
- bucket_contiguous_checkbox->hide();
- } else if (tool_buttons_group->get_pressed_button() == bucket_tool_button) {
+ } else {
tools_settings_vsep->show();
picker_button->show();
erase_button->show();
@@ -3496,7 +3649,6 @@ TileMapEditorTerrainsPlugin::~TileMapEditorTerrainsPlugin() {
void TileMapEditor::_notification(int p_what) {
switch (p_what) {
- case NOTIFICATION_ENTER_TREE:
case NOTIFICATION_THEME_CHANGED: {
missing_tile_texture = get_editor_theme_icon(SNAME("StatusWarning"));
warning_pattern_texture = get_editor_theme_icon(SNAME("WarningPattern"));
@@ -3600,7 +3752,7 @@ void TileMapEditor::_update_bottom_panel() {
}
Vector<Vector2i> TileMapEditor::get_line(TileMap *p_tile_map, Vector2i p_from_cell, Vector2i p_to_cell) {
- ERR_FAIL_COND_V(!p_tile_map, Vector<Vector2i>());
+ ERR_FAIL_NULL_V(p_tile_map, Vector<Vector2i>());
Ref<TileSet> tile_set = p_tile_map->get_tileset();
ERR_FAIL_COND_V(!tile_set.is_valid(), Vector<Vector2i>());
diff --git a/editor/plugins/tiles/tile_map_editor.h b/editor/plugins/tiles/tile_map_editor.h
index ab5787b78f..c9a1efe62d 100644
--- a/editor/plugins/tiles/tile_map_editor.h
+++ b/editor/plugins/tiles/tile_map_editor.h
@@ -48,6 +48,8 @@
#include "scene/gui/tab_bar.h"
#include "scene/gui/tree.h"
+class TileMapEditor;
+
class TileMapSubEditorPlugin : public Object {
public:
struct TabData {
@@ -68,6 +70,14 @@ public:
class TileMapEditorTilesPlugin : public TileMapSubEditorPlugin {
GDCLASS(TileMapEditorTilesPlugin, TileMapSubEditorPlugin);
+public:
+ enum {
+ TRANSFORM_ROTATE_LEFT,
+ TRANSFORM_ROTATE_RIGHT,
+ TRANSFORM_FLIP_H,
+ TRANSFORM_FLIP_V,
+ };
+
private:
ObjectID tile_map_id;
int tile_map_layer = -1;
@@ -89,6 +99,12 @@ private:
Button *picker_button = nullptr;
Button *erase_button = nullptr;
+ HBoxContainer *transform_toolbar = nullptr;
+ Button *transform_button_rotate_left = nullptr;
+ Button *transform_button_rotate_right = nullptr;
+ Button *transform_button_flip_h = nullptr;
+ Button *transform_button_flip_v = nullptr;
+
VSeparator *tools_settings_vsep_2 = nullptr;
CheckBox *bucket_contiguous_checkbox = nullptr;
Button *random_tile_toggle = nullptr;
@@ -101,6 +117,8 @@ private:
void _on_scattering_spinbox_changed(double p_value);
void _update_toolbar();
+ void _update_transform_buttons();
+ void _set_transform_buttons_state(const Vector<Button *> &p_enabled_buttons, const Vector<Button *> &p_disabled_buttons, const String &p_why_disabled);
///// Tilemap editing. /////
bool has_mouse = false;
@@ -129,6 +147,9 @@ private:
HashMap<Vector2i, TileMapCell> _draw_bucket_fill(Vector2i p_coords, bool p_contiguous, bool p_erase);
void _stop_dragging();
+ void _apply_transform(int p_type);
+ int _get_transformed_alternative(int p_alternative_id, int p_transform);
+
///// Selection system. /////
RBSet<Vector2i> tile_map_selection;
Ref<TileMapPattern> tile_map_clipboard;
diff --git a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
index a2e4c4a784..4037655e2c 100644
--- a/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_atlas_source_editor.cpp
@@ -295,7 +295,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_set(const StringName &p_na
bool valid = false;
TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
- ERR_FAIL_COND_V(!tile_data, false);
+ ERR_FAIL_NULL_V(tile_data, false);
tile_data->set(p_name, p_value, &valid);
any_valid |= valid;
@@ -383,7 +383,7 @@ bool TileSetAtlasSourceEditor::AtlasTileProxyObject::_get(const StringName &p_na
const int &alternative = E.alternative;
TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
- ERR_FAIL_COND_V(!tile_data, false);
+ ERR_FAIL_NULL_V(tile_data, false);
bool valid = false;
r_ret = tile_data->get(p_name, &valid);
@@ -461,7 +461,7 @@ void TileSetAtlasSourceEditor::AtlasTileProxyObject::_get_property_list(List<Pro
const int &alternative = E.alternative;
TileData *tile_data = tile_set_atlas_source->get_tile_data(coords, alternative);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
List<PropertyInfo> list;
tile_data->get_property_list(&list);
@@ -1202,7 +1202,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
if (tools_button_group->get_pressed_button() == tool_setup_atlas_source_button) {
if (tools_settings_erase_button->is_pressed()) {
// Erasing
- if (mb->is_ctrl_pressed() || mb->is_shift_pressed()) {
+ if (mb->is_command_or_control_pressed() || mb->is_shift_pressed()) {
// Remove tiles using rect.
// Setup the dragging info.
@@ -1241,7 +1241,7 @@ void TileSetAtlasSourceEditor::_tile_atlas_control_gui_input(const Ref<InputEven
// Create a tile.
tile_set_atlas_source->create_tile(coords);
}
- } else if (mb->is_ctrl_pressed()) {
+ } else if (mb->is_command_or_control_pressed()) {
// Create tiles using rect.
drag_type = DRAG_TYPE_CREATE_TILES_USING_RECT;
drag_start_mouse_pos = mouse_local_pos;
@@ -2157,7 +2157,7 @@ Vector2i TileSetAtlasSourceEditor::_get_drag_offset_tile_coords(const Vector2i &
void TileSetAtlasSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetAtlasSource *p_tile_set_atlas_source, int p_source_id) {
ERR_FAIL_COND(!p_tile_set.is_valid());
- ERR_FAIL_COND(!p_tile_set_atlas_source);
+ ERR_FAIL_NULL(p_tile_set_atlas_source);
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_atlas_source);
@@ -2406,7 +2406,7 @@ void TileSetAtlasSourceEditor::_notification(int p_what) {
case NOTIFICATION_THEME_CHANGED: {
tool_setup_atlas_source_button->set_icon(get_editor_theme_icon(SNAME("Tools")));
tool_select_button->set_icon(get_editor_theme_icon(SNAME("ToolSelect")));
- tool_paint_button->set_icon(get_editor_theme_icon(SNAME("CanvasItem")));
+ tool_paint_button->set_icon(get_editor_theme_icon(SNAME("Paint")));
tools_settings_erase_button->set_icon(get_editor_theme_icon(SNAME("Eraser")));
tool_advanced_menu_button->set_icon(get_editor_theme_icon(SNAME("GuiTabMenuHl")));
@@ -2771,7 +2771,7 @@ void EditorPropertyTilePolygon::_polygons_changed() {
void EditorPropertyTilePolygon::update_property() {
TileSetAtlasSourceEditor::AtlasTileProxyObject *atlas_tile_proxy_object = Object::cast_to<TileSetAtlasSourceEditor::AtlasTileProxyObject>(get_edited_object());
- ERR_FAIL_COND(!atlas_tile_proxy_object);
+ ERR_FAIL_NULL(atlas_tile_proxy_object);
ERR_FAIL_COND(atlas_tile_proxy_object->get_edited_tiles().is_empty());
Ref<TileSetAtlasSource> tile_set_atlas_source = atlas_tile_proxy_object->get_edited_tile_set_atlas_source();
diff --git a/editor/plugins/tiles/tile_set_editor.cpp b/editor/plugins/tiles/tile_set_editor.cpp
index 53cc59b718..0209e6a6d6 100644
--- a/editor/plugins/tiles/tile_set_editor.cpp
+++ b/editor/plugins/tiles/tile_set_editor.cpp
@@ -568,7 +568,7 @@ void TileSetEditor::_move_tile_set_array_element(Object *p_undo_redo, Object *p_
for (int k = 0; k < tas->get_alternative_tiles_count(tile_id); k++) {
int alternative_id = tas->get_alternative_tile_id(tile_id, k);
TileData *tile_data = tas->get_tile_data(tile_id, alternative_id);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
// Actually saving stuff.
if (p_array_prefix == "occlusion_layer_") {
@@ -687,7 +687,7 @@ void TileSetEditor::_undo_redo_inspector_callback(Object *p_undo_redo, Object *p
for (int k = 0; k < tas->get_alternative_tiles_count(tile_id); k++) {
int alternative_id = tas->get_alternative_tile_id(tile_id, k);
TileData *tile_data = tas->get_tile_data(tile_id, alternative_id);
- ERR_FAIL_COND(!tile_data);
+ ERR_FAIL_NULL(tile_data);
if (components.size() == 2 && components[0].begins_with("terrain_set_") && components[0].trim_prefix("terrain_set_").is_valid_int() && components[1] == "mode") {
ADD_UNDO(tile_data, "terrain_set");
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 6b9250010e..939ee5f056 100644
--- a/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
+++ b/editor/plugins/tiles/tile_set_scenes_collection_source_editor.cpp
@@ -107,7 +107,7 @@ void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::_b
void TileSetScenesCollectionSourceEditor::TileSetScenesCollectionProxyObject::edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id) {
ERR_FAIL_COND(!p_tile_set.is_valid());
- ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
+ ERR_FAIL_NULL(p_tile_set_scenes_collection_source);
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_scenes_collection_source);
@@ -197,7 +197,7 @@ void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::_get_property_li
}
void TileSetScenesCollectionSourceEditor::SceneTileProxyObject::edit(TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_scene_id) {
- ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
+ ERR_FAIL_NULL(p_tile_set_scenes_collection_source);
ERR_FAIL_COND(!p_tile_set_scenes_collection_source->has_scene_tile_id(p_scene_id));
if (tile_set_scenes_collection_source == p_tile_set_scenes_collection_source && scene_id == p_scene_id) {
@@ -390,7 +390,7 @@ void TileSetScenesCollectionSourceEditor::_notification(int p_what) {
void TileSetScenesCollectionSourceEditor::edit(Ref<TileSet> p_tile_set, TileSetScenesCollectionSource *p_tile_set_scenes_collection_source, int p_source_id) {
ERR_FAIL_COND(!p_tile_set.is_valid());
- ERR_FAIL_COND(!p_tile_set_scenes_collection_source);
+ ERR_FAIL_NULL(p_tile_set_scenes_collection_source);
ERR_FAIL_COND(p_source_id < 0);
ERR_FAIL_COND(p_tile_set->get_source(p_source_id) != p_tile_set_scenes_collection_source);
diff --git a/editor/plugins/tiles/tiles_editor_plugin.cpp b/editor/plugins/tiles/tiles_editor_plugin.cpp
index 904348d3bf..4d4b1fa734 100644
--- a/editor/plugins/tiles/tiles_editor_plugin.cpp
+++ b/editor/plugins/tiles/tiles_editor_plugin.cpp
@@ -38,6 +38,7 @@
#include "editor/editor_node.h"
#include "editor/editor_scale.h"
#include "editor/editor_settings.h"
+#include "editor/editor_string_names.h"
#include "editor/plugins/canvas_item_editor_plugin.h"
#include "scene/2d/tile_map.h"
@@ -163,8 +164,8 @@ void TilesEditorUtils::set_sources_lists_current(int p_current) {
void TilesEditorUtils::synchronize_sources_list(Object *p_current_list, Object *p_current_sort_button) {
ItemList *item_list = Object::cast_to<ItemList>(p_current_list);
MenuButton *sorting_button = Object::cast_to<MenuButton>(p_current_sort_button);
- ERR_FAIL_COND(!item_list);
- ERR_FAIL_COND(!sorting_button);
+ ERR_FAIL_NULL(item_list);
+ ERR_FAIL_NULL(sorting_button);
if (sorting_button->is_visible_in_tree()) {
for (int i = 0; i != SOURCE_SORT_MAX; i++) {
@@ -195,7 +196,7 @@ void TilesEditorUtils::set_atlas_view_transform(float p_zoom, Vector2 p_scroll)
void TilesEditorUtils::synchronize_atlas_view(Object *p_current) {
TileAtlasView *tile_atlas_view = Object::cast_to<TileAtlasView>(p_current);
- ERR_FAIL_COND(!tile_atlas_view);
+ ERR_FAIL_NULL(tile_atlas_view);
if (tile_atlas_view->is_visible_in_tree()) {
tile_atlas_view->set_transform(atlas_view_zoom, atlas_view_scroll);
@@ -289,10 +290,12 @@ void TilesEditorUtils::display_tile_set_editor_panel() {
}
void TilesEditorUtils::draw_selection_rect(CanvasItem *p_ci, const Rect2 &p_rect, const Color &p_color) {
+ Ref<Texture2D> selection_texture = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("TileSelection"), EditorStringName(EditorIcons));
+
real_t scale = p_ci->get_global_transform().get_scale().x * 0.5;
p_ci->draw_set_transform(p_rect.position, 0, Vector2(1, 1) / scale);
RS::get_singleton()->canvas_item_add_nine_patch(
- p_ci->get_canvas_item(), Rect2(Vector2(), p_rect.size * scale), Rect2(), EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("TileSelection"))->get_rid(),
+ p_ci->get_canvas_item(), Rect2(Vector2(), p_rect.size * scale), Rect2(), selection_texture->get_rid(),
Vector2(2, 2), Vector2(2, 2), RS::NINE_PATCH_STRETCH, RS::NINE_PATCH_STRETCH, false, p_color);
p_ci->draw_set_transform_matrix(Transform2D());
}
diff --git a/editor/plugins/version_control_editor_plugin.cpp b/editor/plugins/version_control_editor_plugin.cpp
index a6c98e646e..d6b08b42cb 100644
--- a/editor/plugins/version_control_editor_plugin.cpp
+++ b/editor/plugins/version_control_editor_plugin.cpp
@@ -174,7 +174,7 @@ void VersionControlEditorPlugin::_update_set_up_warning(String p_new_text) {
set_up_ssh_passphrase->get_text().is_empty();
if (empty_settings) {
- set_up_warning_text->add_theme_color_override(SNAME("font_color"), EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), EditorStringName(Editor)));
+ set_up_warning_text->add_theme_color_override(SNAME("font_color"), EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor)));
set_up_warning_text->set_text(TTR("Remote settings are empty. VCS features that use the network may not work."));
} else {
set_up_warning_text->set_text("");
@@ -192,7 +192,7 @@ void VersionControlEditorPlugin::_refresh_branch_list() {
String current_branch = EditorVCSInterface::get_singleton()->get_current_branch_name();
for (int i = 0; i < branch_list.size(); i++) {
- branch_select->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("VcsBranches")), branch_list[i], i);
+ branch_select->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("VcsBranches"), EditorStringName(EditorIcons)), branch_list[i], i);
if (branch_list[i] == current_branch) {
branch_select->select(i);
@@ -252,7 +252,7 @@ void VersionControlEditorPlugin::_refresh_remote_list() {
remote_select->set_disabled(remotes.is_empty());
for (int i = 0; i < remotes.size(); i++) {
- remote_select->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("ArrowUp")), remotes[i], i);
+ remote_select->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ArrowUp"), EditorStringName(EditorIcons)), remotes[i], i);
remote_select->set_item_metadata(i, remotes[i]);
if (remotes[i] == current_remote) {
@@ -422,9 +422,9 @@ void VersionControlEditorPlugin::_add_new_item(Tree *p_tree, String p_file_path,
new_item->set_meta(SNAME("change_type"), p_change);
new_item->set_custom_color(0, change_type_to_color[p_change]);
- new_item->add_button(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("File")), BUTTON_TYPE_OPEN, false, TTR("Open in editor"));
+ new_item->add_button(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("File"), EditorStringName(EditorIcons)), BUTTON_TYPE_OPEN, false, TTR("Open in editor"));
if (p_tree == unstaged_files) {
- new_item->add_button(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Close")), BUTTON_TYPE_DISCARD, false, TTR("Discard changes"));
+ new_item->add_button(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Close"), EditorStringName(EditorIcons)), BUTTON_TYPE_DISCARD, false, TTR("Discard changes"));
}
}
@@ -570,8 +570,8 @@ void VersionControlEditorPlugin::_display_diff(int p_idx) {
String commit_author = meta_data[SNAME("commit_author")];
String commit_date_string = meta_data[SNAME("commit_date_string")];
- diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("doc_bold"), EditorStringName(EditorFonts)));
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), EditorStringName(Editor)));
+ diff->push_font(EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("doc_bold"), EditorStringName(EditorFonts)));
+ diff->push_color(EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("accent_color"), EditorStringName(Editor)));
diff->add_text(TTR("Commit:") + " " + commit_id);
diff->add_newline();
diff->add_text(TTR("Author:") + " " + commit_author);
@@ -590,13 +590,13 @@ void VersionControlEditorPlugin::_display_diff(int p_idx) {
for (int i = 0; i < diff_content.size(); i++) {
EditorVCSInterface::DiffFile diff_file = diff_content[i];
- diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("doc_bold"), EditorStringName(EditorFonts)));
- diff->push_color(EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), EditorStringName(Editor)));
+ diff->push_font(EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("doc_bold"), EditorStringName(EditorFonts)));
+ diff->push_color(EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("accent_color"), EditorStringName(Editor)));
diff->add_text(TTR("File:") + " " + diff_file.new_file);
diff->pop();
diff->pop();
- diff->push_font(EditorNode::get_singleton()->get_gui_base()->get_theme_font(SNAME("status_source"), EditorStringName(EditorFonts)));
+ diff->push_font(EditorNode::get_singleton()->get_editor_theme()->get_font(SNAME("status_source"), EditorStringName(EditorFonts)));
for (int j = 0; j < diff_file.diff_hunks.size(); j++) {
EditorVCSInterface::DiffHunk hunk = diff_file.diff_hunks[j];
@@ -679,9 +679,9 @@ void VersionControlEditorPlugin::_display_diff_split_view(List<EditorVCSInterfac
EditorVCSInterface::DiffLine diff_line = parsed_diff[i];
bool has_change = diff_line.status != " ";
- static const Color red = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor));
- static const Color green = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), EditorStringName(Editor));
- static const Color white = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label")) * Color(1, 1, 1, 0.6);
+ static const Color red = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor));
+ static const Color green = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("success_color"), EditorStringName(Editor));
+ static const Color white = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("font_color"), SNAME("Label")) * Color(1, 1, 1, 0.6);
if (diff_line.old_line_no >= 0) {
diff->push_cell();
@@ -761,11 +761,11 @@ void VersionControlEditorPlugin::_display_diff_unified_view(List<EditorVCSInterf
Color color;
if (diff_line.status == "+") {
- color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), EditorStringName(Editor));
+ color = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("success_color"), EditorStringName(Editor));
} else if (diff_line.status == "-") {
- color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor));
+ color = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor));
} else {
- color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), SNAME("Label"));
+ color = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("font_color"), SNAME("Label"));
color *= Color(1, 1, 1, 0.6);
}
@@ -856,13 +856,13 @@ void VersionControlEditorPlugin::_popup_remote_remove_confirm(int p_index) {
void VersionControlEditorPlugin::_update_extra_options() {
extra_options_remove_branch_list->clear();
for (int i = 0; i < branch_select->get_item_count(); i++) {
- extra_options_remove_branch_list->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("VcsBranches")), branch_select->get_item_text(branch_select->get_item_id(i)));
+ extra_options_remove_branch_list->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("VcsBranches"), EditorStringName(EditorIcons)), branch_select->get_item_text(branch_select->get_item_id(i)));
}
extra_options_remove_branch_list->update_canvas_items();
extra_options_remove_remote_list->clear();
for (int i = 0; i < remote_select->get_item_count(); i++) {
- extra_options_remove_remote_list->add_icon_item(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("ArrowUp")), remote_select->get_item_text(remote_select->get_item_id(i)));
+ extra_options_remove_remote_list->add_icon_item(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ArrowUp"), EditorStringName(EditorIcons)), remote_select->get_item_text(remote_select->get_item_id(i)));
}
extra_options_remove_remote_list->update_canvas_items();
}
@@ -1161,7 +1161,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
refresh_button = memnew(Button);
refresh_button->set_tooltip_text(TTR("Detect new changes"));
refresh_button->set_flat(true);
- refresh_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Reload")));
+ refresh_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Reload"), EditorStringName(EditorIcons)));
refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_stage_area));
refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_commit_list));
refresh_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_refresh_branch_list));
@@ -1181,14 +1181,14 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
discard_all_button = memnew(Button);
discard_all_button->set_tooltip_text(TTR("Discard all changes"));
- discard_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Close")));
+ discard_all_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Close"), EditorStringName(EditorIcons)));
discard_all_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_confirm_discard_all));
discard_all_button->set_flat(true);
unstage_title->add_child(discard_all_button);
stage_all_button = memnew(Button);
stage_all_button->set_flat(true);
- stage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("MoveDown")));
+ stage_all_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveDown"), EditorStringName(EditorIcons)));
stage_all_button->set_tooltip_text(TTR("Stage all changes"));
unstage_title->add_child(stage_all_button);
@@ -1218,7 +1218,7 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
unstage_all_button = memnew(Button);
unstage_all_button->set_flat(true);
- unstage_all_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("MoveUp")));
+ unstage_all_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveUp"), EditorStringName(EditorIcons)));
unstage_all_button->set_tooltip_text(TTR("Unstage all changes"));
stage_title->add_child(unstage_all_button);
@@ -1413,26 +1413,26 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
fetch_button = memnew(Button);
fetch_button->set_flat(true);
fetch_button->set_tooltip_text(TTR("Fetch"));
- fetch_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Reload")));
+ fetch_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Reload"), EditorStringName(EditorIcons)));
fetch_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_fetch));
menu_bar->add_child(fetch_button);
pull_button = memnew(Button);
pull_button->set_flat(true);
pull_button->set_tooltip_text(TTR("Pull"));
- pull_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("MoveDown")));
+ pull_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveDown"), EditorStringName(EditorIcons)));
pull_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_pull));
menu_bar->add_child(pull_button);
push_button = memnew(Button);
push_button->set_flat(true);
push_button->set_tooltip_text(TTR("Push"));
- push_button->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("MoveUp")));
+ push_button->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("MoveUp"), EditorStringName(EditorIcons)));
push_button->connect(SNAME("pressed"), callable_mp(this, &VersionControlEditorPlugin::_push));
menu_bar->add_child(push_button);
extra_options = memnew(MenuButton);
- extra_options->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("GuiTabMenuHl")));
+ extra_options->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("GuiTabMenuHl"), EditorStringName(EditorIcons)));
extra_options->get_popup()->connect(SNAME("about_to_popup"), callable_mp(this, &VersionControlEditorPlugin::_update_extra_options));
extra_options->get_popup()->connect(SNAME("id_pressed"), callable_mp(this, &VersionControlEditorPlugin::_extra_option_selected));
menu_bar->add_child(extra_options);
@@ -1463,19 +1463,19 @@ VersionControlEditorPlugin::VersionControlEditorPlugin() {
change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = TTR("Typechange");
change_type_to_strings[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = TTR("Unmerged");
- change_type_to_color[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), EditorStringName(Editor));
- change_type_to_color[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
- change_type_to_color[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
- change_type_to_color[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor));
- change_type_to_color[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("font_color"), EditorStringName(Editor));
- change_type_to_color[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("warning_color"), EditorStringName(Editor));
-
- change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusSuccess"));
- change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusWarning"));
- change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusWarning"));
- change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusWarning"));
- change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusError"));
- change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("StatusWarning"));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("success_color"), EditorStringName(Editor));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("font_color"), EditorStringName(Editor));
+ change_type_to_color[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("warning_color"), EditorStringName(Editor));
+
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_NEW] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusSuccess"), EditorStringName(EditorIcons));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_MODIFIED] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusWarning"), EditorStringName(EditorIcons));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_RENAMED] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusWarning"), EditorStringName(EditorIcons));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_TYPECHANGE] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusWarning"), EditorStringName(EditorIcons));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_DELETED] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusError"), EditorStringName(EditorIcons));
+ change_type_to_icon[EditorVCSInterface::CHANGE_TYPE_UNMERGED] = EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("StatusWarning"), EditorStringName(EditorIcons));
version_control_dock = memnew(VBoxContainer);
version_control_dock->set_v_size_flags(Control::SIZE_EXPAND_FILL);
diff --git a/editor/plugins/visual_shader_editor_plugin.cpp b/editor/plugins/visual_shader_editor_plugin.cpp
index 8e1862d88b..b9b47c475b 100644
--- a/editor/plugins/visual_shader_editor_plugin.cpp
+++ b/editor/plugins/visual_shader_editor_plugin.cpp
@@ -419,8 +419,8 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
// Visual shader specific theme for MSDF font.
Ref<Theme> vstheme;
vstheme.instantiate();
- Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", EditorStringName(EditorIcons));
- Ref<Font> label_bold_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_bold_msdf", EditorStringName(EditorIcons));
+ Ref<Font> label_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_msdf", EditorStringName(EditorFonts));
+ Ref<Font> label_bold_font = EditorNode::get_singleton()->get_editor_theme()->get_font("main_bold_msdf", EditorStringName(EditorFonts));
vstheme->set_font("font", "Label", label_font);
vstheme->set_font("font", "GraphNodeTitleLabel", label_bold_font);
vstheme->set_font("font", "LineEdit", label_font);
@@ -796,7 +796,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
name_box->connect("focus_exited", callable_mp(editor, &VisualShaderEditor::_port_name_focus_out).bind(name_box, p_id, i, false), CONNECT_DEFERRED);
Button *remove_btn = memnew(Button);
- remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Remove")));
+ remove_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);
remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_input_port).bind(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
@@ -823,7 +823,7 @@ void VisualShaderGraphPlugin::add_node(VisualShader::Type p_type, int p_id, bool
if (valid_right) {
if (is_group) {
Button *remove_btn = memnew(Button);
- remove_btn->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Remove")));
+ remove_btn->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Remove"), EditorStringName(EditorIcons)));
remove_btn->set_tooltip_text(TTR("Remove") + " " + name_left);
remove_btn->connect("pressed", callable_mp(editor, &VisualShaderEditor::_remove_output_port).bind(p_id, i), CONNECT_DEFERRED);
hb->add_child(remove_btn);
@@ -2152,7 +2152,7 @@ void VisualShaderEditor::_change_input_port_name(const String &p_text, Object *p
}
LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);
- ERR_FAIL_COND(!line_edit);
+ ERR_FAIL_NULL(line_edit);
String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, false);
if (validated_name.is_empty() || prev_name == validated_name) {
@@ -2179,7 +2179,7 @@ void VisualShaderEditor::_change_output_port_name(const String &p_text, Object *
}
LineEdit *line_edit = Object::cast_to<LineEdit>(p_line_edit);
- ERR_FAIL_COND(!line_edit);
+ ERR_FAIL_NULL(line_edit);
String validated_name = visual_shader->validate_port_name(p_text, node.ptr(), p_port_id, true);
if (validated_name.is_empty() || prev_name == validated_name) {
@@ -3036,7 +3036,7 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
if (!is_custom && !add_options[p_idx].type.is_empty()) {
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(add_options[p_idx].type));
- ERR_FAIL_COND(!vsn);
+ ERR_FAIL_NULL(vsn);
if (!p_ops.is_empty()) {
_setup_node(vsn, p_ops);
}
@@ -3074,13 +3074,13 @@ void VisualShaderEditor::_add_node(int p_idx, const Vector<Variant> &p_ops, Stri
base_type = add_options[p_idx].script->get_instance_base_type();
}
VisualShaderNode *vsn = Object::cast_to<VisualShaderNode>(ClassDB::instantiate(base_type));
- ERR_FAIL_COND(!vsn);
+ ERR_FAIL_NULL(vsn);
vsnode = Ref<VisualShaderNode>(vsn);
if (!is_native) {
vsnode->set_script(add_options[p_idx].script);
}
VisualShaderNodeCustom *custom_node = Object::cast_to<VisualShaderNodeCustom>(vsn);
- ERR_FAIL_COND(!custom_node);
+ ERR_FAIL_NULL(custom_node);
custom_node->update_ports();
}
@@ -3846,7 +3846,7 @@ void VisualShaderEditor::_node_selected(Object *p_node) {
VisualShader::Type type = get_current_shader_type();
GraphElement *graph_element = Object::cast_to<GraphElement>(p_node);
- ERR_FAIL_COND(!graph_element);
+ ERR_FAIL_NULL(graph_element);
int id = String(graph_element->get_name()).to_int();
@@ -4709,28 +4709,28 @@ void VisualShaderEditor::_update_varying_tree() {
switch (varying->type) {
case VisualShader::VARYING_TYPE_FLOAT:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("float")));
+ item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)));
break;
case VisualShader::VARYING_TYPE_INT:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("int")));
+ item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)));
break;
case VisualShader::VARYING_TYPE_UINT:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("uint")));
+ item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)));
break;
case VisualShader::VARYING_TYPE_VECTOR_2D:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector2")));
+ item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)));
break;
case VisualShader::VARYING_TYPE_VECTOR_3D:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector3")));
+ item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)));
break;
case VisualShader::VARYING_TYPE_VECTOR_4D:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector4")));
+ item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)));
break;
case VisualShader::VARYING_TYPE_BOOLEAN:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("bool")));
+ item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)));
break;
case VisualShader::VARYING_TYPE_TRANSFORM:
- item->set_icon(0, EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Transform3D")));
+ item->set_icon(0, EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)));
break;
default:
break;
@@ -6195,15 +6195,15 @@ public:
editor = p_editor;
input = p_input;
Ref<Texture2D> type_icon[] = {
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("float")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("int")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("uint")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector2")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector3")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector4")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("bool")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Transform3D")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("ImageTexture")),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ImageTexture"), EditorStringName(EditorIcons)),
};
add_item("[None]");
@@ -6245,14 +6245,14 @@ public:
varying = p_varying;
Ref<Texture2D> type_icon[] = {
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("float")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("int")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("uint")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector2")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector3")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector4")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("bool")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Transform3D")),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),
};
bool is_getter = Ref<VisualShaderNodeVaryingGetter>(p_varying.ptr()).is_valid();
@@ -6325,16 +6325,16 @@ public:
parameter_ref = p_parameter_ref;
Ref<Texture2D> type_icon[] = {
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("float")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("int")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("uint")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("bool")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector2")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector3")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Vector4")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Transform3D")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Color")),
- EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("ImageTexture")),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("float"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("int"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("uint"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("bool"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector2"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector3"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Vector4"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Transform3D"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Color"), EditorStringName(EditorIcons)),
+ EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("ImageTexture"), EditorStringName(EditorIcons)),
};
add_item("[None]");
@@ -6370,7 +6370,7 @@ public:
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
updating = true;
- undo_redo->create_action(TTR("Edit Visual Property:") + " " + p_property, UndoRedo::MERGE_ENDS);
+ undo_redo->create_action(vformat(TTR("Edit Visual Property: %s"), p_property), UndoRedo::MERGE_ENDS);
undo_redo->add_do_property(node.ptr(), p_property, p_value);
undo_redo->add_undo_property(node.ptr(), p_property, node->get(p_property));
diff --git a/editor/plugins/voxel_gi_editor_plugin.cpp b/editor/plugins/voxel_gi_editor_plugin.cpp
index 50c68f7d21..1c6dcc8b86 100644
--- a/editor/plugins/voxel_gi_editor_plugin.cpp
+++ b/editor/plugins/voxel_gi_editor_plugin.cpp
@@ -32,6 +32,7 @@
#include "editor/editor_interface.h"
#include "editor/editor_node.h"
+#include "editor/editor_string_names.h"
#include "editor/gui/editor_file_dialog.h"
void VoxelGIEditorPlugin::_bake() {
@@ -152,12 +153,12 @@ void VoxelGIEditorPlugin::bake_func_begin(int p_steps) {
}
void VoxelGIEditorPlugin::bake_func_step(int p_step, const String &p_description) {
- ERR_FAIL_COND(tmp_progress == nullptr);
+ ERR_FAIL_NULL(tmp_progress);
tmp_progress->step(p_description, p_step, false);
}
void VoxelGIEditorPlugin::bake_func_end() {
- ERR_FAIL_COND(tmp_progress == nullptr);
+ ERR_FAIL_NULL(tmp_progress);
memdelete(tmp_progress);
tmp_progress = nullptr;
}
@@ -185,7 +186,9 @@ VoxelGIEditorPlugin::VoxelGIEditorPlugin() {
bake_hb->hide();
bake = memnew(Button);
bake->set_flat(true);
- bake->set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon(SNAME("Bake")));
+ // TODO: Rework this as a dedicated toolbar control so we can hook into theme changes and update it
+ // when the editor theme updates.
+ bake->set_icon(EditorNode::get_singleton()->get_editor_theme()->get_icon(SNAME("Bake"), EditorStringName(EditorIcons)));
bake->set_text(TTR("Bake VoxelGI"));
bake->connect("pressed", callable_mp(this, &VoxelGIEditorPlugin::_bake));
bake_hb->add_child(bake);
diff --git a/editor/project_manager.cpp b/editor/project_manager.cpp
index feb3d7fa14..e7fe9a353c 100644
--- a/editor/project_manager.cpp
+++ b/editor/project_manager.cpp
@@ -1863,7 +1863,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
CRASH_COND(anchor_index == -1);
_select_project_range(anchor_index, clicked_index);
- } else if (mb->is_ctrl_pressed()) {
+ } else if (mb->is_command_or_control_pressed()) {
_toggle_project(clicked_index);
} else {
@@ -1875,7 +1875,7 @@ void ProjectList::_panel_input(const Ref<InputEvent> &p_ev, Node *p_hb) {
// Do not allow opening a project more than once using a single project manager instance.
// Opening the same project in several editor instances at once can lead to various issues.
- if (!mb->is_ctrl_pressed() && mb->is_double_click() && !project_opening_initiated) {
+ if (!mb->is_command_or_control_pressed() && mb->is_double_click() && !project_opening_initiated) {
emit_signal(SNAME(SIGNAL_PROJECT_ASK_OPEN));
}
}
diff --git a/editor/rename_dialog.cpp b/editor/rename_dialog.cpp
index 9eeea0ac54..a3a16dccd8 100644
--- a/editor/rename_dialog.cpp
+++ b/editor/rename_dialog.cpp
@@ -397,11 +397,11 @@ void RenameDialog::_update_preview(String new_text) {
if (new_name == preview_node->get_name()) {
// New name is identical to the old one. Don't color it as much to avoid distracting the user.
- const Color accent_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("accent_color"), EditorStringName(Editor));
- const Color text_color = EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("default_color"), SNAME("RichTextLabel"));
+ const Color accent_color = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("accent_color"), EditorStringName(Editor));
+ const Color text_color = EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("default_color"), SNAME("RichTextLabel"));
lbl_preview->add_theme_color_override("font_color", accent_color.lerp(text_color, 0.5));
} else {
- lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("success_color"), EditorStringName(Editor)));
+ lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("success_color"), EditorStringName(Editor)));
}
}
@@ -487,7 +487,7 @@ void RenameDialog::_error_handler(void *p_self, const char *p_func, const char *
self->has_errors = true;
self->lbl_preview_title->set_text(TTR("Regular Expression Error:"));
- self->lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_gui_base()->get_theme_color(SNAME("error_color"), EditorStringName(Editor)));
+ self->lbl_preview->add_theme_color_override("font_color", EditorNode::get_singleton()->get_editor_theme()->get_color(SNAME("error_color"), EditorStringName(Editor)));
self->lbl_preview->set_text(vformat(TTR("At character %s"), err_str));
}
diff --git a/editor/scene_tree_dock.cpp b/editor/scene_tree_dock.cpp
index 161598b50f..c91f1599ed 100644
--- a/editor/scene_tree_dock.cpp
+++ b/editor/scene_tree_dock.cpp
@@ -189,7 +189,7 @@ void SceneTreeDock::instantiate_scenes(const Vector<String> &p_files, Node *p_pa
}
void SceneTreeDock::_perform_instantiate_scenes(const Vector<String> &p_files, Node *parent, int p_pos) {
- ERR_FAIL_COND(!parent);
+ ERR_FAIL_NULL(parent);
Vector<Node *> instances;
@@ -493,7 +493,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
// Preserve ownership relations ready for pasting.
List<Node *> owned;
- node->get_owned_by(node->get_owner(), &owned);
+ node->get_owned_by(node->get_owner() ? node->get_owner() : node, &owned);
for (Node *F : owned) {
if (!duplimap.has(F) || F == node) {
@@ -1255,7 +1255,7 @@ void SceneTreeDock::_tool_selected(int p_tool, bool p_confirm_override) {
ERR_FAIL_INDEX(idx, subresources.size());
Object *obj = ObjectDB::get_instance(subresources[idx]);
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
_push_item(obj);
}
@@ -1757,6 +1757,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
continue;
}
+ int tracks_removed = 0;
+
for (int i = 0; i < anim->get_track_count(); i++) {
NodePath track_np = anim->track_get_path(i);
Node *n = root->get_node_or_null(track_np);
@@ -1774,14 +1776,8 @@ void SceneTreeDock::perform_node_renames(Node *p_base, HashMap<Node *, NodePath>
if (found_path->value.is_empty()) {
//will be erased
- int idx = 0;
- HashSet<int>::Iterator EI = ran.begin();
- ERR_FAIL_COND(!EI); //bug
- while (*EI != i) {
- idx++;
- ++EI;
- ERR_FAIL_COND(!EI); //another bug
- }
+ int idx = i - tracks_removed;
+ tracks_removed++;
undo_redo->add_do_method(anim.ptr(), "remove_track", idx);
undo_redo->add_undo_method(anim.ptr(), "add_track", anim->track_get_type(i), idx);
@@ -1885,7 +1881,7 @@ bool SceneTreeDock::_validate_no_instance() {
void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) {
Node *new_parent = scene_root->get_node(p_path);
- ERR_FAIL_COND(!new_parent);
+ ERR_FAIL_NULL(new_parent);
List<Node *> selection = editor_selection->get_selected_node_list();
@@ -1904,7 +1900,7 @@ void SceneTreeDock::_node_reparent(NodePath p_path, bool p_keep_global_xform) {
void SceneTreeDock::_do_reparent(Node *p_new_parent, int p_position_in_parent, Vector<Node *> p_nodes, bool p_keep_global_xform) {
Node *new_parent = p_new_parent;
- ERR_FAIL_COND(!new_parent);
+ ERR_FAIL_NULL(new_parent);
if (p_nodes.size() == 0) {
return; // Nothing to reparent.
@@ -2074,6 +2070,10 @@ void SceneTreeDock::_script_created(Ref<Script> p_script) {
return;
}
+ if (p_script->is_built_in()) {
+ p_script->set_path(edited_scene->get_scene_file_path() + "::");
+ }
+
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
undo_redo->create_action(TTR("Attach Script"), UndoRedo::MERGE_DISABLE, selected.front()->get());
for (Node *E : selected) {
@@ -2297,7 +2297,7 @@ void SceneTreeDock::_selection_changed() {
void SceneTreeDock::_do_create(Node *p_parent) {
Variant c = create_dialog->instantiate_selected();
Node *child = Object::cast_to<Node>(c);
- ERR_FAIL_COND(!child);
+ ERR_FAIL_NULL(child);
String new_name = p_parent->validate_child_name(child);
if (GLOBAL_GET("editor/naming/node_name_casing").operator int() != NAME_CASING_PASCAL_CASE) {
@@ -2365,7 +2365,7 @@ void SceneTreeDock::_create() {
} else {
// If no root exist in edited scene
parent = scene_root;
- ERR_FAIL_COND(!parent);
+ ERR_FAIL_NULL(parent);
}
_do_create(parent);
@@ -2378,13 +2378,13 @@ void SceneTreeDock::_create() {
ur->create_action(TTR("Change type of node(s)"), UndoRedo::MERGE_DISABLE, selection.front()->get());
for (Node *n : selection) {
- ERR_FAIL_COND(!n);
+ ERR_FAIL_NULL(n);
Variant c = create_dialog->instantiate_selected();
ERR_FAIL_COND(!c);
Node *new_node = Object::cast_to<Node>(c);
- ERR_FAIL_COND(!new_node);
+ ERR_FAIL_NULL(new_node);
replace_node(n, new_node);
}
@@ -2397,13 +2397,13 @@ void SceneTreeDock::_create() {
bool only_one_top_node = true;
Node *first = selection.front()->get();
- ERR_FAIL_COND(!first);
+ ERR_FAIL_NULL(first);
int smaller_path_to_top = first->get_path_to(scene_root).get_name_count();
Node *top_node = first;
for (List<Node *>::Element *E = selection.front()->next(); E; E = E->next()) {
Node *n = E->get();
- ERR_FAIL_COND(!n);
+ ERR_FAIL_NULL(n);
int path_length = n->get_path_to(scene_root).get_name_count();
@@ -2759,7 +2759,7 @@ void SceneTreeDock::_normalize_drop(Node *&to_node, int &to_pos, int p_type) {
void SceneTreeDock::_files_dropped(Vector<String> p_files, NodePath p_to, int p_type) {
Node *node = get_node(p_to);
- ERR_FAIL_COND(!node);
+ ERR_FAIL_NULL(node);
if (scene_tree->get_scene_tree()->get_drop_mode_flags() & Tree::DROP_MODE_INBETWEEN) {
// Dropped PackedScene, instance it.
@@ -2818,7 +2818,7 @@ void SceneTreeDock::_script_dropped(String p_file, NodePath p_to) {
}
EditorUndoRedoManager *undo_redo = EditorUndoRedoManager::get_singleton();
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
Object *obj = ClassDB::instantiate(scr->get_instance_base_type());
ERR_FAIL_NULL(obj);
@@ -2977,7 +2977,10 @@ void SceneTreeDock::_tree_rmb(const Vector2 &p_menu_pos) {
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionCopy")), ED_GET_SHORTCUT("scene_tree/copy_node"), TOOL_COPY);
if (selection.size() == 1 && !node_clipboard.is_empty()) {
menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionPaste")), ED_GET_SHORTCUT("scene_tree/paste_node"), TOOL_PASTE);
- menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionPaste")), ED_GET_SHORTCUT("scene_tree/paste_node_as_sibling"), TOOL_PASTE);
+ menu->add_icon_shortcut(get_editor_theme_icon(SNAME("ActionPaste")), ED_GET_SHORTCUT("scene_tree/paste_node_as_sibling"), TOOL_PASTE_AS_SIBLING);
+ if (selection.front()->get() == edited_scene) {
+ menu->set_item_disabled(-1, true);
+ }
}
menu->add_separator();
}
@@ -3227,7 +3230,7 @@ void SceneTreeDock::save_branch_to_file(String p_directory) {
void SceneTreeDock::_focus_node() {
Node *node = scene_tree->get_selected();
- ERR_FAIL_COND(!node);
+ ERR_FAIL_NULL(node);
if (node->is_class("CanvasItem")) {
CanvasItemEditorPlugin *editor = Object::cast_to<CanvasItemEditorPlugin>(editor_data->get_editor_by_name("2D"));
@@ -3376,12 +3379,19 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
}
Node *paste_parent = edited_scene;
+ Node *paste_sibling = nullptr;
+
List<Node *> selection = editor_selection->get_selected_node_list();
if (selection.size() > 0) {
paste_parent = selection.back()->get();
}
if (p_paste_as_sibling) {
+ if (paste_parent == edited_scene) {
+ return pasted_nodes; // Don't paste as sibling of scene root.
+ }
+
+ paste_sibling = paste_parent;
paste_parent = paste_parent->get_parent();
}
@@ -3394,7 +3404,11 @@ List<Node *> SceneTreeDock::paste_nodes(bool p_paste_as_sibling) {
}
EditorUndoRedoManager *ur = EditorUndoRedoManager::get_singleton();
- ur->create_action(vformat(p_paste_as_sibling ? TTR("Paste Node(s) as Sibling of %s") : TTR("Paste Node(s) as Child of %s"), paste_parent->get_name()), UndoRedo::MERGE_DISABLE, EditorNode::get_singleton()->get_edited_scene());
+ if (paste_parent) {
+ ur->create_action(vformat(p_paste_as_sibling ? TTR("Paste Node(s) as Sibling of %s") : TTR("Paste Node(s) as Child of %s"), paste_sibling ? paste_sibling->get_name() : paste_parent->get_name()), UndoRedo::MERGE_DISABLE, edited_scene);
+ } else {
+ ur->create_action(TTR("Paste Node(s) as Root"), UndoRedo::MERGE_DISABLE, edited_scene);
+ }
ur->add_do_method(editor_selection, "clear");
HashMap<Ref<Resource>, Ref<Resource>> resource_remap;
@@ -3740,7 +3754,7 @@ void SceneTreeDock::_edit_subresource(int p_idx, const PopupMenu *p_from_menu) {
const ObjectID &id = p_from_menu->get_item_metadata(p_idx);
Object *obj = ObjectDB::get_instance(id);
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
_push_item(obj);
}
diff --git a/editor/window_wrapper.cpp b/editor/window_wrapper.cpp
index 2570574823..a5c862ffd6 100644
--- a/editor/window_wrapper.cpp
+++ b/editor/window_wrapper.cpp
@@ -59,7 +59,7 @@ class ShortcutBin : public Node {
return;
}
Window *grandparent_window = get_window()->get_parent_visible_window();
- ERR_FAIL_COND(!grandparent_window);
+ ERR_FAIL_NULL(grandparent_window);
if (Object::cast_to<InputEventKey>(p_event.ptr()) || Object::cast_to<InputEventShortcut>(p_event.ptr())) {
// HACK: Propagate the window input to the editor main window to handle global shortcuts.
@@ -385,7 +385,7 @@ void ScreenSelect::_notification(int p_what) {
connect("gui_input", callable_mp(this, &ScreenSelect::_handle_mouse_shortcut));
} break;
case NOTIFICATION_THEME_CHANGED: {
- set_icon(EditorNode::get_singleton()->get_gui_base()->get_editor_theme_icon("MakeFloating"));
+ set_icon(get_editor_theme_icon("MakeFloating"));
popup_background->add_theme_style_override("panel", get_theme_stylebox("PanelForeground", EditorStringName(EditorStyles)));
const real_t popup_height = real_t(get_theme_font_size("font_size")) * 2.0;
diff --git a/main/main.cpp b/main/main.cpp
index 32262b50b3..970c77a34b 100644
--- a/main/main.cpp
+++ b/main/main.cpp
@@ -114,7 +114,10 @@
#ifdef MODULE_GDSCRIPT_ENABLED
#include "modules/gdscript/gdscript.h"
-#endif
+#if defined(TOOLS_ENABLED) && !defined(GDSCRIPT_NO_LSP)
+#include "modules/gdscript/language_server/gdscript_language_server.h"
+#endif // TOOLS_ENABLED && !GDSCRIPT_NO_LSP
+#endif // MODULE_GDSCRIPT_ENABLED
/* Static members */
@@ -289,7 +292,7 @@ void initialize_physics() {
// Physics server not found, Use the default physics
physics_server_3d = PhysicsServer3DManager::get_singleton()->new_default_server();
}
- ERR_FAIL_COND(!physics_server_3d);
+ ERR_FAIL_NULL(physics_server_3d);
physics_server_3d->init();
// 2D Physics server
@@ -299,7 +302,7 @@ void initialize_physics() {
// Physics server not found, Use the default physics
physics_server_2d = PhysicsServer2DManager::get_singleton()->new_default_server();
}
- ERR_FAIL_COND(!physics_server_2d);
+ ERR_FAIL_NULL(physics_server_2d);
physics_server_2d->init();
}
@@ -389,7 +392,10 @@ void Main::print_help(const char *p_binary) {
OS::get_singleton()->print(" -e, --editor Start the editor instead of running the scene.\n");
OS::get_singleton()->print(" -p, --project-manager Start the project manager, even if a project is auto-detected.\n");
OS::get_singleton()->print(" --debug-server <uri> Start the editor debug server (<protocol>://<host/IP>[:<port>], e.g. tcp://127.0.0.1:6007)\n");
-#endif
+#if defined(MODULE_GDSCRIPT_ENABLED) && !defined(GDSCRIPT_NO_LSP)
+ OS::get_singleton()->print(" --lsp-port <port> Use the specified port for the language server protocol. The port must be between 0 to 65535.\n");
+#endif // MODULE_GDSCRIPT_ENABLED && !GDSCRIPT_NO_LSP
+#endif // TOOLS_ENABLED
OS::get_singleton()->print(" --quit Quit after the first iteration.\n");
OS::get_singleton()->print(" --quit-after <int> Quit after the given number of iterations. Set to 0 to disable.\n");
OS::get_singleton()->print(" -l, --language <locale> Use a specific locale (<locale> being a two-letter code).\n");
@@ -1504,7 +1510,21 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
OS::get_singleton()->print("Missing <path> argument for --benchmark-file <path>.\n");
goto error;
}
-
+#if defined(TOOLS_ENABLED) && !defined(GDSCRIPT_NO_LSP)
+ } else if (I->get() == "--lsp-port") {
+ if (I->next()) {
+ int port_override = I->next()->get().to_int();
+ if (port_override < 0 || port_override > 65535) {
+ OS::get_singleton()->print("<port> argument for --lsp-port <port> must be between 0 and 65535.\n");
+ goto error;
+ }
+ GDScriptLanguageServer::port_override = port_override;
+ N = I->next()->next();
+ } else {
+ OS::get_singleton()->print("Missing <port> argument for --lsp-port <port>.\n");
+ goto error;
+ }
+#endif // TOOLS_ENABLED && !GDSCRIPT_NO_LSP
} else if (I->get() == "--" || I->get() == "++") {
adding_user_args = true;
} else {
@@ -1663,7 +1683,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
}
if (bool(GLOBAL_GET("application/run/disable_stderr"))) {
CoreGlobals::print_error_enabled = false;
- };
+ }
if (quiet_stdout) {
CoreGlobals::print_line_enabled = false;
@@ -1688,21 +1708,26 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.android", PROPERTY_HINT_ENUM, driver_hints), default_driver);
GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.ios", PROPERTY_HINT_ENUM, driver_hints), default_driver);
GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/rendering_device/driver.macos", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ }
- driver_hints = "";
+ {
+ String driver_hints = "";
+ String driver_hints_angle = "";
#ifdef GLES3_ENABLED
- driver_hints += "opengl3";
+ driver_hints = "opengl3";
+ driver_hints_angle = "opengl3,opengl3_angle";
#endif
- default_driver = driver_hints.get_slice(",", 0);
+ String default_driver = driver_hints.get_slice(",", 0);
GLOBAL_DEF("rendering/gl_compatibility/driver", default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.windows", PROPERTY_HINT_ENUM, driver_hints_angle), default_driver);
GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.linuxbsd", PROPERTY_HINT_ENUM, driver_hints), default_driver);
GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.web", PROPERTY_HINT_ENUM, driver_hints), default_driver);
GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.android", PROPERTY_HINT_ENUM, driver_hints), default_driver);
GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.ios", PROPERTY_HINT_ENUM, driver_hints), default_driver);
- GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints), default_driver);
+ GLOBAL_DEF(PropertyInfo(Variant::STRING, "rendering/gl_compatibility/driver.macos", PROPERTY_HINT_ENUM, driver_hints_angle), default_driver);
+
GLOBAL_DEF_RST("rendering/gl_compatibility/nvidia_disable_threaded_optimization", true);
}
@@ -1777,7 +1802,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
// Set a default renderer if none selected. Try to choose one that matches the driver.
if (rendering_method.is_empty()) {
- if (rendering_driver == "opengl3") {
+ if (rendering_driver == "opengl3" || rendering_driver == "opengl3_angle") {
rendering_method = "gl_compatibility";
} else {
rendering_method = "forward_plus";
@@ -1795,6 +1820,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
#ifdef GLES3_ENABLED
if (rendering_method == "gl_compatibility") {
available_drivers.push_back("opengl3");
+ available_drivers.push_back("opengl3_angle");
}
#endif
if (available_drivers.is_empty()) {
@@ -2048,6 +2074,7 @@ Error Main::setup(const char *execpath, int argc, char *argv[], bool p_second_ph
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/form_factor", PROPERTY_HINT_ENUM, "Head Mounted,Handheld"), "0");
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/view_configuration", PROPERTY_HINT_ENUM, "Mono,Stereo"), "1"); // "Mono,Stereo,Quad,Observer"
GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/reference_space", PROPERTY_HINT_ENUM, "Local,Stage"), "1");
+ GLOBAL_DEF_BASIC(PropertyInfo(Variant::INT, "xr/openxr/environment_blend_mode", PROPERTY_HINT_ENUM, "Opaque,Additive,Alpha"), "0");
GLOBAL_DEF_BASIC("xr/openxr/submit_depth_buffer", false);
GLOBAL_DEF_BASIC("xr/openxr/startup_alert", true);
@@ -3022,7 +3049,7 @@ bool Main::start() {
return false;
} else {
Object *ml = ClassDB::instantiate(main_loop_type);
- ERR_FAIL_COND_V_MSG(!ml, false, "Can't instance MainLoop type.");
+ ERR_FAIL_NULL_V_MSG(ml, false, "Can't instance MainLoop type.");
main_loop = Object::cast_to<MainLoop>(ml);
if (!main_loop) {
@@ -3302,7 +3329,7 @@ bool Main::start() {
scene = scenedata->instantiate();
}
- ERR_FAIL_COND_V_MSG(!scene, false, "Failed loading scene: " + local_game_path);
+ ERR_FAIL_NULL_V_MSG(scene, false, "Failed loading scene: " + local_game_path + ".");
sml->add_current_scene(scene);
#ifdef MACOS_ENABLED
diff --git a/misc/extension_api_validation/4.1-stable.expected b/misc/extension_api_validation/4.1-stable.expected
index 39eba9642b..19c9a28c09 100644
--- a/misc/extension_api_validation/4.1-stable.expected
+++ b/misc/extension_api_validation/4.1-stable.expected
@@ -176,3 +176,11 @@ Validate extension JSON: API was removed: classes/TileMap/methods/set_quadrant_s
Validate extension JSON: API was removed: classes/TileMap/properties/cell_quadrant_size
cell_quadrant_size/quadrant_size of the TileMap API was renamed to rendering_quadrant_size.
+
+
+GH-81298
+--------
+Validate extension JSON: Error: Field 'classes/PhysicsServer3DRenderingServerHandler/methods/_set_vertex/arguments/1': type changed value in new API, from "const void*" to "Vector3".
+Validate extension JSON: Error: Field 'classes/PhysicsServer3DRenderingServerHandler/methods/_set_normal/arguments/1': type changed value in new API, from "const void*" to "Vector3".
+
+Intentional compatibility breakage to be consistent with the new non-virtual set_vertex/set_normal.
diff --git a/misc/scripts/header_guards.sh b/misc/scripts/header_guards.sh
index 1f8aa6151c..ce0b3f334d 100755
--- a/misc/scripts/header_guards.sh
+++ b/misc/scripts/header_guards.sh
@@ -19,7 +19,7 @@ for file in $files; do
# Skip *.gen.h and *-so_wrap.h, they're generated.
if [[ "$file" == *".gen.h" || "$file" == *"-so_wrap.h" ]]; then continue; fi
# Has important define before normal header guards.
- if [[ "$file" == *"thread.h" || "$file" == *"platform_config.h" ]]; then continue; fi
+ if [[ "$file" == *"thread.h" || "$file" == *"platform_config.h" || "$file" == *"platform_gl.h" ]]; then continue; fi
# Obj-C files don't use header guards.
if grep -q "#import " "$file"; then continue; fi
diff --git a/misc/scripts/mypy.ini b/misc/scripts/mypy.ini
index c1ea695ca5..b3323eacda 100644
--- a/misc/scripts/mypy.ini
+++ b/misc/scripts/mypy.ini
@@ -9,3 +9,4 @@ warn_unreachable = True
namespace_packages = True
explicit_package_bases = True
+exclude = (?x)(^thirdparty)
diff --git a/modules/csg/editor/csg_gizmos.cpp b/modules/csg/editor/csg_gizmos.cpp
index 2c533cb36d..ebf0f5a91f 100644
--- a/modules/csg/editor/csg_gizmos.cpp
+++ b/modules/csg/editor/csg_gizmos.cpp
@@ -35,12 +35,15 @@
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
#include "editor/editor_undo_redo_manager.h"
+#include "editor/plugins/gizmos/gizmo_3d_helper.h"
#include "editor/plugins/node_3d_editor_plugin.h"
#include "scene/3d/camera_3d.h"
///////////
CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() {
+ helper.instantiate();
+
Color gizmo_color = EDITOR_DEF("editors/3d_gizmos/gizmo_colors/csg", Color(0.0, 0.4, 1, 0.15));
create_material("shape_union_material", gizmo_color);
create_material("shape_union_solid_material", gizmo_color);
@@ -56,6 +59,9 @@ CSGShape3DGizmoPlugin::CSGShape3DGizmoPlugin() {
create_handle_material("handles");
}
+CSGShape3DGizmoPlugin::~CSGShape3DGizmoPlugin() {
+}
+
String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d());
@@ -64,7 +70,7 @@ String CSGShape3DGizmoPlugin::get_handle_name(const EditorNode3DGizmo *p_gizmo,
}
if (Object::cast_to<CSGBox3D>(cs)) {
- return "Size";
+ return helper->box_get_handle_name(p_id);
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
@@ -104,17 +110,15 @@ Variant CSGShape3DGizmoPlugin::get_handle_value(const EditorNode3DGizmo *p_gizmo
return Variant();
}
+void CSGShape3DGizmoPlugin::begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) {
+ helper->initialize_handle_action(get_handle_value(p_gizmo, p_id, p_secondary), p_gizmo->get_node_3d()->get_global_transform());
+}
+
void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) {
CSGShape3D *cs = Object::cast_to<CSGShape3D>(p_gizmo->get_node_3d());
- Transform3D gt = cs->get_global_transform();
- //gt.orthonormalize();
- Transform3D gi = gt.affine_inverse();
-
- Vector3 ray_from = p_camera->project_ray_origin(p_point);
- Vector3 ray_dir = p_camera->project_ray_normal(p_point);
-
- Vector3 sg[2] = { gi.xform(ray_from), gi.xform(ray_from + ray_dir * 16384) };
+ Vector3 sg[2];
+ helper->get_segment(p_camera, p_point, sg);
if (Object::cast_to<CSGSphere3D>(cs)) {
CSGSphere3D *s = Object::cast_to<CSGSphere3D>(cs);
@@ -135,29 +139,11 @@ void CSGShape3DGizmoPlugin::set_handle(const EditorNode3DGizmo *p_gizmo, int p_i
if (Object::cast_to<CSGBox3D>(cs)) {
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
-
- Vector3 axis;
- axis[p_id] = 1.0;
- Vector3 ra, rb;
- Geometry3D::get_closest_points_between_segments(Vector3(), axis * 4096, sg[0], sg[1], ra, rb);
- float d = ra[p_id];
-
- if (Math::is_nan(d)) {
- // The handle is perpendicular to the camera.
- return;
- }
-
- if (Node3DEditor::get_singleton()->is_snap_enabled()) {
- d = Math::snapped(d, Node3DEditor::get_singleton()->get_translate_snap());
- }
-
- if (d < 0.001) {
- d = 0.001;
- }
-
- Vector3 h = s->get_size();
- h[p_id] = d * 2;
- s->set_size(h);
+ Vector3 size = s->get_size();
+ Vector3 position;
+ helper->box_set_handle(sg, p_id, size, position);
+ s->set_size(size);
+ s->set_global_position(position);
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
@@ -225,17 +211,7 @@ void CSGShape3DGizmoPlugin::commit_handle(const EditorNode3DGizmo *p_gizmo, int
}
if (Object::cast_to<CSGBox3D>(cs)) {
- CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
- if (p_cancel) {
- s->set_size(p_restore);
- return;
- }
-
- 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);
- ur->commit_action();
+ helper->box_commit_handle(TTR("Change Box Shape Size"), p_cancel, cs);
}
if (Object::cast_to<CSGCylinder3D>(cs)) {
@@ -394,15 +370,7 @@ void CSGShape3DGizmoPlugin::redraw(EditorNode3DGizmo *p_gizmo) {
if (Object::cast_to<CSGBox3D>(cs)) {
CSGBox3D *s = Object::cast_to<CSGBox3D>(cs);
-
- Vector<Vector3> handles;
-
- for (int i = 0; i < 3; i++) {
- Vector3 h;
- h[i] = s->get_size()[i] / 2;
- handles.push_back(h);
- }
-
+ Vector<Vector3> handles = helper->box_get_handles(s->get_size());
p_gizmo->add_handles(handles, handles_material);
}
diff --git a/modules/csg/editor/csg_gizmos.h b/modules/csg/editor/csg_gizmos.h
index deac1d428d..6281db0a21 100644
--- a/modules/csg/editor/csg_gizmos.h
+++ b/modules/csg/editor/csg_gizmos.h
@@ -38,9 +38,13 @@
#include "editor/editor_plugin.h"
#include "editor/plugins/node_3d_editor_gizmos.h"
+class Gizmo3DHelper;
+
class CSGShape3DGizmoPlugin : public EditorNode3DGizmoPlugin {
GDCLASS(CSGShape3DGizmoPlugin, EditorNode3DGizmoPlugin);
+ Ref<Gizmo3DHelper> helper;
+
public:
virtual bool has_gizmo(Node3D *p_spatial) override;
virtual String get_gizmo_name() const override;
@@ -50,10 +54,12 @@ public:
virtual String get_handle_name(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
virtual Variant get_handle_value(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) const override;
+ void begin_handle_action(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary) override;
virtual void set_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, Camera3D *p_camera, const Point2 &p_point) override;
virtual void commit_handle(const EditorNode3DGizmo *p_gizmo, int p_id, bool p_secondary, const Variant &p_restore, bool p_cancel) override;
CSGShape3DGizmoPlugin();
+ ~CSGShape3DGizmoPlugin();
};
class EditorPluginCSG : public EditorPlugin {
diff --git a/modules/csg/icons/CSGTorus3D.svg b/modules/csg/icons/CSGTorus3D.svg
index 5672244e5c..27a6b422f9 100644
--- a/modules/csg/icons/CSGTorus3D.svg
+++ b/modules/csg/icons/CSGTorus3D.svg
@@ -1 +1 @@
-<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><ellipse cx="8" cy="7.5" fill="none" rx="6" ry="3.5" stroke="#fc7f7f" stroke-width="2" mask="url(#a)"/></svg>
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><mask id="a"><path d="M0 0h16v10a2 2 0 0 0-2-2h-2a2 2 0 0 0-2 2 2 2 0 0 0-2 2v2a2 2 0 0 0 2 2H0z" fill="#fff"/></mask><path d="M12 9a1 1 0 0 0-1 1v1h2v2h1a1 1 0 0 0 1-1v-2a1 1 0 0 0-1-1zm1 4h-2v-2h-1a1 1 0 0 0-1 1v2a1 1 0 0 0 1 1h2a1 1 0 0 0 1-1z" fill="#5fb2ff"/><g fill="none" stroke="#fc7f7f" mask="url(#a)"><path d="M2.5 10a6 4 0 0 0 11 0 4 4 0 0 0 0-4 6 4 0 0 0-11 0 4 4 0 0 0 0 4z" stroke-width="2"/><path d="M6.2 7.2a2 1 0 1 0 3.6 0" stroke-width="1.75" stroke-linecap="round"/></g></svg>
diff --git a/modules/gdscript/.editorconfig b/modules/gdscript/.editorconfig
new file mode 100644
index 0000000000..640c205093
--- /dev/null
+++ b/modules/gdscript/.editorconfig
@@ -0,0 +1,8 @@
+[*.gd]
+indent_style = tab
+indent_size = 4
+insert_final_newline = true
+trim_trailing_whitespace = true
+
+[*.out]
+insert_final_newline = true
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 4f1a256ec9..18045e323c 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -57,11 +57,12 @@
[/codeblock]
</description>
</method>
- <method name="convert">
+ <method name="convert" is_deprecated="true">
<return type="Variant" />
<param index="0" name="what" type="Variant" />
<param index="1" name="type" type="int" />
<description>
+ [i]Deprecated.[/i] Use [method @GlobalScope.type_convert] instead.
Converts [param what] to [param type] in the best way possible. The [param type] uses the [enum Variant.Type] values.
[codeblock]
var a = [4, 2.5, 1.2]
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp
index 1aecfc6de1..0b440274c0 100644
--- a/modules/gdscript/editor/gdscript_docgen.cpp
+++ b/modules/gdscript/editor/gdscript_docgen.cpp
@@ -87,7 +87,7 @@ static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String
case GDType::SCRIPT:
if (p_gdtype.script_type.is_valid()) {
if (p_gdtype.script_type->get_global_name() != StringName()) {
- r_type = _get_script_path(p_gdtype.script_type->get_global_name());
+ r_type = p_gdtype.script_type->get_global_name();
return;
}
if (!p_gdtype.script_type->get_path().is_empty()) {
@@ -129,10 +129,10 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
DocData::ClassDoc &doc = p_script->doc;
doc.script_path = _get_script_path(p_script->get_script_path());
- if (p_script->name.is_empty()) {
+ if (p_script->local_name == StringName()) {
doc.name = doc.script_path;
} else {
- doc.name = p_script->name;
+ doc.name = p_script->local_name;
}
if (p_script->_owner) {
@@ -204,6 +204,9 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c
if (m_func->return_type) {
_doctype_from_gdtype(m_func->return_type->get_datatype(), method_doc.return_type, method_doc.return_enum, true);
+ } else if (!m_func->body->has_return) {
+ // If no `return` statement, then return type is `void`, not `Variant`.
+ method_doc.return_type = "void";
} else {
method_doc.return_type = "Variant";
}
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index e488d6e266..1be690d894 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -52,6 +52,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
bool in_keyword = false;
bool in_word = false;
bool in_number = false;
+ bool in_raw_string = false;
bool in_node_path = false;
bool in_node_ref = false;
bool in_annotation = false;
@@ -234,15 +235,33 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
if (str[from] == '\\') {
- Dictionary escape_char_highlighter_info;
- escape_char_highlighter_info["color"] = symbol_color;
- color_map[from] = escape_char_highlighter_info;
+ if (!in_raw_string) {
+ Dictionary escape_char_highlighter_info;
+ escape_char_highlighter_info["color"] = symbol_color;
+ color_map[from] = escape_char_highlighter_info;
+ }
from++;
- Dictionary region_continue_highlighter_info;
- region_continue_highlighter_info["color"] = region_color;
- color_map[from + 1] = region_continue_highlighter_info;
+ if (!in_raw_string) {
+ int esc_len = 0;
+ if (str[from] == 'u') {
+ esc_len = 4;
+ } else if (str[from] == 'U') {
+ esc_len = 6;
+ }
+ for (int k = 0; k < esc_len && from < line_length - 1; k++) {
+ if (!is_hex_digit(str[from + 1])) {
+ break;
+ }
+ from++;
+ }
+
+ Dictionary region_continue_highlighter_info;
+ region_continue_highlighter_info["color"] = region_color;
+ color_map[from + 1] = region_continue_highlighter_info;
+ }
+
continue;
}
@@ -489,6 +508,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_member_variable = false;
}
+ if (!in_raw_string && in_region == -1 && str[j] == 'r' && j < line_length - 1 && (str[j + 1] == '"' || str[j + 1] == '\'')) {
+ in_raw_string = true;
+ } else if (in_raw_string && in_region == -1) {
+ in_raw_string = false;
+ }
+
// Keep symbol color for binary '&&'. In the case of '&&&' use StringName color for the last ampersand.
if (!in_string_name && in_region == -1 && str[j] == '&' && !is_binary_op) {
if (j >= 2 && str[j - 1] == '&' && str[j - 2] != '&' && prev_is_binary_op) {
@@ -520,7 +545,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
in_annotation = false;
}
- if (in_node_ref) {
+ if (in_raw_string) {
+ color = string_color;
+ } else if (in_node_ref) {
next_type = NODE_REF;
color = node_ref_color;
} else if (in_annotation) {
@@ -692,7 +719,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
}
/* Strings */
- const Color string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
+ string_color = EDITOR_GET("text_editor/theme/highlighting/string_color");
List<String> strings;
gdscript->get_string_delimiters(&strings);
for (const String &string : strings) {
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index fe3b63d713..090857f397 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -78,6 +78,7 @@ private:
Color built_in_type_color;
Color number_color;
Color member_color;
+ Color string_color;
Color node_path_color;
Color node_ref_color;
Color annotation_color;
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index 064143f400..becc2876f9 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -225,10 +225,15 @@ void GDScriptEditorTranslationParserPlugin::_assess_assignment(const GDScriptPar
if (p_assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) {
assignee_name = static_cast<const GDScriptParser::IdentifierNode *>(p_assignment->assignee)->name;
} else if (p_assignment->assignee->type == GDScriptParser::Node::SUBSCRIPT) {
- assignee_name = static_cast<const GDScriptParser::SubscriptNode *>(p_assignment->assignee)->attribute->name;
+ const GDScriptParser::SubscriptNode *subscript = static_cast<const GDScriptParser::SubscriptNode *>(p_assignment->assignee);
+ if (subscript->is_attribute && subscript->attribute) {
+ assignee_name = subscript->attribute->name;
+ } else if (subscript->index && _is_constant_string(subscript->index)) {
+ assignee_name = subscript->index->reduced_value;
+ }
}
- if (assignment_patterns.has(assignee_name) && _is_constant_string(p_assignment->assigned_value)) {
+ if (assignee_name != StringName() && assignment_patterns.has(assignee_name) && _is_constant_string(p_assignment->assigned_value)) {
// If the assignment is towards one of the extract patterns (text, tooltip_text etc.), and the value is a constant string, we collect the string.
ids->push_back(p_assignment->assigned_value->reduced_value);
} else if (assignee_name == fd_filters && p_assignment->assigned_value->type == GDScriptParser::Node::CALL) {
@@ -236,7 +241,7 @@ void GDScriptEditorTranslationParserPlugin::_assess_assignment(const GDScriptPar
// get_node("FileDialog").filters = PackedStringArray(["*.png ; PNG Images","*.gd ; GDScript Files"]).
const GDScriptParser::CallNode *call_node = static_cast<const GDScriptParser::CallNode *>(p_assignment->assigned_value);
- if (call_node->arguments[0]->type == GDScriptParser::Node::ARRAY) {
+ if (!call_node->arguments.is_empty() && call_node->arguments[0]->type == GDScriptParser::Node::ARRAY) {
const GDScriptParser::ArrayNode *array_node = static_cast<const GDScriptParser::ArrayNode *>(call_node->arguments[0]);
// Extract the name in "extension ; name" of PackedStringArray.
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index ccbcb3ee96..62d2c14c17 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -254,7 +254,7 @@ Ref<Script> GDScript::get_base_script() const {
}
StringName GDScript::get_global_name() const {
- return name;
+ return global_name;
}
StringName GDScript::get_instance_base_type() const {
@@ -284,27 +284,9 @@ void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_
const GDScript *current = this;
while (current) {
for (const KeyValue<StringName, GDScriptFunction *> &E : current->member_functions) {
- GDScriptFunction *func = E.value;
- MethodInfo mi;
- mi.name = E.key;
-
- if (func->is_static()) {
- mi.flags |= METHOD_FLAG_STATIC;
- }
-
- for (int i = 0; i < func->get_argument_count(); i++) {
- PropertyInfo arginfo = func->get_argument_type(i);
-#ifdef TOOLS_ENABLED
- arginfo.name = func->get_argument_name(i);
-#endif
- mi.arguments.push_back(arginfo);
- }
-#ifdef TOOLS_ENABLED
- mi.default_arguments.append_array(func->get_default_arg_values());
-#endif
- mi.return_val = func->get_return_type();
- r_list->push_back(mi);
+ r_list->push_back(E.value->get_method_info());
}
+
if (!p_include_base) {
return;
}
@@ -323,10 +305,9 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl
while (sptr) {
Vector<_GDScriptMemberSort> msort;
- for (const KeyValue<StringName, PropertyInfo> &E : sptr->member_info) {
+ for (const KeyValue<StringName, MemberInfo> &E : sptr->member_indices) {
_GDScriptMemberSort ms;
- ERR_CONTINUE(!sptr->member_indices.has(E.key));
- ms.index = sptr->member_indices[E.key].index;
+ ms.index = E.value.index;
ms.name = E.key;
msort.push_back(ms);
}
@@ -334,7 +315,7 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl
msort.sort();
msort.reverse();
for (int i = 0; i < msort.size(); i++) {
- props.push_front(sptr->member_info[msort[i].name]);
+ props.push_front(sptr->member_indices[msort[i].name].property_info);
}
#ifdef TOOLS_ENABLED
@@ -368,15 +349,7 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const {
return MethodInfo();
}
- GDScriptFunction *func = E->value;
- MethodInfo mi;
- mi.name = E->key;
- for (int i = 0; i < func->get_argument_count(); i++) {
- mi.arguments.push_back(func->get_argument_type(i));
- }
-
- mi.return_val = func->get_return_type();
- return mi;
+ return E->value->get_method_info();
}
bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const {
@@ -557,13 +530,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
member_default_values_cache[member.variable->identifier->name] = default_value;
} break;
case GDScriptParser::ClassNode::Member::SIGNAL: {
- // TODO: Cache this in parser to avoid loops like this.
- Vector<StringName> parameters_names;
- parameters_names.resize(member.signal->parameters.size());
- for (int j = 0; j < member.signal->parameters.size(); j++) {
- parameters_names.write[j] = member.signal->parameters[j]->identifier->name;
- }
- _signals[member.signal->identifier->name] = parameters_names;
+ _signals[member.signal->identifier->name] = member.signal->method_info;
} break;
case GDScriptParser::ClassNode::Member::GROUP: {
members_cache.push_back(member.annotation->export_info);
@@ -977,22 +944,26 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
- List<PropertyInfo> property_list;
-
+ List<const GDScript *> classes;
const GDScript *top = this;
while (top) {
- for (const KeyValue<StringName, MemberInfo> &E : top->static_variables_indices) {
- PropertyInfo pi = PropertyInfo(E.value.data_type);
- pi.name = E.key;
- pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; // For the script (as a class) it is a non-static property.
- property_list.push_back(pi);
- }
-
+ classes.push_back(top);
top = top->_base;
}
- for (const List<PropertyInfo>::Element *E = property_list.back(); E; E = E->prev()) {
- p_properties->push_back(E->get());
+ for (const List<const GDScript *>::Element *E = classes.back(); E; E = E->prev()) {
+ Vector<_GDScriptMemberSort> msort;
+ for (const KeyValue<StringName, MemberInfo> &F : E->get()->static_variables_indices) {
+ _GDScriptMemberSort ms;
+ ms.index = F.value.index;
+ ms.name = F.key;
+ msort.push_back(ms);
+ }
+ msort.sort();
+
+ for (int i = 0; i < msort.size(); i++) {
+ p_properties->push_back(E->get()->static_variables_indices[msort[i].name].property_info);
+ }
}
}
@@ -1110,7 +1081,7 @@ GDScript *GDScript::find_class(const String &p_qualified_name) {
Vector<String> class_names;
GDScript *result = nullptr;
// Empty initial name means start here.
- if (first.is_empty() || first == name) {
+ if (first.is_empty() || first == global_name) {
class_names = p_qualified_name.split("::");
result = this;
} else if (p_qualified_name.begins_with(get_root_script()->path)) {
@@ -1245,15 +1216,8 @@ bool GDScript::has_script_signal(const StringName &p_signal) const {
}
void GDScript::_get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const {
- for (const KeyValue<StringName, Vector<StringName>> &E : _signals) {
- MethodInfo mi;
- mi.name = E.key;
- for (int i = 0; i < E.value.size(); i++) {
- PropertyInfo arg;
- arg.name = E.value[i];
- mi.arguments.push_back(arg);
- }
- r_list->push_back(mi);
+ for (const KeyValue<StringName, MethodInfo> &E : _signals) {
+ r_list->push_back(E.value);
}
if (!p_include_base) {
@@ -1274,21 +1238,6 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const {
_get_script_signal_list(r_signals, true);
}
-String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript) {
- ERR_FAIL_NULL_V(p_gdscript, String());
-
- String class_name;
- while (p_gdscript) {
- if (class_name.is_empty()) {
- class_name = p_gdscript->get_script_class_name();
- } else {
- class_name = p_gdscript->get_script_class_name() + "." + class_name;
- }
- p_gdscript = p_gdscript->_owner;
- }
- return class_name;
-}
-
GDScript *GDScript::_get_gdscript_from_variant(const Variant &p_variant) {
Object *obj = p_variant;
if (obj == nullptr || obj->get_instance_id().is_null()) {
@@ -1399,29 +1348,13 @@ void GDScript::_save_orphaned_subclasses(ClearData *p_clear_data) {
}
}
-void GDScript::_init_rpc_methods_properties() {
- // Copy the base rpc methods so we don't mask their IDs.
- rpc_config.clear();
- if (base.is_valid()) {
- rpc_config = base->rpc_config.duplicate();
- }
-
- // RPC Methods
- for (KeyValue<StringName, GDScriptFunction *> &E : member_functions) {
- Variant config = E.value->get_rpc_config();
- if (config.get_type() != Variant::NIL) {
- rpc_config[E.value->get_name()] = config;
- }
- }
-}
-
#ifdef DEBUG_ENABLED
String GDScript::debug_get_script_name(const Ref<Script> &p_script) {
if (p_script.is_valid()) {
Ref<GDScript> gdscript = p_script;
if (gdscript.is_valid()) {
- if (!gdscript->get_script_class_name().is_empty()) {
- return gdscript->get_script_class_name();
+ if (gdscript->get_local_name() != StringName()) {
+ return gdscript->get_local_name();
}
return gdscript->get_fully_qualified_name().get_file();
}
@@ -1667,7 +1600,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
}
{
- HashMap<StringName, Vector<StringName>>::ConstIterator E = sptr->_signals.find(p_name);
+ HashMap<StringName, MethodInfo>::ConstIterator E = sptr->_signals.find(p_name);
if (E) {
r_ret = Signal(this->owner, E->key);
return true;
@@ -1717,11 +1650,11 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const {
Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const {
const GDScript *sptr = script.ptr();
while (sptr) {
- if (sptr->member_info.has(p_name)) {
+ if (sptr->member_indices.has(p_name)) {
if (r_is_valid) {
*r_is_valid = true;
}
- return sptr->member_info[p_name].type;
+ return sptr->member_indices[p_name].property_info.type;
}
sptr = sptr->_base;
}
@@ -1798,10 +1731,9 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
//instance a fake script for editing the values
Vector<_GDScriptMemberSort> msort;
- for (const KeyValue<StringName, PropertyInfo> &F : sptr->member_info) {
+ for (const KeyValue<StringName, GDScript::MemberInfo> &F : sptr->member_indices) {
_GDScriptMemberSort ms;
- ERR_CONTINUE(!sptr->member_indices.has(F.key));
- ms.index = sptr->member_indices[F.key].index;
+ ms.index = F.value.index;
ms.name = F.key;
msort.push_back(ms);
}
@@ -1809,7 +1741,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
msort.sort();
msort.reverse();
for (int i = 0; i < msort.size(); i++) {
- props.push_front(sptr->member_info[msort[i].name]);
+ props.push_front(sptr->member_indices[msort[i].name].property_info);
}
#ifdef TOOLS_ENABLED
@@ -1872,12 +1804,7 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const {
const GDScript *sptr = script.ptr();
while (sptr) {
for (const KeyValue<StringName, GDScriptFunction *> &E : sptr->member_functions) {
- MethodInfo mi;
- mi.name = E.key;
- for (int i = 0; i < E.value->get_argument_count(); i++) {
- mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i)));
- }
- p_list->push_back(mi);
+ p_list->push_back(E.value->get_method_info());
}
sptr = sptr->_base;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 0ba007683c..2fd2ec236a 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -69,6 +69,7 @@ class GDScript : public Script {
StringName setter;
StringName getter;
GDScriptDataType data_type;
+ PropertyInfo property_info;
};
struct ClearData {
@@ -100,7 +101,7 @@ class GDScript : public Script {
HashMap<StringName, GDScriptFunction *> member_functions;
HashMap<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script.
HashMap<StringName, Ref<GDScript>> subclasses;
- HashMap<StringName, Vector<StringName>> _signals;
+ HashMap<StringName, MethodInfo> _signals;
Dictionary rpc_config;
#ifdef TOOLS_ENABLED
@@ -126,8 +127,6 @@ class GDScript : public Script {
void _add_doc(const DocData::ClassDoc &p_inner_class);
#endif
- HashMap<StringName, PropertyInfo> member_info;
-
GDScriptFunction *implicit_initializer = nullptr;
GDScriptFunction *initializer = nullptr; //direct pointer to new , faster to locate
GDScriptFunction *implicit_ready = nullptr;
@@ -142,7 +141,8 @@ class GDScript : public Script {
//exported members
String source;
String path;
- String name;
+ StringName local_name; // Inner class identifier or `class_name`.
+ StringName global_name; // `class_name`.
String fully_qualified_name;
String simplified_icon_path;
SelfList<GDScript> script_list;
@@ -168,15 +168,11 @@ class GDScript : public Script {
bool _update_exports(bool *r_err = nullptr, bool p_recursive_call = false, PlaceHolderScriptInstance *p_instance_to_update = nullptr);
void _save_orphaned_subclasses(GDScript::ClearData *p_clear_data);
- void _init_rpc_methods_properties();
void _get_script_property_list(List<PropertyInfo> *r_list, bool p_include_base) const;
void _get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const;
void _get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const;
- // This method will map the class name from "RefCounted" to "MyClass.InnerClass".
- static String _get_gdscript_reference_class_name(const GDScript *p_gdscript);
-
GDScript *_get_gdscript_from_variant(const Variant &p_variant);
void _get_dependencies(RBSet<GDScript *> &p_dependencies, const GDScript *p_except);
@@ -194,6 +190,8 @@ public:
static String debug_get_script_name(const Ref<Script> &p_script);
#endif
+ _FORCE_INLINE_ StringName get_local_name() const { return local_name; }
+
void clear(GDScript::ClearData *p_clear_data = nullptr);
virtual bool is_valid() const override { return valid; }
@@ -214,7 +212,6 @@ public:
}
const HashMap<StringName, GDScriptFunction *> &get_member_functions() const { return member_functions; }
const Ref<GDScriptNativeClass> &get_native() const { return native; }
- const String &get_script_class_name() const { return name; }
RBSet<GDScript *> get_dependencies();
RBSet<GDScript *> get_inverted_dependencies();
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 18c69467dc..04c86d60a8 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -1000,10 +1000,16 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class,
GDScriptParser::ParameterNode *param = member.signal->parameters[j];
GDScriptParser::DataType param_type = type_from_metatype(resolve_datatype(param->datatype_specifier));
param->set_datatype(param_type);
- mi.arguments.push_back(PropertyInfo(param_type.builtin_type, param->identifier->name));
- // TODO: add signal parameter default values
+#ifdef DEBUG_ENABLED
+ if (param->datatype_specifier == nullptr) {
+ parser->push_warning(param, GDScriptWarning::UNTYPED_DECLARATION, "Parameter", param->identifier->name);
+ }
+#endif
+ mi.arguments.push_back(param_type.to_property_info(param->identifier->name));
+ // Signals do not support parameter default values.
}
member.signal->set_datatype(make_signal_type(mi));
+ member.signal->method_info = mi;
// Apply annotations.
for (GDScriptParser::AnnotationNode *&E : member.signal->annotations) {
@@ -1278,17 +1284,15 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class, co
} else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) {
if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) {
if (member.variable->getter != nullptr) {
- member.variable->getter->set_datatype(member.variable->datatype);
+ member.variable->getter->return_type = member.variable->datatype_specifier;
+ member.variable->getter->set_datatype(member.get_datatype());
resolve_function_body(member.variable->getter);
}
if (member.variable->setter != nullptr) {
- resolve_function_signature(member.variable->setter);
-
- if (member.variable->setter->parameters.size() > 0) {
- member.variable->setter->parameters[0]->datatype_specifier = member.variable->datatype_specifier;
- member.variable->setter->parameters[0]->set_datatype(member.get_datatype());
- }
+ ERR_CONTINUE(member.variable->setter->parameters.is_empty());
+ member.variable->setter->parameters[0]->datatype_specifier = member.variable->datatype_specifier;
+ member.variable->setter->parameters[0]->set_datatype(member.get_datatype());
resolve_function_body(member.variable->setter);
}
@@ -1592,21 +1596,26 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
int default_value_count = 0;
#endif // TOOLS_ENABLED
+#ifdef DEBUG_ENABLED
+ String function_visible_name = function_name;
+ if (function_name == StringName()) {
+ function_visible_name = p_is_lambda ? "<anonymous lambda>" : "<unknown function>";
+ }
+#endif
+
for (int i = 0; i < p_function->parameters.size(); i++) {
resolve_parameter(p_function->parameters[i]);
#ifdef DEBUG_ENABLED
if (p_function->parameters[i]->usages == 0 && !String(p_function->parameters[i]->identifier->name).begins_with("_")) {
- String visible_name = function_name;
- if (function_name == StringName()) {
- visible_name = p_is_lambda ? "<anonymous lambda>" : "<unknown function>";
- }
- parser->push_warning(p_function->parameters[i]->identifier, GDScriptWarning::UNUSED_PARAMETER, visible_name, p_function->parameters[i]->identifier->name);
+ parser->push_warning(p_function->parameters[i]->identifier, GDScriptWarning::UNUSED_PARAMETER, function_visible_name, p_function->parameters[i]->identifier->name);
}
is_shadowing(p_function->parameters[i]->identifier, "function parameter", true);
#endif // DEBUG_ENABLED
-#ifdef TOOLS_ENABLED
+
if (p_function->parameters[i]->initializer) {
+#ifdef TOOLS_ENABLED
default_value_count++;
+#endif // TOOLS_ENABLED
if (p_function->parameters[i]->initializer->is_constant) {
p_function->default_arg_values.push_back(p_function->parameters[i]->initializer->reduced_value);
@@ -1614,7 +1623,6 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
p_function->default_arg_values.push_back(Variant()); // Prevent shift.
}
}
-#endif // TOOLS_ENABLED
}
if (!p_is_lambda && function_name == GDScriptLanguage::get_singleton()->strings._init) {
@@ -1714,6 +1722,12 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode *
#endif // TOOLS_ENABLED
}
+#ifdef DEBUG_ENABLED
+ if (p_function->return_type == nullptr) {
+ parser->push_warning(p_function, GDScriptWarning::UNTYPED_DECLARATION, "Function", function_visible_name);
+ }
+#endif
+
if (p_function->get_datatype().is_resolving()) {
p_function->set_datatype(prev_datatype);
}
@@ -1917,6 +1931,13 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi
}
}
+#ifdef DEBUG_ENABLED
+ if (!has_specified_type && !p_assignable->infer_datatype && !is_constant) {
+ const bool is_parameter = p_assignable->type == GDScriptParser::Node::PARAMETER;
+ parser->push_warning(p_assignable, GDScriptWarning::UNTYPED_DECLARATION, is_parameter ? "Parameter" : "Variable", p_assignable->identifier->name);
+ }
+#endif
+
type.is_constant = is_constant;
type.is_read_only = false;
p_assignable->set_datatype(type);
@@ -2121,19 +2142,16 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) {
}
} else if (!is_type_compatible(specified_type, variable_type)) {
p_for->use_conversion_assign = true;
-#ifdef DEBUG_ENABLED
- } else {
- parser->push_warning(p_for->datatype_specifier, GDScriptWarning::REDUNDANT_FOR_VARIABLE_TYPE, p_for->variable->name, variable_type.to_string(), specified_type.to_string());
-#endif
}
-#ifdef DEBUG_ENABLED
- } else {
- parser->push_warning(p_for->datatype_specifier, GDScriptWarning::REDUNDANT_FOR_VARIABLE_TYPE, p_for->variable->name, variable_type.to_string(), specified_type.to_string());
-#endif
}
p_for->variable->set_datatype(specified_type);
} else {
p_for->variable->set_datatype(variable_type);
+#ifdef DEBUG_ENABLED
+ if (!variable_type.is_hard_type()) {
+ parser->push_warning(p_for->variable, GDScriptWarning::UNTYPED_DECLARATION, R"("for" iterator variable)", p_for->variable->name);
+ }
+#endif
}
}
@@ -2591,7 +2609,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
}
// Check if assigned value is an array literal, so we can make it a typed array too if appropriate.
- if (p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY && assignee_type.has_container_element_type()) {
+ if (p_assignment->assigned_value->type == GDScriptParser::Node::ARRAY && assignee_type.is_hard_type() && assignee_type.has_container_element_type()) {
update_array_literal_element_type(static_cast<GDScriptParser::ArrayNode *>(p_assignment->assigned_value), assignee_type.get_container_element_type());
}
@@ -3186,10 +3204,16 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
bool is_constructor = (base_type.is_meta_type || (p_call->callee && p_call->callee->type == GDScriptParser::Node::IDENTIFIER)) && p_call->function_name == SNAME("new");
if (get_function_signature(p_call, is_constructor, base_type, p_call->function_name, return_type, par_types, default_arg_count, method_flags)) {
- // If the function require typed arrays we must make literals be typed.
+ // If the method is implemented in the class hierarchy, the virtual flag will not be set for that MethodInfo and the search stops there.
+ // Virtual check only possible for super() calls because class hierarchy is known. Node/Objects may have scripts attached we don't know of at compile-time.
+ if (p_call->is_super && method_flags.has_flag(METHOD_FLAG_VIRTUAL)) {
+ push_error(vformat(R"*(Cannot call the parent class' virtual function "%s()" because it hasn't been defined.)*", p_call->function_name), p_call);
+ }
+
+ // If the function requires typed arrays we must make literals be typed.
for (const KeyValue<int, GDScriptParser::ArrayNode *> &E : arrays) {
int index = E.key;
- if (index < par_types.size() && par_types[index].has_container_element_type()) {
+ if (index < par_types.size() && par_types[index].is_hard_type() && par_types[index].has_container_element_type()) {
update_array_literal_element_type(E.value, par_types[index].get_container_element_type());
}
}
@@ -3439,7 +3463,7 @@ void GDScriptAnalyzer::reduce_identifier_from_base_set_class(GDScriptParser::Ide
p_identifier->set_datatype(p_identifier_datatype);
Error err = OK;
- Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_identifier_datatype.script_path, err);
+ Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_identifier_datatype.script_path, err, parser->script_path);
if (err) {
push_error(vformat(R"(Error while getting cache for script "%s".)", p_identifier_datatype.script_path), p_identifier);
return;
@@ -4075,7 +4099,7 @@ void GDScriptAnalyzer::reduce_subscript(GDScriptParser::SubscriptNode *p_subscri
GDScriptParser::DataType base_type = p_subscript->base->get_datatype();
bool valid = false;
// If the base is a metatype, use the analyzer instead.
- if (p_subscript->base->is_constant && !base_type.is_meta_type) {
+ if (p_subscript->base->is_constant && !base_type.is_meta_type && base_type.kind != GDScriptParser::DataType::CLASS) {
// Just try to get it.
Variant value = p_subscript->base->reduced_value.get_named(p_subscript->attribute->name, valid);
if (valid) {
@@ -4563,7 +4587,7 @@ Array GDScriptAnalyzer::make_array_from_element_datatype(const GDScriptParser::D
Ref<Script> script_type = p_element_datatype.script_type;
if (p_element_datatype.kind == GDScriptParser::DataType::CLASS && script_type.is_null()) {
Error err = OK;
- Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_element_datatype.script_path, err);
+ Ref<GDScript> scr = GDScriptCache::get_shallow_script(p_element_datatype.script_path, err, parser->script_path);
if (err) {
push_error(vformat(R"(Error while getting cache for script "%s".)", p_element_datatype.script_path), p_source_node);
return array;
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index af7862efc5..8394fce9b3 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -35,9 +35,6 @@
#include "core/debugger/engine_debugger.h"
uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) {
-#ifdef TOOLS_ENABLED
- function->arg_names.push_back(p_name);
-#endif
function->_argument_count++;
function->argument_types.push_back(p_type);
if (p_is_optional) {
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index 985eb97b29..7f2c401afc 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -84,7 +84,7 @@ void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::N
}
}
-GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner) {
+GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner, bool p_handle_metatype) {
if (!p_datatype.is_set() || !p_datatype.is_hard_type() || p_datatype.is_coroutine) {
return GDScriptDataType();
}
@@ -101,11 +101,25 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.builtin_type = p_datatype.builtin_type;
} break;
case GDScriptParser::DataType::NATIVE: {
+ if (p_handle_metatype && p_datatype.is_meta_type) {
+ result.kind = GDScriptDataType::NATIVE;
+ result.builtin_type = Variant::OBJECT;
+ result.native_type = GDScriptNativeClass::get_class_static();
+ break;
+ }
+
result.kind = GDScriptDataType::NATIVE;
result.native_type = p_datatype.native_type;
result.builtin_type = p_datatype.builtin_type;
} break;
case GDScriptParser::DataType::SCRIPT: {
+ if (p_handle_metatype && p_datatype.is_meta_type) {
+ result.kind = GDScriptDataType::NATIVE;
+ result.builtin_type = Variant::OBJECT;
+ result.native_type = p_datatype.script_type.is_valid() ? p_datatype.script_type->get_class() : Script::get_class_static();
+ break;
+ }
+
result.kind = GDScriptDataType::SCRIPT;
result.builtin_type = p_datatype.builtin_type;
result.script_type_ref = p_datatype.script_type;
@@ -113,6 +127,13 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
result.native_type = p_datatype.native_type;
} break;
case GDScriptParser::DataType::CLASS: {
+ if (p_handle_metatype && p_datatype.is_meta_type) {
+ result.kind = GDScriptDataType::NATIVE;
+ result.builtin_type = Variant::OBJECT;
+ result.native_type = GDScript::get_class_static();
+ break;
+ }
+
result.kind = GDScriptDataType::GDSCRIPT;
result.builtin_type = p_datatype.builtin_type;
result.native_type = p_datatype.native_type;
@@ -148,6 +169,12 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
}
} break;
case GDScriptParser::DataType::ENUM:
+ if (p_handle_metatype && p_datatype.is_meta_type) {
+ result.kind = GDScriptDataType::BUILTIN;
+ result.builtin_type = Variant::DICTIONARY;
+ break;
+ }
+
result.kind = GDScriptDataType::BUILTIN;
result.builtin_type = p_datatype.builtin_type;
break;
@@ -159,7 +186,7 @@ GDScriptDataType GDScriptCompiler::_gdtype_from_datatype(const GDScriptParser::D
}
if (p_datatype.has_container_element_type()) {
- result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type(), p_owner));
+ result.set_container_element_type(_gdtype_from_datatype(p_datatype.get_container_element_type(), p_owner, false));
}
return result;
@@ -402,7 +429,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
String global_class_path = ScriptServer::get_global_class_path(identifier);
if (ResourceLoader::get_resource_type(global_class_path) == "GDScript") {
Error err = OK;
- res = GDScriptCache::get_full_script(global_class_path, err);
+ // Should not need to pass p_owner since analyzer will already have done it.
+ res = GDScriptCache::get_shallow_script(global_class_path, err);
if (err != OK) {
_set_error("Can't load global class " + String(identifier), p_expression);
r_error = ERR_COMPILATION_FAILED;
@@ -533,7 +561,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
} break;
case GDScriptParser::Node::CAST: {
const GDScriptParser::CastNode *cn = static_cast<const GDScriptParser::CastNode *>(p_expression);
- GDScriptDataType cast_type = _gdtype_from_datatype(cn->get_datatype(), codegen.script);
+ GDScriptDataType cast_type = _gdtype_from_datatype(cn->get_datatype(), codegen.script, false);
GDScriptCodeGenerator::Address result;
if (cast_type.has_type) {
@@ -911,7 +939,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
GDScriptCodeGenerator::Address result = codegen.add_temporary(_gdtype_from_datatype(type_test->get_datatype(), codegen.script));
GDScriptCodeGenerator::Address operand = _parse_expression(codegen, r_error, type_test->operand);
- GDScriptDataType test_type = _gdtype_from_datatype(type_test->test_datatype, codegen.script);
+ GDScriptDataType test_type = _gdtype_from_datatype(type_test->test_datatype, codegen.script, false);
if (r_error) {
return GDScriptCodeGenerator::Address();
}
@@ -2165,8 +2193,14 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
}
}
+ MethodInfo method_info;
+
codegen.function_name = func_name;
+ method_info.name = func_name;
codegen.is_static = is_static;
+ if (is_static) {
+ method_info.flags |= METHOD_FLAG_STATIC;
+ }
codegen.generator->write_start(p_script, func_name, is_static, rpc_config, return_type);
int optional_parameters = 0;
@@ -2178,10 +2212,14 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
uint32_t par_addr = codegen.generator->add_parameter(parameter->identifier->name, parameter->initializer != nullptr, par_type);
codegen.parameters[parameter->identifier->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, par_type);
+ method_info.arguments.push_back(parameter->get_datatype().to_property_info(parameter->identifier->name));
+
if (parameter->initializer != nullptr) {
optional_parameters++;
}
}
+
+ method_info.default_arguments.append_array(p_func->default_arg_values);
}
// Parse initializer if applies.
@@ -2335,20 +2373,20 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
}
if (p_func) {
- // if no return statement -> return type is void not unresolved Variant
+ // If no `return` statement, then return type is `void`, not `Variant`.
if (p_func->body->has_return) {
gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);
+ method_info.return_val = p_func->get_datatype().to_property_info(String());
} else {
gd_function->return_type = GDScriptDataType();
gd_function->return_type.has_type = true;
gd_function->return_type.kind = GDScriptDataType::BUILTIN;
gd_function->return_type.builtin_type = Variant::NIL;
}
-#ifdef TOOLS_ENABLED
- gd_function->default_arg_values = p_func->default_arg_values;
-#endif
}
+ gd_function->method_info = method_info;
+
if (!is_implicit_initializer && !is_implicit_ready && !p_for_lambda) {
p_script->member_functions[func_name] = gd_function;
}
@@ -2503,7 +2541,10 @@ Error GDScriptCompiler::_parse_setter_getter(GDScript *p_script, const GDScriptP
return err;
}
-Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
+// Prepares given script, and inner class scripts, for compilation. It populates class members and initializes method
+// RPC info for its base classes first, then for itself, then for inner classes.
+// Warning: this function cannot initiate compilation of other classes, or it will result in cyclic dependency issues.
+Error GDScriptCompiler::_prepare_compilation(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
if (parsed_classes.has(p_script)) {
return OK;
}
@@ -2554,7 +2595,6 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
p_script->member_functions.clear();
p_script->member_indices.clear();
- p_script->member_info.clear();
p_script->static_variables_indices.clear();
p_script->static_variables.clear();
p_script->_signals.clear();
@@ -2562,19 +2602,20 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
p_script->implicit_initializer = nullptr;
p_script->implicit_ready = nullptr;
p_script->static_initializer = nullptr;
+ p_script->rpc_config.clear();
p_script->clearing = false;
p_script->tool = parser->is_tool();
- if (!p_script->name.is_empty()) {
- if (ClassDB::class_exists(p_script->name) && ClassDB::is_class_exposed(p_script->name)) {
- _set_error("The class '" + p_script->name + "' shadows a native class", p_class);
+ if (p_script->local_name != StringName()) {
+ if (ClassDB::class_exists(p_script->local_name) && ClassDB::is_class_exposed(p_script->local_name)) {
+ _set_error(vformat(R"(The class "%s" shadows a native class)", p_script->local_name), p_class);
return ERR_ALREADY_EXISTS;
}
}
- GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type, p_script);
+ GDScriptDataType base_type = _gdtype_from_datatype(p_class->base_type, p_script, false);
int native_idx = GDScriptLanguage::get_singleton()->get_global_map()[base_type.native_type];
p_script->native = GDScriptLanguage::get_singleton()->get_global_array()[native_idx];
@@ -2592,7 +2633,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
}
if (main_script->has_class(base.ptr())) {
- Error err = _populate_class_members(base.ptr(), p_class->base_type.class_type, p_keep_state);
+ Error err = _prepare_compilation(base.ptr(), p_class->base_type.class_type, p_keep_state);
if (err) {
return err;
}
@@ -2611,7 +2652,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
return ERR_COMPILATION_FAILED;
}
- err = _populate_class_members(base.ptr(), p_class->base_type.class_type, p_keep_state);
+ err = _prepare_compilation(base.ptr(), p_class->base_type.class_type, p_keep_state);
if (err) {
_set_error(vformat(R"(Could not populate class members of base class "%s" in "%s".)", base->fully_qualified_name, base->path), nullptr);
return err;
@@ -2628,6 +2669,12 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
} break;
}
+ // Duplicate RPC information from base GDScript
+ // Base script isn't valid because it should not have been compiled yet, but the reference contains relevant info.
+ if (base_type.kind == GDScriptDataType::GDSCRIPT && p_script->base.is_valid()) {
+ p_script->rpc_config = p_script->base->rpc_config.duplicate();
+ }
+
for (int i = 0; i < p_class->members.size(); i++) {
const GDScriptParser::ClassNode::Member &member = p_class->members[i];
switch (member.type) {
@@ -2636,7 +2683,6 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
StringName name = variable->identifier->name;
GDScript::MemberInfo minfo;
- minfo.index = p_script->member_indices.size();
switch (variable->property) {
case GDScriptParser::VariableNode::PROP_NONE:
break; // Nothing to do.
@@ -2659,8 +2705,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
}
minfo.data_type = _gdtype_from_datatype(variable->get_datatype(), p_script);
- PropertyInfo prop_info = minfo.data_type;
- prop_info.name = name;
+ PropertyInfo prop_info = variable->get_datatype().to_property_info(name);
PropertyInfo export_info = variable->export_info;
if (variable->exported) {
@@ -2670,16 +2715,16 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
}
prop_info.hint = export_info.hint;
prop_info.hint_string = export_info.hint_string;
- prop_info.usage = export_info.usage | PROPERTY_USAGE_SCRIPT_VARIABLE;
- } else {
- prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE;
+ prop_info.usage = export_info.usage;
}
+ prop_info.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE;
+ minfo.property_info = prop_info;
if (variable->is_static) {
minfo.index = p_script->static_variables_indices.size();
p_script->static_variables_indices[name] = minfo;
} else {
- p_script->member_info[name] = prop_info;
+ minfo.index = p_script->member_indices.size();
p_script->member_indices[name] = minfo;
p_script->members.insert(name);
}
@@ -2712,12 +2757,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
const GDScriptParser::SignalNode *signal = member.signal;
StringName name = signal->identifier->name;
- Vector<StringName> parameters_names;
- parameters_names.resize(signal->parameters.size());
- for (int j = 0; j < signal->parameters.size(); j++) {
- parameters_names.write[j] = signal->parameters[j]->identifier->name;
- }
- p_script->_signals[name] = parameters_names;
+ p_script->_signals[name] = signal->method_info;
} break;
case GDScriptParser::ClassNode::Member::ENUM: {
@@ -2740,12 +2780,20 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
prop_info.name = annotation->export_info.name;
prop_info.usage = annotation->export_info.usage;
prop_info.hint_string = annotation->export_info.hint_string;
+ minfo.property_info = prop_info;
- p_script->member_info[name] = prop_info;
p_script->member_indices[name] = minfo;
p_script->members.insert(Variant());
} break;
+ case GDScriptParser::ClassNode::Member::FUNCTION: {
+ const GDScriptParser::FunctionNode *function_n = member.function;
+
+ Variant config = function_n->rpc_config;
+ if (config.get_type() != Variant::NIL) {
+ p_script->rpc_config[function_n->identifier->name] = config;
+ }
+ } break;
default:
break; // Nothing to do here.
}
@@ -2756,7 +2804,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
parsed_classes.insert(p_script);
parsing_classes.erase(p_script);
- // Populate sub-classes.
+ // Populate inner classes.
for (int i = 0; i < p_class->members.size(); i++) {
const GDScriptParser::ClassNode::Member &member = p_class->members[i];
if (member.type != member.CLASS) {
@@ -2769,7 +2817,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri
// Subclass might still be parsing, just skip it
if (!parsing_classes.has(subclass_ptr)) {
- Error err = _populate_class_members(subclass_ptr, inner_class, p_keep_state);
+ Error err = _prepare_compilation(subclass_ptr, inner_class, p_keep_state);
if (err) {
return err;
}
@@ -2905,8 +2953,6 @@ Error GDScriptCompiler::_compile_class(GDScript *p_script, const GDScriptParser:
has_static_data = has_static_data || inner_class->has_static_data;
}
- p_script->_init_rpc_methods_properties();
-
p_script->valid = true;
return OK;
}
@@ -2927,7 +2973,8 @@ void GDScriptCompiler::convert_to_initializer_type(Variant &p_variant, const GDS
void GDScriptCompiler::make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) {
p_script->fully_qualified_name = p_class->fqcn;
- p_script->name = p_class->identifier ? p_class->identifier->name : "";
+ p_script->local_name = p_class->identifier ? p_class->identifier->name : StringName();
+ p_script->global_name = p_class->get_global_name();
p_script->simplified_icon_path = p_class->simplified_icon_path;
HashMap<StringName, Ref<GDScript>> old_subclasses;
@@ -2979,7 +3026,7 @@ Error GDScriptCompiler::compile(const GDScriptParser *p_parser, GDScript *p_scri
make_scripts(p_script, root, p_keep_state);
main_script->_owner = nullptr;
- Error err = _populate_class_members(main_script, parser->get_tree(), p_keep_state);
+ Error err = _prepare_compilation(main_script, parser->get_tree(), p_keep_state);
if (err) {
return err;
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 2f522da4ea..099bd00a2e 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -124,7 +124,7 @@ class GDScriptCompiler {
Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::BinaryOpNode *on, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
Error _create_binary_operator(CodeGen &codegen, const GDScriptParser::ExpressionNode *p_left_operand, const GDScriptParser::ExpressionNode *p_right_operand, Variant::Operator op, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
- GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner);
+ GDScriptDataType _gdtype_from_datatype(const GDScriptParser::DataType &p_datatype, GDScript *p_owner, bool p_handle_metatype = true);
GDScriptCodeGenerator::Address _parse_assign_right_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::AssignmentNode *p_assignmentint, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
GDScriptCodeGenerator::Address _parse_expression(CodeGen &codegen, Error &r_error, const GDScriptParser::ExpressionNode *p_expression, bool p_root = false, bool p_initializer = false, const GDScriptCodeGenerator::Address &p_index_addr = GDScriptCodeGenerator::Address());
@@ -135,7 +135,7 @@ class GDScriptCompiler {
GDScriptFunction *_parse_function(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::FunctionNode *p_func, bool p_for_ready = false, bool p_for_lambda = false);
GDScriptFunction *_make_static_initializer(Error &r_error, GDScript *p_script, const GDScriptParser::ClassNode *p_class);
Error _parse_setter_getter(GDScript *p_script, const GDScriptParser::ClassNode *p_class, const GDScriptParser::VariableNode *p_variable, bool p_is_setter);
- Error _populate_class_members(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
+ Error _prepare_compilation(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
Error _compile_class(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state);
int err_line = 0;
int err_column = 0;
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 6cad3b2b90..00d3df8fd0 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -59,6 +59,7 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("' '");
p_delimiters->push_back("\"\"\" \"\"\"");
p_delimiters->push_back("''' '''");
+ // NOTE: StringName, NodePath and r-strings are not listed here.
}
bool GDScriptLanguage::is_using_templates() {
@@ -500,7 +501,7 @@ String GDScriptLanguage::make_function(const String &p_class, const String &p_na
s += p_args[i].get_slice(":", 0);
if (th) {
String type = p_args[i].get_slice(":", 1);
- if (!type.is_empty() && type != "var") {
+ if (!type.is_empty()) {
s += ": " + type;
}
}
@@ -1459,8 +1460,13 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
if (p_expression->is_constant) {
// Already has a value, so just use that.
r_type = _type_from_variant(p_expression->reduced_value);
- if (p_expression->get_datatype().kind == GDScriptParser::DataType::ENUM) {
- r_type.type = p_expression->get_datatype();
+ switch (p_expression->get_datatype().kind) {
+ case GDScriptParser::DataType::ENUM:
+ case GDScriptParser::DataType::CLASS:
+ r_type.type = p_expression->get_datatype();
+ break;
+ default:
+ break;
}
found = true;
} else {
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index a6b4dc7981..4f5a65a709 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -32,14 +32,6 @@
#include "gdscript.h"
-const int *GDScriptFunction::get_code() const {
- return _code_ptr;
-}
-
-int GDScriptFunction::get_code_size() const {
- return _code_size;
-}
-
Variant GDScriptFunction::get_constant(int p_idx) const {
ERR_FAIL_INDEX_V(p_idx, constants.size(), "<errconst>");
return constants[p_idx];
@@ -50,32 +42,6 @@ StringName GDScriptFunction::get_global_name(int p_idx) const {
return global_names[p_idx];
}
-int GDScriptFunction::get_default_argument_count() const {
- return _default_arg_count;
-}
-
-int GDScriptFunction::get_default_argument_addr(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), -1);
- return default_arguments[p_idx];
-}
-
-GDScriptDataType GDScriptFunction::get_return_type() const {
- return return_type;
-}
-
-GDScriptDataType GDScriptFunction::get_argument_type(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, argument_types.size(), GDScriptDataType());
- return argument_types[p_idx];
-}
-
-StringName GDScriptFunction::get_name() const {
- return name;
-}
-
-int GDScriptFunction::get_max_stack_size() const {
- return _stack_size;
-}
-
struct _GDFKC {
int order = 0;
List<int> pos;
@@ -161,9 +127,7 @@ GDScriptFunction::~GDScriptFunction() {
return_type.script_type_ref = Ref<Script>();
#ifdef DEBUG_ENABLED
-
MutexLock lock(GDScriptLanguage::get_singleton()->mutex);
-
GDScriptLanguage::get_singleton()->function_list.remove(&function_list);
#endif
}
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 5230773c13..31da70f9ae 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -147,33 +147,6 @@ public:
return false;
}
- operator PropertyInfo() const {
- PropertyInfo info;
- info.usage = PROPERTY_USAGE_NONE;
- if (has_type) {
- switch (kind) {
- case UNINITIALIZED:
- break;
- case BUILTIN: {
- info.type = builtin_type;
- } break;
- case NATIVE: {
- info.type = Variant::OBJECT;
- info.class_name = native_type;
- } break;
- case SCRIPT:
- case GDSCRIPT: {
- info.type = Variant::OBJECT;
- info.class_name = script_type->get_instance_base_type();
- } break;
- }
- } else {
- info.type = Variant::NIL;
- info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
- }
- return info;
- }
-
void set_container_element_type(const GDScriptDataType &p_element_type) {
container_element_type = memnew(GDScriptDataType(p_element_type));
}
@@ -437,59 +410,32 @@ private:
friend class GDScript;
friend class GDScriptCompiler;
friend class GDScriptByteCodeGenerator;
+ friend class GDScriptLanguage;
+ StringName name;
StringName source;
+ bool _static = false;
+ Vector<GDScriptDataType> argument_types;
+ GDScriptDataType return_type;
+ MethodInfo method_info;
+ Variant rpc_config;
- mutable Variant nil;
- mutable Variant *_constants_ptr = nullptr;
- int _constant_count = 0;
- const StringName *_global_names_ptr = nullptr;
- int _global_names_count = 0;
- const int *_default_arg_ptr = nullptr;
- int _default_arg_count = 0;
- int _operator_funcs_count = 0;
- const Variant::ValidatedOperatorEvaluator *_operator_funcs_ptr = nullptr;
- int _setters_count = 0;
- const Variant::ValidatedSetter *_setters_ptr = nullptr;
- int _getters_count = 0;
- const Variant::ValidatedGetter *_getters_ptr = nullptr;
- int _keyed_setters_count = 0;
- const Variant::ValidatedKeyedSetter *_keyed_setters_ptr = nullptr;
- int _keyed_getters_count = 0;
- const Variant::ValidatedKeyedGetter *_keyed_getters_ptr = nullptr;
- int _indexed_setters_count = 0;
- const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr;
- int _indexed_getters_count = 0;
- const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr;
- int _builtin_methods_count = 0;
- const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr;
- int _constructors_count = 0;
- const Variant::ValidatedConstructor *_constructors_ptr = nullptr;
- int _utilities_count = 0;
- const Variant::ValidatedUtilityFunction *_utilities_ptr = nullptr;
- int _gds_utilities_count = 0;
- const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr;
- int _methods_count = 0;
- MethodBind **_methods_ptr = nullptr;
- int _lambdas_count = 0;
- GDScriptFunction **_lambdas_ptr = nullptr;
- int *_code_ptr = nullptr;
- int _code_size = 0;
+ GDScript *_script = nullptr;
+ int _initial_line = 0;
int _argument_count = 0;
int _stack_size = 0;
int _instruction_args_size = 0;
int _ptrcall_args_size = 0;
- int _initial_line = 0;
- bool _static = false;
- Variant rpc_config;
-
- GDScript *_script = nullptr;
+ SelfList<GDScriptFunction> function_list{ this };
+ mutable Variant nil;
+ HashMap<int, Variant::Type> temporary_slots;
+ List<StackDebug> stack_debug;
- StringName name;
+ Vector<int> code;
+ Vector<int> default_arguments;
Vector<Variant> constants;
Vector<StringName> global_names;
- Vector<int> default_arguments;
Vector<Variant::ValidatedOperatorEvaluator> operator_funcs;
Vector<Variant::ValidatedSetter> setters;
Vector<Variant::ValidatedGetter> getters;
@@ -503,18 +449,47 @@ private:
Vector<GDScriptUtilityFunctions::FunctionPtr> gds_utilities;
Vector<MethodBind *> methods;
Vector<GDScriptFunction *> lambdas;
- Vector<int> code;
- Vector<GDScriptDataType> argument_types;
- GDScriptDataType return_type;
- HashMap<int, Variant::Type> temporary_slots;
+ int _code_size = 0;
+ int _default_arg_count = 0;
+ int _constant_count = 0;
+ int _global_names_count = 0;
+ int _operator_funcs_count = 0;
+ int _setters_count = 0;
+ int _getters_count = 0;
+ int _keyed_setters_count = 0;
+ int _keyed_getters_count = 0;
+ int _indexed_setters_count = 0;
+ int _indexed_getters_count = 0;
+ int _builtin_methods_count = 0;
+ int _constructors_count = 0;
+ int _utilities_count = 0;
+ int _gds_utilities_count = 0;
+ int _methods_count = 0;
+ int _lambdas_count = 0;
-#ifdef TOOLS_ENABLED
- Vector<StringName> arg_names;
- Vector<Variant> default_arg_values;
-#endif
+ int *_code_ptr = nullptr;
+ const int *_default_arg_ptr = nullptr;
+ mutable Variant *_constants_ptr = nullptr;
+ const StringName *_global_names_ptr = nullptr;
+ const Variant::ValidatedOperatorEvaluator *_operator_funcs_ptr = nullptr;
+ const Variant::ValidatedSetter *_setters_ptr = nullptr;
+ const Variant::ValidatedGetter *_getters_ptr = nullptr;
+ const Variant::ValidatedKeyedSetter *_keyed_setters_ptr = nullptr;
+ const Variant::ValidatedKeyedGetter *_keyed_getters_ptr = nullptr;
+ const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr;
+ const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr;
+ const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr;
+ const Variant::ValidatedConstructor *_constructors_ptr = nullptr;
+ const Variant::ValidatedUtilityFunction *_utilities_ptr = nullptr;
+ const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr;
+ MethodBind **_methods_ptr = nullptr;
+ GDScriptFunction **_lambdas_ptr = nullptr;
#ifdef DEBUG_ENABLED
+ CharString func_cname;
+ const char *_func_cname = nullptr;
+
Vector<String> operator_names;
Vector<String> setter_names;
Vector<String> getter_names;
@@ -522,20 +497,6 @@ private:
Vector<String> constructors_names;
Vector<String> utilities_names;
Vector<String> gds_utilities_names;
-#endif
-
- List<StackDebug> stack_debug;
-
- Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type);
-
- _FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const;
-
- friend class GDScriptLanguage;
-
- SelfList<GDScriptFunction> function_list{ this };
-#ifdef DEBUG_ENABLED
- CharString func_cname;
- const char *_func_cname = nullptr;
struct Profile {
StringName signature;
@@ -549,9 +510,11 @@ private:
uint64_t last_frame_self_time = 0;
uint64_t last_frame_total_time = 0;
} profile;
-
#endif
+ _FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const;
+ Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type);
+
public:
static constexpr int MAX_CALL_DEPTH = 2048; // Limit to try to avoid crash because of a stack overflow.
@@ -571,51 +534,24 @@ public:
Variant result;
};
+ _FORCE_INLINE_ StringName get_name() const { return name; }
+ _FORCE_INLINE_ StringName get_source() const { return source; }
+ _FORCE_INLINE_ GDScript *get_script() const { return _script; }
_FORCE_INLINE_ bool is_static() const { return _static; }
+ _FORCE_INLINE_ MethodInfo get_method_info() const { return method_info; }
+ _FORCE_INLINE_ Variant get_rpc_config() const { return rpc_config; }
+ _FORCE_INLINE_ int get_max_stack_size() const { return _stack_size; }
- const int *get_code() const; //used for debug
- int get_code_size() const;
Variant get_constant(int p_idx) const;
StringName get_global_name(int p_idx) const;
- StringName get_name() const;
- int get_max_stack_size() const;
- int get_default_argument_count() const;
- int get_default_argument_addr(int p_idx) const;
- GDScriptDataType get_return_type() const;
- GDScriptDataType get_argument_type(int p_idx) const;
- GDScript *get_script() const { return _script; }
- StringName get_source() const { return source; }
-
- void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const;
-
- _FORCE_INLINE_ bool is_empty() const { return _code_size == 0; }
-
- int get_argument_count() const { return _argument_count; }
- StringName get_argument_name(int p_idx) const {
-#ifdef TOOLS_ENABLED
- ERR_FAIL_INDEX_V(p_idx, arg_names.size(), StringName());
- return arg_names[p_idx];
-#else
- return StringName();
-#endif
- }
- Variant get_default_argument(int p_idx) const {
- ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), Variant());
- return default_arguments[p_idx];
- }
-#ifdef TOOLS_ENABLED
- const Vector<Variant> &get_default_arg_values() const {
- return default_arg_values;
- }
-#endif // TOOLS_ENABLED
Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = nullptr);
+ void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const;
#ifdef DEBUG_ENABLED
void disassemble(const Vector<String> &p_code_lines) const;
#endif
- _FORCE_INLINE_ const Variant get_rpc_config() const { return rpc_config; }
GDScriptFunction();
~GDScriptFunction();
};
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index 3b89f077bd..9d0fce0928 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -79,13 +79,48 @@ void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, V
args.resize(p_argcount + captures_amount);
for (int i = 0; i < captures_amount; i++) {
args.write[i] = &captures[i];
+ if (captures[i].get_type() == Variant::OBJECT) {
+ bool was_freed = false;
+ captures[i].get_validated_object_with_check(was_freed);
+ if (was_freed) {
+ ERR_PRINT(vformat(R"(Lambda capture at index %d was freed. Passed "null" instead.)", i));
+ static Variant nil;
+ args.write[i] = &nil;
+ }
+ }
}
for (int i = 0; i < p_argcount; i++) {
args.write[i + captures_amount] = p_arguments[i];
}
r_return_value = function->call(nullptr, args.ptrw(), args.size(), r_call_error);
- r_call_error.argument -= captures_amount;
+ switch (r_call_error.error) {
+ case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
+ r_call_error.argument -= captures_amount;
+#ifdef DEBUG_ENABLED
+ if (r_call_error.argument < 0) {
+ ERR_PRINT(vformat("GDScript bug (please report): Invalid value of lambda capture at index %d.", captures_amount + r_call_error.argument));
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // TODO: Add a more suitable error code.
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ }
+#endif
+ break;
+ case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
+ case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
+ r_call_error.expected -= captures_amount;
+#ifdef DEBUG_ENABLED
+ if (r_call_error.expected < 0) {
+ ERR_PRINT("GDScript bug (please report): Invalid lambda captures count.");
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // TODO: Add a more suitable error code.
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ }
+#endif
+ break;
+ default:
+ break;
+ }
} else {
r_return_value = function->call(nullptr, p_arguments, p_argcount, r_call_error);
}
@@ -148,13 +183,48 @@ void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcoun
args.resize(p_argcount + captures_amount);
for (int i = 0; i < captures_amount; i++) {
args.write[i] = &captures[i];
+ if (captures[i].get_type() == Variant::OBJECT) {
+ bool was_freed = false;
+ captures[i].get_validated_object_with_check(was_freed);
+ if (was_freed) {
+ ERR_PRINT(vformat(R"(Lambda capture at index %d was freed. Passed "null" instead.)", i));
+ static Variant nil;
+ args.write[i] = &nil;
+ }
+ }
}
for (int i = 0; i < p_argcount; i++) {
args.write[i + captures_amount] = p_arguments[i];
}
r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), args.ptrw(), args.size(), r_call_error);
- r_call_error.argument -= captures_amount;
+ switch (r_call_error.error) {
+ case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
+ r_call_error.argument -= captures_amount;
+#ifdef DEBUG_ENABLED
+ if (r_call_error.argument < 0) {
+ ERR_PRINT(vformat("GDScript bug (please report): Invalid value of lambda capture at index %d.", captures_amount + r_call_error.argument));
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // TODO: Add a more suitable error code.
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ }
+#endif
+ break;
+ case Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS:
+ case Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS:
+ r_call_error.expected -= captures_amount;
+#ifdef DEBUG_ENABLED
+ if (r_call_error.expected < 0) {
+ ERR_PRINT("GDScript bug (please report): Invalid lambda captures count.");
+ r_call_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; // TODO: Add a more suitable error code.
+ r_call_error.argument = 0;
+ r_call_error.expected = 0;
+ }
+#endif
+ break;
+ default:
+ break;
+ }
} else {
r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), p_arguments, p_argcount, r_call_error);
}
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index a0d02b12b5..1202e7e235 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -383,8 +383,10 @@ GDScriptTokenizer::Token GDScriptParser::advance() {
push_error(current.literal);
current = tokenizer.scan();
}
- for (Node *n : nodes_in_progress) {
- update_extents(n);
+ if (previous.type != GDScriptTokenizer::Token::DEDENT) { // `DEDENT` belongs to the next non-empty line.
+ for (Node *n : nodes_in_progress) {
+ update_extents(n);
+ }
}
return previous;
}
@@ -579,13 +581,14 @@ void GDScriptParser::parse_program() {
complete_extents(head);
#ifdef TOOLS_ENABLED
- for (const KeyValue<int, GDScriptTokenizer::CommentData> &E : tokenizer.get_comments()) {
- if (E.value.new_line && E.value.comment.begins_with("##")) {
- class_doc_line = MIN(class_doc_line, E.key);
+ const HashMap<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
+ int line = MIN(max_script_doc_line, head->end_line);
+ while (line > 0) {
+ if (comments.has(line) && comments[line].new_line && comments[line].comment.begins_with("##")) {
+ head->doc_data = parse_class_doc_comment(line);
+ break;
}
- }
- if (has_comment(class_doc_line, true)) {
- head->doc_data = parse_class_doc_comment(class_doc_line, false);
+ line--;
}
#endif // TOOLS_ENABLED
@@ -747,10 +750,6 @@ template <class T>
void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(bool), AnnotationInfo::TargetKind p_target, const String &p_member_kind, bool p_is_static) {
advance();
-#ifdef TOOLS_ENABLED
- int doc_comment_line = previous.start_line - 1;
-#endif // TOOLS_ENABLED
-
// Consume annotations.
List<AnnotationNode *> annotations;
while (!annotation_stack.is_empty()) {
@@ -762,11 +761,6 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(b
push_error(vformat(R"(Annotation "%s" cannot be applied to a %s.)", last_annotation->name, p_member_kind));
clear_unused_annotations();
}
-#ifdef TOOLS_ENABLED
- if (last_annotation->start_line == doc_comment_line) {
- doc_comment_line--;
- }
-#endif // TOOLS_ENABLED
}
T *member = (this->*p_parse_function)(p_is_static);
@@ -774,28 +768,40 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(b
return;
}
+#ifdef TOOLS_ENABLED
+ int doc_comment_line = member->start_line - 1;
+#endif // TOOLS_ENABLED
+
for (AnnotationNode *&annotation : annotations) {
member->annotations.push_back(annotation);
+#ifdef TOOLS_ENABLED
+ if (annotation->start_line <= doc_comment_line) {
+ doc_comment_line = annotation->start_line - 1;
+ }
+#endif // TOOLS_ENABLED
}
#ifdef TOOLS_ENABLED
- // Consume doc comments.
- class_doc_line = MIN(class_doc_line, doc_comment_line - 1);
-
- // Check whether current line has a doc comment
- if (has_comment(previous.start_line, true)) {
- if constexpr (std::is_same_v<T, ClassNode>) {
- member->doc_data = parse_class_doc_comment(previous.start_line, true, true);
- } else {
- member->doc_data = parse_doc_comment(previous.start_line, true);
+ if constexpr (std::is_same_v<T, ClassNode>) {
+ if (has_comment(member->start_line, true)) {
+ // Inline doc comment.
+ member->doc_data = parse_class_doc_comment(member->start_line, true);
+ } else if (has_comment(doc_comment_line, true) && tokenizer.get_comments()[doc_comment_line].new_line) {
+ // Normal doc comment. Don't check `min_member_doc_line` because a class ends parsing after its members.
+ // This may not work correctly for cases like `var a; class B`, but it doesn't matter in practice.
+ member->doc_data = parse_class_doc_comment(doc_comment_line);
}
- } else if (has_comment(doc_comment_line, true)) {
- if constexpr (std::is_same_v<T, ClassNode>) {
- member->doc_data = parse_class_doc_comment(doc_comment_line, true);
- } else {
+ } else {
+ if (has_comment(member->start_line, true)) {
+ // Inline doc comment.
+ member->doc_data = parse_doc_comment(member->start_line, true);
+ } else if (doc_comment_line >= min_member_doc_line && has_comment(doc_comment_line, true) && tokenizer.get_comments()[doc_comment_line].new_line) {
+ // Normal doc comment.
member->doc_data = parse_doc_comment(doc_comment_line);
}
}
+
+ min_member_doc_line = member->end_line + 1; // Prevent multiple members from using the same doc comment.
#endif // TOOLS_ENABLED
if (member->identifier != nullptr) {
@@ -1263,6 +1269,9 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum(bool p_is_static) {
push_multiline(true);
consume(GDScriptTokenizer::Token::BRACE_OPEN, vformat(R"(Expected "{" after %s.)", named ? "enum name" : R"("enum")"));
+#ifdef TOOLS_ENABLED
+ int min_enum_value_doc_line = previous.end_line + 1;
+#endif
HashMap<StringName, int> elements;
@@ -1325,43 +1334,35 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum(bool p_is_static) {
}
} while (match(GDScriptTokenizer::Token::COMMA));
- pop_multiline();
- consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected closing "}" for enum.)");
-
#ifdef TOOLS_ENABLED
// Enum values documentation.
for (int i = 0; i < enum_node->values.size(); i++) {
- int doc_comment_line = enum_node->values[i].line;
- bool single_line = false;
-
- if (has_comment(doc_comment_line, true)) {
- single_line = true;
- } else if (has_comment(doc_comment_line - 1, true)) {
- doc_comment_line--;
- } else {
- continue;
- }
-
- if (i == enum_node->values.size() - 1) {
- // If close bracket is same line as last value.
- if (doc_comment_line == previous.start_line) {
- break;
- }
- } else {
- // If two values are same line.
- if (doc_comment_line == enum_node->values[i + 1].line) {
- continue;
+ int enum_value_line = enum_node->values[i].line;
+ int doc_comment_line = enum_value_line - 1;
+
+ MemberDocData doc_data;
+ if (has_comment(enum_value_line, true)) {
+ // Inline doc comment.
+ if (i == enum_node->values.size() - 1 || enum_node->values[i + 1].line > enum_value_line) {
+ doc_data = parse_doc_comment(enum_value_line, true);
}
+ } else if (doc_comment_line >= min_enum_value_doc_line && has_comment(doc_comment_line, true) && tokenizer.get_comments()[doc_comment_line].new_line) {
+ // Normal doc comment.
+ doc_data = parse_doc_comment(doc_comment_line);
}
if (named) {
- enum_node->values.write[i].doc_data = parse_doc_comment(doc_comment_line, single_line);
+ enum_node->values.write[i].doc_data = doc_data;
} else {
- current_class->set_enum_value_doc_data(enum_node->values[i].identifier->name, parse_doc_comment(doc_comment_line, single_line));
+ current_class->set_enum_value_doc_data(enum_node->values[i].identifier->name, doc_data);
}
+
+ min_enum_value_doc_line = enum_value_line + 1; // Prevent multiple enum values from using the same doc comment.
}
#endif // TOOLS_ENABLED
+ pop_multiline();
+ consume(GDScriptTokenizer::Token::BRACE_CLOSE, R"(Expected closing "}" for enum.)");
complete_extents(enum_node);
end_statement("enum");
@@ -3454,31 +3455,21 @@ bool GDScriptParser::has_comment(int p_line, bool p_must_be_doc) {
}
GDScriptParser::MemberDocData GDScriptParser::parse_doc_comment(int p_line, bool p_single_line) {
- MemberDocData result;
+ ERR_FAIL_COND_V(!has_comment(p_line, true), MemberDocData());
const HashMap<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
- ERR_FAIL_COND_V(!comments.has(p_line), result);
-
- if (p_single_line) {
- if (comments[p_line].comment.begins_with("##")) {
- result.description = comments[p_line].comment.trim_prefix("##").strip_edges();
- return result;
- }
- return result;
- }
-
int line = p_line;
- DocLineState state = DOC_LINE_NORMAL;
- while (comments.has(line - 1)) {
- if (!comments[line - 1].new_line || !comments[line - 1].comment.begins_with("##")) {
- break;
+ if (!p_single_line) {
+ while (comments.has(line - 1) && comments[line - 1].new_line && comments[line - 1].comment.begins_with("##")) {
+ line--;
}
- line--;
}
+ max_script_doc_line = MIN(max_script_doc_line, line - 1);
+
String space_prefix;
- if (comments.has(line) && comments[line].comment.begins_with("##")) {
+ {
int i = 2;
for (; i < comments[line].comment.length(); i++) {
if (comments[line].comment[i] != ' ') {
@@ -3488,11 +3479,10 @@ GDScriptParser::MemberDocData GDScriptParser::parse_doc_comment(int p_line, bool
space_prefix = String(" ").repeat(i - 2);
}
- while (comments.has(line)) {
- if (!comments[line].new_line || !comments[line].comment.begins_with("##")) {
- break;
- }
+ DocLineState state = DOC_LINE_NORMAL;
+ MemberDocData result;
+ while (line <= p_line) {
String doc_line = comments[line].comment.trim_prefix("##");
line++;
@@ -3513,35 +3503,22 @@ GDScriptParser::MemberDocData GDScriptParser::parse_doc_comment(int p_line, bool
return result;
}
-GDScriptParser::ClassDocData GDScriptParser::parse_class_doc_comment(int p_line, bool p_inner_class, bool p_single_line) {
- ClassDocData result;
+GDScriptParser::ClassDocData GDScriptParser::parse_class_doc_comment(int p_line, bool p_single_line) {
+ ERR_FAIL_COND_V(!has_comment(p_line, true), ClassDocData());
const HashMap<int, GDScriptTokenizer::CommentData> &comments = tokenizer.get_comments();
- ERR_FAIL_COND_V(!comments.has(p_line), result);
-
- if (p_single_line) {
- if (comments[p_line].comment.begins_with("##")) {
- result.brief = comments[p_line].comment.trim_prefix("##").strip_edges();
- return result;
- }
- return result;
- }
-
int line = p_line;
- DocLineState state = DOC_LINE_NORMAL;
- bool is_in_brief = true;
- if (p_inner_class) {
- while (comments.has(line - 1)) {
- if (!comments[line - 1].new_line || !comments[line - 1].comment.begins_with("##")) {
- break;
- }
+ if (!p_single_line) {
+ while (comments.has(line - 1) && comments[line - 1].new_line && comments[line - 1].comment.begins_with("##")) {
line--;
}
}
+ max_script_doc_line = MIN(max_script_doc_line, line - 1);
+
String space_prefix;
- if (comments.has(line) && comments[line].comment.begins_with("##")) {
+ {
int i = 2;
for (; i < comments[line].comment.length(); i++) {
if (comments[line].comment[i] != ' ') {
@@ -3551,11 +3528,11 @@ GDScriptParser::ClassDocData GDScriptParser::parse_class_doc_comment(int p_line,
space_prefix = String(" ").repeat(i - 2);
}
- while (comments.has(line)) {
- if (!comments[line].new_line || !comments[line].comment.begins_with("##")) {
- break;
- }
+ DocLineState state = DOC_LINE_NORMAL;
+ bool is_in_brief = true;
+ ClassDocData result;
+ while (line <= p_line) {
String doc_line = comments[line].comment.trim_prefix("##");
line++;
@@ -3630,14 +3607,6 @@ GDScriptParser::ClassDocData GDScriptParser::parse_class_doc_comment(int p_line,
}
}
- if (current_class->members.size() > 0) {
- const ClassNode::Member &m = current_class->members[0];
- int first_member_line = m.get_line();
- if (first_member_line == line) {
- result = ClassDocData(); // Clear result.
- }
- }
-
return result;
}
#endif // TOOLS_ENABLED
@@ -4095,23 +4064,29 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
}
} break;
case GDScriptParser::DataType::ENUM: {
- variable->export_info.type = Variant::INT;
- variable->export_info.hint = PROPERTY_HINT_ENUM;
-
- String enum_hint_string;
- bool first = true;
- for (const KeyValue<StringName, int64_t> &E : export_type.enum_values) {
- if (!first) {
- enum_hint_string += ",";
- } else {
- first = false;
+ if (export_type.is_meta_type) {
+ variable->export_info.type = Variant::DICTIONARY;
+ } else {
+ variable->export_info.type = Variant::INT;
+ variable->export_info.hint = PROPERTY_HINT_ENUM;
+
+ String enum_hint_string;
+ bool first = true;
+ for (const KeyValue<StringName, int64_t> &E : export_type.enum_values) {
+ if (!first) {
+ enum_hint_string += ",";
+ } else {
+ first = false;
+ }
+ enum_hint_string += E.key.operator String().capitalize().xml_escape();
+ enum_hint_string += ":";
+ enum_hint_string += String::num_int64(E.value).xml_escape();
}
- enum_hint_string += E.key.operator String().capitalize().xml_escape();
- enum_hint_string += ":";
- enum_hint_string += String::num_int64(E.value).xml_escape();
- }
- variable->export_info.hint_string = enum_hint_string;
+ variable->export_info.hint_string = enum_hint_string;
+ variable->export_info.usage |= PROPERTY_USAGE_CLASS_IS_ENUM;
+ variable->export_info.class_name = String(export_type.native_type).replace("::", ".");
+ }
} break;
default:
push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable);
@@ -4370,6 +4345,104 @@ String GDScriptParser::DataType::to_string() const {
ERR_FAIL_V_MSG("<unresolved type>", "Kind set outside the enum range.");
}
+PropertyInfo GDScriptParser::DataType::to_property_info(const String &p_name) const {
+ PropertyInfo result;
+ result.name = p_name;
+ result.usage = PROPERTY_USAGE_NONE;
+
+ if (!is_hard_type()) {
+ result.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ return result;
+ }
+
+ switch (kind) {
+ case BUILTIN:
+ result.type = builtin_type;
+ if (builtin_type == Variant::ARRAY && has_container_element_type()) {
+ const DataType *elem_type = container_element_type;
+ switch (elem_type->kind) {
+ case BUILTIN:
+ result.hint = PROPERTY_HINT_ARRAY_TYPE;
+ result.hint_string = Variant::get_type_name(elem_type->builtin_type);
+ break;
+ case NATIVE:
+ result.hint = PROPERTY_HINT_ARRAY_TYPE;
+ result.hint_string = elem_type->native_type;
+ break;
+ case SCRIPT:
+ result.hint = PROPERTY_HINT_ARRAY_TYPE;
+ if (elem_type->script_type.is_valid() && elem_type->script_type->get_global_name() != StringName()) {
+ result.hint_string = elem_type->script_type->get_global_name();
+ } else {
+ result.hint_string = elem_type->native_type;
+ }
+ break;
+ case CLASS:
+ result.hint = PROPERTY_HINT_ARRAY_TYPE;
+ if (elem_type->class_type != nullptr && elem_type->class_type->get_global_name() != StringName()) {
+ result.hint_string = elem_type->class_type->get_global_name();
+ } else {
+ result.hint_string = elem_type->native_type;
+ }
+ break;
+ case ENUM:
+ result.hint = PROPERTY_HINT_ARRAY_TYPE;
+ result.hint_string = String(elem_type->native_type).replace("::", ".");
+ break;
+ case VARIANT:
+ case RESOLVING:
+ case UNRESOLVED:
+ break;
+ }
+ }
+ break;
+ case NATIVE:
+ result.type = Variant::OBJECT;
+ if (is_meta_type) {
+ result.class_name = GDScriptNativeClass::get_class_static();
+ } else {
+ result.class_name = native_type;
+ }
+ break;
+ case SCRIPT:
+ result.type = Variant::OBJECT;
+ if (is_meta_type) {
+ result.class_name = script_type.is_valid() ? script_type->get_class() : Script::get_class_static();
+ } else if (script_type.is_valid() && script_type->get_global_name() != StringName()) {
+ result.class_name = script_type->get_global_name();
+ } else {
+ result.class_name = native_type;
+ }
+ break;
+ case CLASS:
+ result.type = Variant::OBJECT;
+ if (is_meta_type) {
+ result.class_name = GDScript::get_class_static();
+ } else if (class_type != nullptr && class_type->get_global_name() != StringName()) {
+ result.class_name = class_type->get_global_name();
+ } else {
+ result.class_name = native_type;
+ }
+ break;
+ case ENUM:
+ if (is_meta_type) {
+ result.type = Variant::DICTIONARY;
+ } else {
+ result.type = Variant::INT;
+ result.usage |= PROPERTY_USAGE_CLASS_IS_ENUM;
+ result.class_name = String(native_type).replace("::", ".");
+ }
+ break;
+ case VARIANT:
+ case RESOLVING:
+ case UNRESOLVED:
+ result.usage |= PROPERTY_USAGE_NIL_IS_VARIANT;
+ break;
+ }
+
+ return result;
+}
+
static Variant::Type _variant_type_to_typed_array_element_type(Variant::Type p_type) {
switch (p_type) {
case Variant::PACKED_BYTE_ARRAY:
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 9690784cba..988524d058 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -147,7 +147,9 @@ public:
_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
_FORCE_INLINE_ bool is_variant() const { return kind == VARIANT || kind == RESOLVING || kind == UNRESOLVED; }
_FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; }
+
String to_string() const;
+ PropertyInfo to_property_info(const String &p_name) const;
_FORCE_INLINE_ void set_container_element_type(const DataType &p_type) {
container_element_type = memnew(DataType(p_type));
@@ -749,6 +751,10 @@ public:
bool resolved_interface = false;
bool resolved_body = false;
+ StringName get_global_name() const {
+ return (outer == nullptr && identifier != nullptr) ? identifier->name : StringName();
+ }
+
Member get_member(const StringName &p_name) const {
return members[members_indices[p_name]];
}
@@ -836,8 +842,8 @@ public:
Variant rpc_config;
MethodInfo info;
LambdaNode *source_lambda = nullptr;
-#ifdef TOOLS_ENABLED
Vector<Variant> default_arg_values;
+#ifdef TOOLS_ENABLED
MemberDocData doc_data;
#endif // TOOLS_ENABLED
@@ -1026,6 +1032,7 @@ public:
IdentifierNode *identifier = nullptr;
Vector<ParameterNode *> parameters;
HashMap<StringName, int> parameters_indices;
+ MethodInfo method_info;
#ifdef TOOLS_ENABLED
MemberDocData doc_data;
#endif // TOOLS_ENABLED
@@ -1510,10 +1517,11 @@ private:
TypeNode *parse_type(bool p_allow_void = false);
#ifdef TOOLS_ENABLED
- int class_doc_line = 0x7FFFFFFF;
+ int max_script_doc_line = INT_MAX;
+ int min_member_doc_line = 1;
bool has_comment(int p_line, bool p_must_be_doc = false);
MemberDocData parse_doc_comment(int p_line, bool p_single_line = false);
- ClassDocData parse_class_doc_comment(int p_line, bool p_inner_class, bool p_single_line = false);
+ ClassDocData parse_class_doc_comment(int p_line, bool p_single_line = false);
#endif // TOOLS_ENABLED
public:
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index 42b983ef45..07f2b8b406 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -857,10 +857,14 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
STRING_NODEPATH,
};
+ bool is_raw = false;
bool is_multiline = false;
StringType type = STRING_REGULAR;
- if (_peek(-1) == '&') {
+ if (_peek(-1) == 'r') {
+ is_raw = true;
+ _advance();
+ } else if (_peek(-1) == '&') {
type = STRING_NAME;
_advance();
} else if (_peek(-1) == '^') {
@@ -890,7 +894,12 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
char32_t ch = _peek();
if (ch == 0x200E || ch == 0x200F || (ch >= 0x202A && ch <= 0x202E) || (ch >= 0x2066 && ch <= 0x2069)) {
- Token error = make_error("Invisible text direction control character present in the string, escape it (\"\\u" + String::num_int64(ch, 16) + "\") to avoid confusion.");
+ Token error;
+ if (is_raw) {
+ error = make_error("Invisible text direction control character present in the string, use regular string literal instead of r-string.");
+ } else {
+ error = make_error("Invisible text direction control character present in the string, escape it (\"\\u" + String::num_int64(ch, 16) + "\") to avoid confusion.");
+ }
error.start_column = column;
error.leftmost_column = error.start_column;
error.end_column = column + 1;
@@ -905,144 +914,164 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
return make_error("Unterminated string.");
}
- // Grab escape character.
- char32_t code = _peek();
- _advance();
- if (_is_at_end()) {
- return make_error("Unterminated string.");
- }
+ if (is_raw) {
+ if (_peek() == quote_char) {
+ _advance();
+ if (_is_at_end()) {
+ return make_error("Unterminated string.");
+ }
+ result += '\\';
+ result += quote_char;
+ } else if (_peek() == '\\') { // For `\\\"`.
+ _advance();
+ if (_is_at_end()) {
+ return make_error("Unterminated string.");
+ }
+ result += '\\';
+ result += '\\';
+ } else {
+ result += '\\';
+ }
+ } else {
+ // Grab escape character.
+ char32_t code = _peek();
+ _advance();
+ if (_is_at_end()) {
+ return make_error("Unterminated string.");
+ }
- char32_t escaped = 0;
- bool valid_escape = true;
+ char32_t escaped = 0;
+ bool valid_escape = true;
- switch (code) {
- case 'a':
- escaped = '\a';
- break;
- case 'b':
- escaped = '\b';
- break;
- case 'f':
- escaped = '\f';
- break;
- case 'n':
- escaped = '\n';
- break;
- case 'r':
- escaped = '\r';
- break;
- case 't':
- escaped = '\t';
- break;
- case 'v':
- escaped = '\v';
- break;
- case '\'':
- escaped = '\'';
- break;
- case '\"':
- escaped = '\"';
- break;
- case '\\':
- escaped = '\\';
- break;
- case 'U':
- case 'u': {
- // Hexadecimal sequence.
- int hex_len = (code == 'U') ? 6 : 4;
- for (int j = 0; j < hex_len; j++) {
- if (_is_at_end()) {
- return make_error("Unterminated string.");
+ switch (code) {
+ case 'a':
+ escaped = '\a';
+ break;
+ case 'b':
+ escaped = '\b';
+ break;
+ case 'f':
+ escaped = '\f';
+ break;
+ case 'n':
+ escaped = '\n';
+ break;
+ case 'r':
+ escaped = '\r';
+ break;
+ case 't':
+ escaped = '\t';
+ break;
+ case 'v':
+ escaped = '\v';
+ break;
+ case '\'':
+ escaped = '\'';
+ break;
+ case '\"':
+ escaped = '\"';
+ break;
+ case '\\':
+ escaped = '\\';
+ break;
+ case 'U':
+ case 'u': {
+ // Hexadecimal sequence.
+ int hex_len = (code == 'U') ? 6 : 4;
+ for (int j = 0; j < hex_len; j++) {
+ if (_is_at_end()) {
+ return make_error("Unterminated string.");
+ }
+
+ char32_t digit = _peek();
+ char32_t value = 0;
+ if (is_digit(digit)) {
+ value = digit - '0';
+ } else if (digit >= 'a' && digit <= 'f') {
+ value = digit - 'a';
+ value += 10;
+ } else if (digit >= 'A' && digit <= 'F') {
+ value = digit - 'A';
+ value += 10;
+ } else {
+ // Make error, but keep parsing the string.
+ Token error = make_error("Invalid hexadecimal digit in unicode escape sequence.");
+ error.start_column = column;
+ error.leftmost_column = error.start_column;
+ error.end_column = column + 1;
+ error.rightmost_column = error.end_column;
+ push_error(error);
+ valid_escape = false;
+ break;
+ }
+
+ escaped <<= 4;
+ escaped |= value;
+
+ _advance();
}
-
- char32_t digit = _peek();
- char32_t value = 0;
- if (is_digit(digit)) {
- value = digit - '0';
- } else if (digit >= 'a' && digit <= 'f') {
- value = digit - 'a';
- value += 10;
- } else if (digit >= 'A' && digit <= 'F') {
- value = digit - 'A';
- value += 10;
- } else {
- // Make error, but keep parsing the string.
- Token error = make_error("Invalid hexadecimal digit in unicode escape sequence.");
- error.start_column = column;
- error.leftmost_column = error.start_column;
- error.end_column = column + 1;
- error.rightmost_column = error.end_column;
- push_error(error);
- valid_escape = false;
+ } break;
+ case '\r':
+ if (_peek() != '\n') {
+ // Carriage return without newline in string. (???)
+ // Just add it to the string and keep going.
+ result += ch;
+ _advance();
break;
}
-
- escaped <<= 4;
- escaped |= value;
-
- _advance();
- }
- } break;
- case '\r':
- if (_peek() != '\n') {
- // Carriage return without newline in string. (???)
- // Just add it to the string and keep going.
- result += ch;
- _advance();
+ [[fallthrough]];
+ case '\n':
+ // Escaping newline.
+ newline(false);
+ valid_escape = false; // Don't add to the string.
break;
- }
- [[fallthrough]];
- case '\n':
- // Escaping newline.
- newline(false);
- valid_escape = false; // Don't add to the string.
- break;
- default:
- Token error = make_error("Invalid escape in string.");
- error.start_column = column - 2;
- error.leftmost_column = error.start_column;
- push_error(error);
- valid_escape = false;
- break;
- }
- // Parse UTF-16 pair.
- if (valid_escape) {
- if ((escaped & 0xfffffc00) == 0xd800) {
- if (prev == 0) {
- prev = escaped;
- prev_pos = column - 2;
- continue;
- } else {
- Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
+ default:
+ Token error = make_error("Invalid escape in string.");
error.start_column = column - 2;
error.leftmost_column = error.start_column;
push_error(error);
valid_escape = false;
- prev = 0;
+ break;
+ }
+ // Parse UTF-16 pair.
+ if (valid_escape) {
+ if ((escaped & 0xfffffc00) == 0xd800) {
+ if (prev == 0) {
+ prev = escaped;
+ prev_pos = column - 2;
+ continue;
+ } else {
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate.");
+ error.start_column = column - 2;
+ error.leftmost_column = error.start_column;
+ push_error(error);
+ valid_escape = false;
+ prev = 0;
+ }
+ } else if ((escaped & 0xfffffc00) == 0xdc00) {
+ if (prev == 0) {
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired trail surrogate.");
+ error.start_column = column - 2;
+ error.leftmost_column = error.start_column;
+ push_error(error);
+ valid_escape = false;
+ } else {
+ escaped = (prev << 10UL) + escaped - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
+ prev = 0;
+ }
}
- } else if ((escaped & 0xfffffc00) == 0xdc00) {
- if (prev == 0) {
- Token error = make_error("Invalid UTF-16 sequence in string, unpaired trail surrogate");
- error.start_column = column - 2;
+ if (prev != 0) {
+ Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate.");
+ error.start_column = prev_pos;
error.leftmost_column = error.start_column;
push_error(error);
- valid_escape = false;
- } else {
- escaped = (prev << 10UL) + escaped - ((0xd800 << 10UL) + 0xdc00 - 0x10000);
prev = 0;
}
}
- if (prev != 0) {
- Token error = make_error("Invalid UTF-16 sequence in string, unpaired lead surrogate");
- error.start_column = prev_pos;
- error.leftmost_column = error.start_column;
- push_error(error);
- prev = 0;
- }
- }
- if (valid_escape) {
- result += escaped;
+ if (valid_escape) {
+ result += escaped;
+ }
}
} else if (ch == quote_char) {
if (prev != 0) {
@@ -1216,7 +1245,7 @@ void GDScriptTokenizer::check_indent() {
if (line_continuation || multiline_mode) {
// We cleared up all the whitespace at the beginning of the line.
- // But if this is a continuation or multiline mode and we don't want any indentation change.
+ // If this is a line continuation or we're in multiline mode then we don't want any indentation changes.
return;
}
@@ -1416,6 +1445,9 @@ GDScriptTokenizer::Token GDScriptTokenizer::scan() {
if (is_digit(c)) {
return number();
+ } else if (c == 'r' && (_peek() == '"' || _peek() == '\'')) {
+ // Raw string literals.
+ return string();
} else if (is_unicode_identifier_start(c)) {
return potential_identifier();
}
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 068393cee9..f916407b18 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -187,6 +187,8 @@ public:
#ifdef TOOLS_ENABLED
struct CommentData {
String comment;
+ // true: Comment starts at beginning of line or after indentation.
+ // false: Inline comment (starts after some code).
bool new_line = false;
CommentData() {}
CommentData(const String &p_comment, bool p_new_line) {
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index 030950267d..39cf9d79c8 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -85,6 +85,7 @@
#endif
struct GDScriptUtilityFunctionsDefinitions {
+#ifndef DISABLE_DEPRECATED
static inline void convert(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
VALIDATE_ARG_COUNT(2);
VALIDATE_ARG_INT(1);
@@ -100,6 +101,7 @@ struct GDScriptUtilityFunctionsDefinitions {
Variant::construct(Variant::Type(type), *r_ret, p_args, 1, r_error);
}
}
+#endif // DISABLE_DEPRECATED
static inline void type_exists(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
VALIDATE_ARG_COUNT(1);
@@ -277,7 +279,7 @@ struct GDScriptUtilityFunctionsDefinitions {
Vector<StringName> sname;
while (p->_owner) {
- sname.push_back(p->name);
+ sname.push_back(p->local_name);
p = p->_owner;
}
sname.reverse();
@@ -703,7 +705,9 @@ static void _register_function(const String &p_name, const MethodInfo &p_method_
PropertyInfo(Variant::NIL, m_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT)
void GDScriptUtilityFunctions::register_functions() {
+#ifndef DISABLE_DEPRECATED
REGISTER_VARIANT_FUNC(convert, true, VARARG("what"), ARG("type", Variant::INT));
+#endif // DISABLE_DEPRECATED
REGISTER_FUNC(type_exists, true, Variant::BOOL, ARG("type", Variant::STRING_NAME));
REGISTER_FUNC(_char, true, Variant::STRING, ARG("char", Variant::INT));
REGISTER_VARARG_FUNC(range, false, Variant::ARRAY);
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 1ddd54b323..c0644e089c 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -116,6 +116,7 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_ARGUMENT) {
int errorarg = p_err.argument;
+ ERR_FAIL_COND_V_MSG(errorarg < 0 || argptrs[errorarg] == nullptr, "GDScript bug (please report): Invalid CallError argument index or null pointer.", "Invalid CallError argument index or null pointer.");
// Handle the Object to Object case separately as we don't have further class details.
#ifdef DEBUG_ENABLED
if (p_err.expected == Variant::OBJECT && argptrs[errorarg]->get_type() == p_err.expected) {
@@ -128,9 +129,9 @@ String GDScriptFunction::_get_call_error(const Callable::CallError &p_err, const
err_text = "Invalid type in " + p_where + ". Cannot convert argument " + itos(errorarg + 1) + " from " + Variant::get_type_name(argptrs[errorarg]->get_type()) + " to " + Variant::get_type_name(Variant::Type(p_err.expected)) + ".";
}
} else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS) {
- err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
+ err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.expected) + " arguments.";
} else if (p_err.error == Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS) {
- err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.argument) + " arguments.";
+ err_text = "Invalid call to " + p_where + ". Expected " + itos(p_err.expected) + " arguments.";
} else if (p_err.error == Callable::CallError::CALL_ERROR_INVALID_METHOD) {
err_text = "Invalid call. Nonexistent " + p_where + ".";
} else if (p_err.error == Callable::CallError::CALL_ERROR_INSTANCE_IS_NULL) {
@@ -466,8 +467,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
err_file = "<built-in>";
}
String err_func = name;
- if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && !p_instance->script->name.is_empty()) {
- err_func = p_instance->script->name + "." + err_func;
+ if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->local_name != StringName()) {
+ err_func = p_instance->script->local_name.operator String() + "." + err_func;
}
int err_line = _initial_line;
const char *err_text = "Stack overflow. Check for infinite recursion in your script.";
@@ -511,13 +512,13 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (p_argcount != _argument_count) {
if (p_argcount > _argument_count) {
r_err.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS;
- r_err.argument = _argument_count;
+ r_err.expected = _argument_count;
call_depth--;
return _get_default_variant_for_data_type(return_type);
} else if (p_argcount < _argument_count - _default_arg_count) {
r_err.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
- r_err.argument = _argument_count - _default_arg_count;
+ r_err.expected = _argument_count - _default_arg_count;
call_depth--;
return _get_default_variant_for_data_type(return_type);
} else {
@@ -3649,8 +3650,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
err_file = "<built-in>";
}
String err_func = name;
- if (instance_valid_with_script && !p_instance->script->name.is_empty()) {
- err_func = p_instance->script->name + "." + err_func;
+ if (instance_valid_with_script && p_instance->script->local_name != StringName()) {
+ err_func = p_instance->script->local_name.operator String() + "." + err_func;
}
int err_line = line;
if (err_text.is_empty()) {
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 4fec445995..ef2913926c 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -88,6 +88,12 @@ String GDScriptWarning::get_message() const {
case FUNCTION_USED_AS_PROPERTY:
CHECK_SYMBOLS(2);
return vformat(R"(The property "%s" was not found in base "%s" but there's a method with the same name. Did you mean to call it?)", symbols[0], symbols[1]);
+ case UNTYPED_DECLARATION:
+ CHECK_SYMBOLS(2);
+ if (symbols[0] == "Function") {
+ return vformat(R"*(%s "%s()" has no static return type.)*", symbols[0], symbols[1]);
+ }
+ return vformat(R"(%s "%s" has no static type.)", symbols[0], symbols[1]);
case UNSAFE_PROPERTY_ACCESS:
CHECK_SYMBOLS(2);
return vformat(R"(The property "%s" is not present on the inferred type "%s" (but may be present on a subtype).)", symbols[0], symbols[1]);
@@ -113,14 +119,6 @@ String GDScriptWarning::get_message() const {
return R"(The "@static_unload" annotation is redundant because the file does not have a class with static variables.)";
case REDUNDANT_AWAIT:
return R"("await" keyword not needed in this case, because the expression isn't a coroutine nor a signal.)";
- case REDUNDANT_FOR_VARIABLE_TYPE:
- CHECK_SYMBOLS(3);
- if (symbols[1] == symbols[2]) {
- return vformat(R"(The for loop iterator "%s" already has inferred type "%s", the specified type is redundant.)", symbols[0], symbols[1]);
- } else {
- return vformat(R"(The for loop iterator "%s" has inferred type "%s" but its supertype "%s" is specified.)", symbols[0], symbols[1], symbols[2]);
- }
- break;
case ASSERT_ALWAYS_TRUE:
return "Assert statement is redundant because the expression is always true.";
case ASSERT_ALWAYS_FALSE:
@@ -208,6 +206,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"PROPERTY_USED_AS_FUNCTION",
"CONSTANT_USED_AS_FUNCTION",
"FUNCTION_USED_AS_PROPERTY",
+ "UNTYPED_DECLARATION",
"UNSAFE_PROPERTY_ACCESS",
"UNSAFE_METHOD_ACCESS",
"UNSAFE_CAST",
@@ -217,7 +216,6 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"STATIC_CALLED_ON_INSTANCE",
"REDUNDANT_STATIC_UNLOAD",
"REDUNDANT_AWAIT",
- "REDUNDANT_FOR_VARIABLE_TYPE",
"ASSERT_ALWAYS_TRUE",
"ASSERT_ALWAYS_FALSE",
"INTEGER_DIVISION",
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 73e12eb20e..2b17709338 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -64,6 +64,7 @@ public:
PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name.
CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name.
FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name.
+ UNTYPED_DECLARATION, // Variable/parameter/function has no static type, explicitly specified or inferred (`:=`).
UNSAFE_PROPERTY_ACCESS, // Property not found in the detected type (but can be in subtypes).
UNSAFE_METHOD_ACCESS, // Function not found in the detected type (but can be in subtypes).
UNSAFE_CAST, // Cast used in an unknown type.
@@ -73,7 +74,6 @@ public:
STATIC_CALLED_ON_INSTANCE, // A static method was called on an instance of a class instead of on the class itself.
REDUNDANT_STATIC_UNLOAD, // The `@static_unload` annotation is used but the class does not have static data.
REDUNDANT_AWAIT, // await is used but expression is synchronous (not a signal nor a coroutine).
- REDUNDANT_FOR_VARIABLE_TYPE, // The for variable type specifier is a supertype of the inferred type.
ASSERT_ALWAYS_TRUE, // Expression for assert argument is always true.
ASSERT_ALWAYS_FALSE, // Expression for assert argument is always false.
INTEGER_DIVISION, // Integer divide by integer, decimal part is discarded.
@@ -112,6 +112,7 @@ public:
WARN, // PROPERTY_USED_AS_FUNCTION
WARN, // CONSTANT_USED_AS_FUNCTION
WARN, // FUNCTION_USED_AS_PROPERTY
+ IGNORE, // UNTYPED_DECLARATION // Static typing is optional, we don't want to spam warnings.
IGNORE, // UNSAFE_PROPERTY_ACCESS // Too common in untyped scenarios.
IGNORE, // UNSAFE_METHOD_ACCESS // Too common in untyped scenarios.
IGNORE, // UNSAFE_CAST // Too common in untyped scenarios.
@@ -121,7 +122,6 @@ public:
WARN, // STATIC_CALLED_ON_INSTANCE
WARN, // REDUNDANT_STATIC_UNLOAD
WARN, // REDUNDANT_AWAIT
- WARN, // REDUNDANT_FOR_VARIABLE_TYPE
WARN, // ASSERT_ALWAYS_TRUE
WARN, // ASSERT_ALWAYS_FALSE
WARN, // INTEGER_DIVISION
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index 3a5a54e275..36806d2f73 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -32,9 +32,94 @@
#include "../gdscript.h"
#include "../gdscript_analyzer.h"
+#include "editor/editor_settings.h"
#include "gdscript_language_protocol.h"
#include "gdscript_workspace.h"
+int get_indent_size() {
+ if (EditorSettings::get_singleton()) {
+ return EditorSettings::get_singleton()->get_setting("text_editor/behavior/indent/size");
+ } else {
+ return 4;
+ }
+}
+
+lsp::Position GodotPosition::to_lsp(const Vector<String> &p_lines) const {
+ lsp::Position res;
+
+ // Special case: `line = 0` -> root class (range covers everything).
+ if (this->line <= 0) {
+ return res;
+ }
+ // Special case: `line = p_lines.size() + 1` -> root class (range covers everything).
+ if (this->line >= p_lines.size() + 1) {
+ res.line = p_lines.size();
+ return res;
+ }
+ res.line = this->line - 1;
+ // Note: character outside of `pos_line.length()-1` is valid.
+ res.character = this->column - 1;
+
+ String pos_line = p_lines[res.line];
+ if (pos_line.contains("\t")) {
+ int tab_size = get_indent_size();
+
+ int in_col = 1;
+ int res_char = 0;
+
+ while (res_char < pos_line.size() && in_col < this->column) {
+ if (pos_line[res_char] == '\t') {
+ in_col += tab_size;
+ res_char++;
+ } else {
+ in_col++;
+ res_char++;
+ }
+ }
+
+ res.character = res_char;
+ }
+
+ return res;
+}
+
+GodotPosition GodotPosition::from_lsp(const lsp::Position p_pos, const Vector<String> &p_lines) {
+ GodotPosition res(p_pos.line + 1, p_pos.character + 1);
+
+ // Line outside of actual text is valid (-> pos/cursor at end of text).
+ if (res.line > p_lines.size()) {
+ return res;
+ }
+
+ String line = p_lines[p_pos.line];
+ int tabs_before_char = 0;
+ for (int i = 0; i < p_pos.character && i < line.length(); i++) {
+ if (line[i] == '\t') {
+ tabs_before_char++;
+ }
+ }
+
+ if (tabs_before_char > 0) {
+ int tab_size = get_indent_size();
+ res.column += tabs_before_char * (tab_size - 1);
+ }
+
+ return res;
+}
+
+lsp::Range GodotRange::to_lsp(const Vector<String> &p_lines) const {
+ lsp::Range res;
+ res.start = start.to_lsp(p_lines);
+ res.end = end.to_lsp(p_lines);
+ return res;
+}
+
+GodotRange GodotRange::from_lsp(const lsp::Range &p_range, const Vector<String> &p_lines) {
+ GodotPosition start = GodotPosition::from_lsp(p_range.start, p_lines);
+ GodotPosition end = GodotPosition::from_lsp(p_range.end, p_lines);
+ return GodotRange(start, end);
+}
+
void ExtendGDScriptParser::update_diagnostics() {
diagnostics.clear();
@@ -90,7 +175,7 @@ void ExtendGDScriptParser::update_symbols() {
const lsp::DocumentSymbol &symbol = class_symbol.children[i];
members.insert(symbol.name, &symbol);
- // cache level one inner classes
+ // Cache level one inner classes.
if (symbol.kind == lsp::SymbolKind::Class) {
ClassMembers inner_class;
for (int j = 0; j < symbol.children.size(); j++) {
@@ -126,10 +211,7 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) {
String value = const_val;
lsp::DocumentLink link;
link.target = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(scr_path);
- link.range.start.line = LINE_NUMBER_TO_INDEX(token.start_line);
- link.range.end.line = LINE_NUMBER_TO_INDEX(token.end_line);
- link.range.start.character = LINE_NUMBER_TO_INDEX(token.start_column);
- link.range.end.character = LINE_NUMBER_TO_INDEX(token.end_column);
+ link.range = GodotRange(GodotPosition(token.start_line, token.start_column), GodotPosition(token.end_line, token.end_column)).to_lsp(this->lines);
document_links.push_back(link);
}
}
@@ -137,6 +219,12 @@ void ExtendGDScriptParser::update_document_links(const String &p_code) {
}
}
+lsp::Range ExtendGDScriptParser::range_of_node(const GDScriptParser::Node *p_node) const {
+ GodotPosition start(p_node->start_line, p_node->start_column);
+ GodotPosition end(p_node->end_line, p_node->end_column);
+ return GodotRange(start, end).to_lsp(this->lines);
+}
+
void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p_class, lsp::DocumentSymbol &r_symbol) {
const String uri = get_uri();
@@ -149,13 +237,30 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
}
r_symbol.kind = lsp::SymbolKind::Class;
r_symbol.deprecated = false;
- r_symbol.range.start.line = p_class->start_line;
- r_symbol.range.start.character = p_class->start_column;
- r_symbol.range.end.line = lines.size();
- r_symbol.selectionRange.start.line = r_symbol.range.start.line;
+ r_symbol.range = range_of_node(p_class);
+ r_symbol.range.start.line = MAX(r_symbol.range.start.line, 0);
+ if (p_class->identifier) {
+ r_symbol.selectionRange = range_of_node(p_class->identifier);
+ }
r_symbol.detail = "class " + r_symbol.name;
- bool is_root_class = &r_symbol == &class_symbol;
- r_symbol.documentation = parse_documentation(is_root_class ? 0 : LINE_NUMBER_TO_INDEX(p_class->start_line), is_root_class);
+ {
+ String doc = p_class->doc_data.description;
+ if (!p_class->doc_data.description.is_empty()) {
+ doc += "\n\n" + p_class->doc_data.description;
+ }
+
+ if (!p_class->doc_data.tutorials.is_empty()) {
+ doc += "\n";
+ for (const Pair<String, String> &tutorial : p_class->doc_data.tutorials) {
+ if (tutorial.first.is_empty()) {
+ doc += vformat("\n@tutorial: %s", tutorial.second);
+ } else {
+ doc += vformat("\n@tutorial(%s): %s", tutorial.first, tutorial.second);
+ }
+ }
+ }
+ r_symbol.documentation = doc;
+ }
for (int i = 0; i < p_class->members.size(); i++) {
const ClassNode::Member &m = p_class->members[i];
@@ -166,11 +271,8 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.name = m.variable->identifier->name;
symbol.kind = m.variable->property == VariableNode::PROP_NONE ? lsp::SymbolKind::Variable : lsp::SymbolKind::Property;
symbol.deprecated = false;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.variable->start_line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.variable->start_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.variable->end_line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.variable->end_column);
- symbol.selectionRange.start.line = symbol.range.start.line;
+ symbol.range = range_of_node(m.variable);
+ symbol.selectionRange = range_of_node(m.variable->identifier);
if (m.variable->exported) {
symbol.detail += "@export ";
}
@@ -182,10 +284,31 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.detail += " = " + m.variable->initializer->reduced_value.to_json_string();
}
- symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.variable->start_line));
+ symbol.documentation = m.variable->doc_data.description;
symbol.uri = uri;
symbol.script_path = path;
+ if (m.variable->initializer && m.variable->initializer->type == GDScriptParser::Node::LAMBDA) {
+ GDScriptParser::LambdaNode *lambda_node = (GDScriptParser::LambdaNode *)m.variable->initializer;
+ lsp::DocumentSymbol lambda;
+ parse_function_symbol(lambda_node->function, lambda);
+ // Merge lambda into current variable.
+ symbol.children.append_array(lambda.children);
+ }
+
+ if (m.variable->getter && m.variable->getter->type == GDScriptParser::Node::FUNCTION) {
+ lsp::DocumentSymbol get_symbol;
+ parse_function_symbol(m.variable->getter, get_symbol);
+ get_symbol.local = true;
+ symbol.children.push_back(get_symbol);
+ }
+ if (m.variable->setter && m.variable->setter->type == GDScriptParser::Node::FUNCTION) {
+ lsp::DocumentSymbol set_symbol;
+ parse_function_symbol(m.variable->setter, set_symbol);
+ set_symbol.local = true;
+ symbol.children.push_back(set_symbol);
+ }
+
r_symbol.children.push_back(symbol);
} break;
case ClassNode::Member::CONSTANT: {
@@ -194,12 +317,9 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.name = m.constant->identifier->name;
symbol.kind = lsp::SymbolKind::Constant;
symbol.deprecated = false;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.constant->start_line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.constant->start_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.constant->end_line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.constant->start_column);
- symbol.selectionRange.start.line = LINE_NUMBER_TO_INDEX(m.constant->start_line);
- symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.constant->start_line));
+ symbol.range = range_of_node(m.constant);
+ symbol.selectionRange = range_of_node(m.constant->identifier);
+ symbol.documentation = m.constant->doc_data.description;
symbol.uri = uri;
symbol.script_path = path;
@@ -231,36 +351,14 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
r_symbol.children.push_back(symbol);
} break;
- case ClassNode::Member::ENUM_VALUE: {
- lsp::DocumentSymbol symbol;
-
- symbol.name = m.enum_value.identifier->name;
- symbol.kind = lsp::SymbolKind::EnumMember;
- symbol.deprecated = false;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.enum_value.line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.enum_value.leftmost_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.enum_value.line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.enum_value.rightmost_column);
- symbol.selectionRange.start.line = LINE_NUMBER_TO_INDEX(m.enum_value.line);
- symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.enum_value.line));
- symbol.uri = uri;
- symbol.script_path = path;
-
- symbol.detail = symbol.name + " = " + itos(m.enum_value.value);
-
- r_symbol.children.push_back(symbol);
- } break;
case ClassNode::Member::SIGNAL: {
lsp::DocumentSymbol symbol;
symbol.name = m.signal->identifier->name;
symbol.kind = lsp::SymbolKind::Event;
symbol.deprecated = false;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.signal->start_line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.signal->start_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.signal->end_line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.signal->end_column);
- symbol.selectionRange.start.line = symbol.range.start.line;
- symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.signal->start_line));
+ symbol.range = range_of_node(m.signal);
+ symbol.selectionRange = range_of_node(m.signal->identifier);
+ symbol.documentation = m.signal->doc_data.description;
symbol.uri = uri;
symbol.script_path = path;
symbol.detail = "signal " + String(m.signal->identifier->name) + "(";
@@ -272,17 +370,48 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
}
symbol.detail += ")";
+ for (GDScriptParser::ParameterNode *param : m.signal->parameters) {
+ lsp::DocumentSymbol param_symbol;
+ param_symbol.name = param->identifier->name;
+ param_symbol.kind = lsp::SymbolKind::Variable;
+ param_symbol.deprecated = false;
+ param_symbol.local = true;
+ param_symbol.range = range_of_node(param);
+ param_symbol.selectionRange = range_of_node(param->identifier);
+ param_symbol.uri = uri;
+ param_symbol.script_path = path;
+ param_symbol.detail = "var " + param_symbol.name;
+ if (param->get_datatype().is_hard_type()) {
+ param_symbol.detail += ": " + param->get_datatype().to_string();
+ }
+ symbol.children.push_back(param_symbol);
+ }
+ r_symbol.children.push_back(symbol);
+ } break;
+ case ClassNode::Member::ENUM_VALUE: {
+ lsp::DocumentSymbol symbol;
+
+ symbol.name = m.enum_value.identifier->name;
+ symbol.kind = lsp::SymbolKind::EnumMember;
+ symbol.deprecated = false;
+ symbol.range.start = GodotPosition(m.enum_value.line, m.enum_value.leftmost_column).to_lsp(this->lines);
+ symbol.range.end = GodotPosition(m.enum_value.line, m.enum_value.rightmost_column).to_lsp(this->lines);
+ symbol.selectionRange = range_of_node(m.enum_value.identifier);
+ symbol.documentation = m.enum_value.doc_data.description;
+ symbol.uri = uri;
+ symbol.script_path = path;
+
+ symbol.detail = symbol.name + " = " + itos(m.enum_value.value);
+
r_symbol.children.push_back(symbol);
} break;
case ClassNode::Member::ENUM: {
lsp::DocumentSymbol symbol;
+ symbol.name = m.m_enum->identifier->name;
symbol.kind = lsp::SymbolKind::Enum;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(m.m_enum->start_line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(m.m_enum->start_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(m.m_enum->end_line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(m.m_enum->end_column);
- symbol.selectionRange.start.line = symbol.range.start.line;
- symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(m.m_enum->start_line));
+ symbol.range = range_of_node(m.m_enum);
+ symbol.selectionRange = range_of_node(m.m_enum->identifier);
+ symbol.documentation = m.m_enum->doc_data.description;
symbol.uri = uri;
symbol.script_path = path;
@@ -294,6 +423,25 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
symbol.detail += String(m.m_enum->values[j].identifier->name) + " = " + itos(m.m_enum->values[j].value);
}
symbol.detail += "}";
+
+ for (GDScriptParser::EnumNode::Value value : m.m_enum->values) {
+ lsp::DocumentSymbol child;
+
+ child.name = value.identifier->name;
+ child.kind = lsp::SymbolKind::EnumMember;
+ child.deprecated = false;
+ child.range.start = GodotPosition(value.line, value.leftmost_column).to_lsp(this->lines);
+ child.range.end = GodotPosition(value.line, value.rightmost_column).to_lsp(this->lines);
+ child.selectionRange = range_of_node(value.identifier);
+ child.documentation = value.doc_data.description;
+ child.uri = uri;
+ child.script_path = path;
+
+ child.detail = child.name + " = " + itos(value.value);
+
+ symbol.children.push_back(child);
+ }
+
r_symbol.children.push_back(symbol);
} break;
case ClassNode::Member::FUNCTION: {
@@ -317,32 +465,29 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionNode *p_func, lsp::DocumentSymbol &r_symbol) {
const String uri = get_uri();
- r_symbol.name = p_func->identifier->name;
- r_symbol.kind = p_func->is_static ? lsp::SymbolKind::Function : lsp::SymbolKind::Method;
- r_symbol.detail = "func " + String(p_func->identifier->name) + "(";
+ bool is_named = p_func->identifier != nullptr;
+
+ r_symbol.name = is_named ? p_func->identifier->name : "";
+ r_symbol.kind = (p_func->is_static || p_func->source_lambda != nullptr) ? lsp::SymbolKind::Function : lsp::SymbolKind::Method;
+ r_symbol.detail = "func";
+ if (is_named) {
+ r_symbol.detail += " " + String(p_func->identifier->name);
+ }
+ r_symbol.detail += "(";
r_symbol.deprecated = false;
- r_symbol.range.start.line = LINE_NUMBER_TO_INDEX(p_func->start_line);
- r_symbol.range.start.character = LINE_NUMBER_TO_INDEX(p_func->start_column);
- r_symbol.range.end.line = LINE_NUMBER_TO_INDEX(p_func->start_line);
- r_symbol.range.end.character = LINE_NUMBER_TO_INDEX(p_func->end_column);
- r_symbol.selectionRange.start.line = r_symbol.range.start.line;
- r_symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(p_func->start_line));
+ r_symbol.range = range_of_node(p_func);
+ if (is_named) {
+ r_symbol.selectionRange = range_of_node(p_func->identifier);
+ } else {
+ r_symbol.selectionRange.start = r_symbol.selectionRange.end = r_symbol.range.start;
+ }
+ r_symbol.documentation = p_func->doc_data.description;
r_symbol.uri = uri;
r_symbol.script_path = path;
String parameters;
for (int i = 0; i < p_func->parameters.size(); i++) {
const ParameterNode *parameter = p_func->parameters[i];
- lsp::DocumentSymbol symbol;
- symbol.kind = lsp::SymbolKind::Variable;
- symbol.name = parameter->identifier->name;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(parameter->start_line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(parameter->start_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(parameter->end_line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(parameter->end_column);
- symbol.uri = uri;
- symbol.script_path = path;
- r_symbol.children.push_back(symbol);
if (i > 0) {
parameters += ", ";
}
@@ -387,6 +532,13 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
node_stack.push_back(while_node->loop);
} break;
+ case GDScriptParser::TypeNode::MATCH: {
+ GDScriptParser::MatchNode *match_node = (GDScriptParser::MatchNode *)node;
+ for (GDScriptParser::MatchBranchNode *branch_node : match_node->branches) {
+ node_stack.push_back(branch_node);
+ }
+ } break;
+
case GDScriptParser::TypeNode::MATCH_BRANCH: {
GDScriptParser::MatchBranchNode *match_node = (GDScriptParser::MatchBranchNode *)node;
node_stack.push_back(match_node->block);
@@ -400,20 +552,6 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
}
} break;
- case GDScriptParser::TypeNode::VARIABLE: {
- GDScriptParser::VariableNode *variable_node = (GDScriptParser::VariableNode *)(node);
- lsp::DocumentSymbol symbol;
- symbol.kind = lsp::SymbolKind::Variable;
- symbol.name = variable_node->identifier->name;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(variable_node->start_line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(variable_node->start_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(variable_node->end_line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(variable_node->end_column);
- symbol.uri = uri;
- symbol.script_path = path;
- r_symbol.children.push_back(symbol);
- } break;
-
default:
continue;
}
@@ -426,10 +564,40 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
lsp::DocumentSymbol symbol;
symbol.name = local.name;
symbol.kind = local.type == SuiteNode::Local::CONSTANT ? lsp::SymbolKind::Constant : lsp::SymbolKind::Variable;
- symbol.range.start.line = LINE_NUMBER_TO_INDEX(local.start_line);
- symbol.range.start.character = LINE_NUMBER_TO_INDEX(local.start_column);
- symbol.range.end.line = LINE_NUMBER_TO_INDEX(local.end_line);
- symbol.range.end.character = LINE_NUMBER_TO_INDEX(local.end_column);
+ switch (local.type) {
+ case SuiteNode::Local::CONSTANT:
+ symbol.range = range_of_node(local.constant);
+ symbol.selectionRange = range_of_node(local.constant->identifier);
+ break;
+ case SuiteNode::Local::VARIABLE:
+ symbol.range = range_of_node(local.variable);
+ symbol.selectionRange = range_of_node(local.variable->identifier);
+ if (local.variable->initializer && local.variable->initializer->type == GDScriptParser::Node::LAMBDA) {
+ GDScriptParser::LambdaNode *lambda_node = (GDScriptParser::LambdaNode *)local.variable->initializer;
+ lsp::DocumentSymbol lambda;
+ parse_function_symbol(lambda_node->function, lambda);
+ // Merge lambda into current variable.
+ // -> Only interested in new variables, not lambda itself.
+ symbol.children.append_array(lambda.children);
+ }
+ break;
+ case SuiteNode::Local::PARAMETER:
+ symbol.range = range_of_node(local.parameter);
+ symbol.selectionRange = range_of_node(local.parameter->identifier);
+ break;
+ case SuiteNode::Local::FOR_VARIABLE:
+ case SuiteNode::Local::PATTERN_BIND:
+ symbol.range = range_of_node(local.bind);
+ symbol.selectionRange = range_of_node(local.bind);
+ break;
+ default:
+ // Fallback.
+ symbol.range.start = GodotPosition(local.start_line, local.start_column).to_lsp(get_lines());
+ symbol.range.end = GodotPosition(local.end_line, local.end_column).to_lsp(get_lines());
+ symbol.selectionRange = symbol.range;
+ break;
+ }
+ symbol.local = true;
symbol.uri = uri;
symbol.script_path = path;
symbol.detail = local.type == SuiteNode::Local::CONSTANT ? "const " : "var ";
@@ -437,53 +605,19 @@ void ExtendGDScriptParser::parse_function_symbol(const GDScriptParser::FunctionN
if (local.get_datatype().is_hard_type()) {
symbol.detail += ": " + local.get_datatype().to_string();
}
- symbol.documentation = parse_documentation(LINE_NUMBER_TO_INDEX(local.start_line));
- r_symbol.children.push_back(symbol);
- }
- }
-}
-
-String ExtendGDScriptParser::parse_documentation(int p_line, bool p_docs_down) {
- ERR_FAIL_INDEX_V(p_line, lines.size(), String());
-
- List<String> doc_lines;
-
- if (!p_docs_down) { // inline comment
- String inline_comment = lines[p_line];
- int comment_start = inline_comment.find("##");
- if (comment_start != -1) {
- inline_comment = inline_comment.substr(comment_start, inline_comment.length()).strip_edges();
- if (inline_comment.length() > 1) {
- doc_lines.push_back(inline_comment.substr(2, inline_comment.length()));
+ switch (local.type) {
+ case SuiteNode::Local::CONSTANT:
+ symbol.documentation = local.constant->doc_data.description;
+ break;
+ case SuiteNode::Local::VARIABLE:
+ symbol.documentation = local.variable->doc_data.description;
+ break;
+ default:
+ break;
}
+ r_symbol.children.push_back(symbol);
}
}
-
- int step = p_docs_down ? 1 : -1;
- int start_line = p_docs_down ? p_line : p_line - 1;
- for (int i = start_line; true; i += step) {
- if (i < 0 || i >= lines.size()) {
- break;
- }
-
- String line_comment = lines[i].strip_edges(true, false);
- if (line_comment.begins_with("##")) {
- line_comment = line_comment.substr(2, line_comment.length());
- if (p_docs_down) {
- doc_lines.push_back(line_comment);
- } else {
- doc_lines.push_front(line_comment);
- }
- } else {
- break;
- }
- }
-
- String doc;
- for (const String &E : doc_lines) {
- doc += E + "\n";
- }
- return doc;
}
String ExtendGDScriptParser::get_text_for_completion(const lsp::Position &p_cursor) const {
@@ -492,7 +626,7 @@ String ExtendGDScriptParser::get_text_for_completion(const lsp::Position &p_curs
for (int i = 0; i < len; i++) {
if (i == p_cursor.line) {
longthing += lines[i].substr(0, p_cursor.character);
- longthing += String::chr(0xFFFF); //not unicode, represents the cursor
+ longthing += String::chr(0xFFFF); // Not unicode, represents the cursor.
longthing += lines[i].substr(p_cursor.character, lines[i].size());
} else {
longthing += lines[i];
@@ -513,7 +647,7 @@ String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_c
if (i == p_cursor.line) {
String line = lines[i];
String first_part = line.substr(0, p_cursor.character);
- String last_part = line.substr(p_cursor.character + 1, lines[i].length());
+ String last_part = line.substr(p_cursor.character, lines[i].length());
if (!p_symbol.is_empty()) {
String left_cursor_text;
for (int c = p_cursor.character - 1; c >= 0; c--) {
@@ -527,9 +661,9 @@ String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_c
}
longthing += first_part;
- longthing += String::chr(0xFFFF); //not unicode, represents the cursor
+ longthing += String::chr(0xFFFF); // Not unicode, represents the cursor.
if (p_func_required) {
- longthing += "("; // tell the parser this is a function call
+ longthing += "("; // Tell the parser this is a function call.
}
longthing += last_part;
} else {
@@ -544,7 +678,7 @@ String ExtendGDScriptParser::get_text_for_lookup_symbol(const lsp::Position &p_c
return longthing;
}
-String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &p_position, Vector2i &p_offset) const {
+String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &p_position, lsp::Range &r_range) const {
ERR_FAIL_INDEX_V(p_position.line, lines.size(), "");
String line = lines[p_position.line];
if (line.is_empty()) {
@@ -552,8 +686,32 @@ String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &
}
ERR_FAIL_INDEX_V(p_position.character, line.size(), "");
- int start_pos = p_position.character;
- for (int c = p_position.character; c >= 0; c--) {
+ // `p_position` cursor is BETWEEN chars, not ON chars.
+ // ->
+ // ```gdscript
+ // var member| := some_func|(some_variable|)
+ // ^ ^ ^
+ // | | | cursor on `some_variable, position on `)`
+ // | |
+ // | | cursor on `some_func`, pos on `(`
+ // |
+ // | cursor on `member`, pos on ` ` (space)
+ // ```
+ // -> Move position to previous character if:
+ // * Position not on valid identifier char.
+ // * Prev position is valid identifier char.
+ lsp::Position pos = p_position;
+ if (
+ pos.character >= line.length() // Cursor at end of line.
+ || (!is_ascii_identifier_char(line[pos.character]) // Not on valid identifier char.
+ && (pos.character > 0 // Not line start -> there is a prev char.
+ && is_ascii_identifier_char(line[pos.character - 1]) // Prev is valid identifier char.
+ ))) {
+ pos.character--;
+ }
+
+ int start_pos = pos.character;
+ for (int c = pos.character; c >= 0; c--) {
start_pos = c;
char32_t ch = line[c];
bool valid_char = is_ascii_identifier_char(ch);
@@ -562,8 +720,8 @@ String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &
}
}
- int end_pos = p_position.character;
- for (int c = p_position.character; c < line.length(); c++) {
+ int end_pos = pos.character;
+ for (int c = pos.character; c < line.length(); c++) {
char32_t ch = line[c];
bool valid_char = is_ascii_identifier_char(ch);
if (!valid_char) {
@@ -571,9 +729,11 @@ String ExtendGDScriptParser::get_identifier_under_position(const lsp::Position &
}
end_pos = c;
}
+
if (start_pos < end_pos) {
- p_offset.x = start_pos - p_position.character;
- p_offset.y = end_pos - p_position.character;
+ r_range.start.line = r_range.end.line = pos.line;
+ r_range.start.character = start_pos + 1;
+ r_range.end.character = end_pos + 1;
return line.substr(start_pos + 1, end_pos - start_pos);
}
@@ -584,15 +744,15 @@ String ExtendGDScriptParser::get_uri() const {
return GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_uri(path);
}
-const lsp::DocumentSymbol *ExtendGDScriptParser::search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent) const {
+const lsp::DocumentSymbol *ExtendGDScriptParser::search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent, const String &p_symbol_name) const {
const lsp::DocumentSymbol *ret = nullptr;
if (p_line < p_parent.range.start.line) {
return ret;
- } else if (p_parent.range.start.line == p_line) {
+ } else if (p_parent.range.start.line == p_line && (p_symbol_name.is_empty() || p_parent.name == p_symbol_name)) {
return &p_parent;
} else {
for (int i = 0; i < p_parent.children.size(); i++) {
- ret = search_symbol_defined_at_line(p_line, p_parent.children[i]);
+ ret = search_symbol_defined_at_line(p_line, p_parent.children[i], p_symbol_name);
if (ret) {
break;
}
@@ -645,11 +805,11 @@ Error ExtendGDScriptParser::get_left_function_call(const lsp::Position &p_positi
return ERR_METHOD_NOT_FOUND;
}
-const lsp::DocumentSymbol *ExtendGDScriptParser::get_symbol_defined_at_line(int p_line) const {
+const lsp::DocumentSymbol *ExtendGDScriptParser::get_symbol_defined_at_line(int p_line, const String &p_symbol_name) const {
if (p_line <= 0) {
return &class_symbol;
}
- return search_symbol_defined_at_line(p_line, class_symbol);
+ return search_symbol_defined_at_line(p_line, class_symbol, p_symbol_name);
}
const lsp::DocumentSymbol *ExtendGDScriptParser::get_member_symbol(const String &p_name, const String &p_subclass) const {
@@ -812,7 +972,7 @@ Dictionary ExtendGDScriptParser::dump_class_api(const GDScriptParser::ClassNode
api["name"] = m.signal->identifier->name;
Array pars;
for (int j = 0; j < m.signal->parameters.size(); j++) {
- pars.append(String(m.signal->parameters[i]->identifier->name));
+ pars.append(String(m.signal->parameters[j]->identifier->name));
}
api["arguments"] = pars;
if (const lsp::DocumentSymbol *symbol = get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(m.signal->start_line))) {
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h
index 4fd27de081..a808f19e5b 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.h
+++ b/modules/gdscript/language_server/gdscript_extend_parser.h
@@ -39,6 +39,9 @@
#ifndef LINE_NUMBER_TO_INDEX
#define LINE_NUMBER_TO_INDEX(p_line) ((p_line)-1)
#endif
+#ifndef COLUMN_NUMBER_TO_INDEX
+#define COLUMN_NUMBER_TO_INDEX(p_column) ((p_column)-1)
+#endif
#ifndef SYMBOL_SEPERATOR
#define SYMBOL_SEPERATOR "::"
@@ -50,6 +53,64 @@
typedef HashMap<String, const lsp::DocumentSymbol *> ClassMembers;
+/**
+ * Represents a Position as used by GDScript Parser. Used for conversion to and from `lsp::Position`.
+ *
+ * Difference to `lsp::Position`:
+ * * Line & Char/column: 1-based
+ * * LSP: both 0-based
+ * * Tabs are expanded to columns using tab size (`text_editor/behavior/indent/size`).
+ * * LSP: tab is single char
+ *
+ * Example:
+ * ```gdscript
+ * →→var my_value = 42
+ * ```
+ * `_` is at:
+ * * Godot: `column=12`
+ * * using `indent/size=4`
+ * * Note: counting starts at `1`
+ * * LSP: `character=8`
+ * * Note: counting starts at `0`
+ */
+struct GodotPosition {
+ int line;
+ int column;
+
+ GodotPosition(int p_line, int p_column) :
+ line(p_line), column(p_column) {}
+
+ lsp::Position to_lsp(const Vector<String> &p_lines) const;
+ static GodotPosition from_lsp(const lsp::Position p_pos, const Vector<String> &p_lines);
+
+ bool operator==(const GodotPosition &p_other) const {
+ return line == p_other.line && column == p_other.column;
+ }
+
+ String to_string() const {
+ return vformat("(%d,%d)", line, column);
+ }
+};
+
+struct GodotRange {
+ GodotPosition start;
+ GodotPosition end;
+
+ GodotRange(GodotPosition p_start, GodotPosition p_end) :
+ start(p_start), end(p_end) {}
+
+ lsp::Range to_lsp(const Vector<String> &p_lines) const;
+ static GodotRange from_lsp(const lsp::Range &p_range, const Vector<String> &p_lines);
+
+ bool operator==(const GodotRange &p_other) const {
+ return start == p_other.start && end == p_other.end;
+ }
+
+ String to_string() const {
+ return vformat("[%s:%s]", start.to_string(), end.to_string());
+ }
+};
+
class ExtendGDScriptParser : public GDScriptParser {
String path;
Vector<String> lines;
@@ -60,6 +121,8 @@ class ExtendGDScriptParser : public GDScriptParser {
ClassMembers members;
HashMap<String, ClassMembers> inner_classes;
+ lsp::Range range_of_node(const GDScriptParser::Node *p_node) const;
+
void update_diagnostics();
void update_symbols();
@@ -70,8 +133,7 @@ class ExtendGDScriptParser : public GDScriptParser {
Dictionary dump_function_api(const GDScriptParser::FunctionNode *p_func) const;
Dictionary dump_class_api(const GDScriptParser::ClassNode *p_class) const;
- String parse_documentation(int p_line, bool p_docs_down = false);
- const lsp::DocumentSymbol *search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent) const;
+ const lsp::DocumentSymbol *search_symbol_defined_at_line(int p_line, const lsp::DocumentSymbol &p_parent, const String &p_symbol_name = "") const;
Array member_completions;
@@ -87,10 +149,18 @@ public:
String get_text_for_completion(const lsp::Position &p_cursor) const;
String get_text_for_lookup_symbol(const lsp::Position &p_cursor, const String &p_symbol = "", bool p_func_required = false) const;
- String get_identifier_under_position(const lsp::Position &p_position, Vector2i &p_offset) const;
+ String get_identifier_under_position(const lsp::Position &p_position, lsp::Range &r_range) const;
String get_uri() const;
- const lsp::DocumentSymbol *get_symbol_defined_at_line(int p_line) const;
+ /**
+ * `p_symbol_name` gets ignored if empty. Otherwise symbol must match passed in named.
+ *
+ * Necessary when multiple symbols at same line for example with `func`:
+ * `func handle_arg(arg: int):`
+ * -> Without `p_symbol_name`: returns `handle_arg`. Even if parameter (`arg`) is wanted.
+ * With `p_symbol_name`: symbol name MUST match `p_symbol_name`: returns `arg`.
+ */
+ const lsp::DocumentSymbol *get_symbol_defined_at_line(int p_line, const String &p_symbol_name = "") const;
const lsp::DocumentSymbol *get_member_symbol(const String &p_name, const String &p_subclass = "") const;
const List<lsp::DocumentLink> &get_document_links() const;
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 112db4df3a..14fc21d7dc 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -278,6 +278,11 @@ void GDScriptLanguageProtocol::stop() {
}
void GDScriptLanguageProtocol::notify_client(const String &p_method, const Variant &p_params, int p_client_id) {
+#ifdef TESTS_ENABLED
+ if (clients.is_empty()) {
+ return;
+ }
+#endif
if (p_client_id == -1) {
ERR_FAIL_COND_MSG(latest_client_id == -1,
"GDScript LSP: Can't notify client as none was connected.");
@@ -294,6 +299,11 @@ void GDScriptLanguageProtocol::notify_client(const String &p_method, const Varia
}
void GDScriptLanguageProtocol::request_client(const String &p_method, const Variant &p_params, int p_client_id) {
+#ifdef TESTS_ENABLED
+ if (clients.is_empty()) {
+ return;
+ }
+#endif
if (p_client_id == -1) {
ERR_FAIL_COND_MSG(latest_client_id == -1,
"GDScript LSP: Can't notify client as none was connected.");
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 8c44483288..053be7eec2 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -36,6 +36,8 @@
#include "editor/editor_node.h"
#include "editor/editor_settings.h"
+int GDScriptLanguageServer::port_override = -1;
+
GDScriptLanguageServer::GDScriptLanguageServer() {
_EDITOR_DEF("network/language_server/remote_host", host);
_EDITOR_DEF("network/language_server/remote_port", port);
@@ -62,7 +64,7 @@ void GDScriptLanguageServer::_notification(int p_what) {
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
String remote_host = String(_EDITOR_GET("network/language_server/remote_host"));
- int remote_port = (int)_EDITOR_GET("network/language_server/remote_port");
+ int remote_port = (GDScriptLanguageServer::port_override > -1) ? GDScriptLanguageServer::port_override : (int)_EDITOR_GET("network/language_server/remote_port");
bool remote_use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
if (remote_host != host || remote_port != port || remote_use_thread != use_thread) {
stop();
@@ -84,10 +86,10 @@ void GDScriptLanguageServer::thread_main(void *p_userdata) {
void GDScriptLanguageServer::start() {
host = String(_EDITOR_GET("network/language_server/remote_host"));
- port = (int)_EDITOR_GET("network/language_server/remote_port");
+ port = (GDScriptLanguageServer::port_override > -1) ? GDScriptLanguageServer::port_override : (int)_EDITOR_GET("network/language_server/remote_port");
use_thread = (bool)_EDITOR_GET("network/language_server/use_thread");
if (protocol.start(port, IPAddress(host)) == OK) {
- EditorNode::get_log()->add_message("--- GDScript language server started ---", EditorLog::MSG_TYPE_EDITOR);
+ EditorNode::get_log()->add_message("--- GDScript language server started on port " + itos(port) + " ---", EditorLog::MSG_TYPE_EDITOR);
if (use_thread) {
thread_running = true;
thread.start(GDScriptLanguageServer::thread_main, this);
diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h
index 75f9403a74..e845d139bf 100644
--- a/modules/gdscript/language_server/gdscript_language_server.h
+++ b/modules/gdscript/language_server/gdscript_language_server.h
@@ -53,6 +53,7 @@ private:
void _notification(int p_what);
public:
+ static int port_override;
GDScriptLanguageServer();
void start();
void stop();
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 92a5f55978..1e927f9f6e 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -50,6 +50,8 @@ void GDScriptTextDocument::_bind_methods() {
ClassDB::bind_method(D_METHOD("completion"), &GDScriptTextDocument::completion);
ClassDB::bind_method(D_METHOD("resolve"), &GDScriptTextDocument::resolve);
ClassDB::bind_method(D_METHOD("rename"), &GDScriptTextDocument::rename);
+ ClassDB::bind_method(D_METHOD("prepareRename"), &GDScriptTextDocument::prepareRename);
+ ClassDB::bind_method(D_METHOD("references"), &GDScriptTextDocument::references);
ClassDB::bind_method(D_METHOD("foldingRange"), &GDScriptTextDocument::foldingRange);
ClassDB::bind_method(D_METHOD("codeLens"), &GDScriptTextDocument::codeLens);
ClassDB::bind_method(D_METHOD("documentLink"), &GDScriptTextDocument::documentLink);
@@ -161,11 +163,8 @@ Array GDScriptTextDocument::documentSymbol(const Dictionary &p_params) {
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(uri);
Array arr;
if (HashMap<String, ExtendGDScriptParser *>::ConstIterator parser = GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts.find(path)) {
- Vector<lsp::DocumentedSymbolInformation> list;
- parser->value->get_symbols().symbol_tree_as_list(uri, list);
- for (int i = 0; i < list.size(); i++) {
- arr.push_back(list[i].to_json());
- }
+ lsp::DocumentSymbol symbol = parser->value->get_symbols();
+ arr.push_back(symbol.to_json(true));
}
return arr;
}
@@ -253,6 +252,48 @@ Dictionary GDScriptTextDocument::rename(const Dictionary &p_params) {
return GDScriptLanguageProtocol::get_singleton()->get_workspace()->rename(params, new_name);
}
+Variant GDScriptTextDocument::prepareRename(const Dictionary &p_params) {
+ lsp::TextDocumentPositionParams params;
+ params.load(p_params);
+
+ lsp::DocumentSymbol symbol;
+ lsp::Range range;
+ if (GDScriptLanguageProtocol::get_singleton()->get_workspace()->can_rename(params, symbol, range)) {
+ return Variant(range.to_json());
+ }
+
+ // `null` -> rename not valid at current location.
+ return Variant();
+}
+
+Array GDScriptTextDocument::references(const Dictionary &p_params) {
+ Array res;
+
+ lsp::ReferenceParams params;
+ params.load(p_params);
+
+ const lsp::DocumentSymbol *symbol = GDScriptLanguageProtocol::get_singleton()->get_workspace()->resolve_symbol(params);
+ if (symbol) {
+ Vector<lsp::Location> usages = GDScriptLanguageProtocol::get_singleton()->get_workspace()->find_all_usages(*symbol);
+ res.resize(usages.size());
+ int declaration_adjustment = 0;
+ for (int i = 0; i < usages.size(); i++) {
+ lsp::Location usage = usages[i];
+ if (!params.context.includeDeclaration && usage.range == symbol->range) {
+ declaration_adjustment++;
+ continue;
+ }
+ res[i - declaration_adjustment] = usages[i].to_json();
+ }
+
+ if (declaration_adjustment > 0) {
+ res.resize(res.size() - declaration_adjustment);
+ }
+ }
+
+ return res;
+}
+
Dictionary GDScriptTextDocument::resolve(const Dictionary &p_params) {
lsp::CompletionItem item;
item.load(p_params);
@@ -450,7 +491,7 @@ Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &
if (symbol) {
lsp::Location location;
location.uri = symbol->uri;
- location.range = symbol->range;
+ location.range = symbol->selectionRange;
const String &path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(symbol->uri);
if (file_checker->file_exists(path)) {
arr.push_back(location.to_json());
@@ -464,7 +505,7 @@ Array GDScriptTextDocument::find_symbols(const lsp::TextDocumentPositionParams &
if (!s->uri.is_empty()) {
lsp::Location location;
location.uri = s->uri;
- location.range = s->range;
+ location.range = s->selectionRange;
arr.push_back(location.to_json());
r_list.push_back(s);
}
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index 0121101db2..cfd0490f0a 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -65,6 +65,8 @@ public:
Array completion(const Dictionary &p_params);
Dictionary resolve(const Dictionary &p_params);
Dictionary rename(const Dictionary &p_params);
+ Variant prepareRename(const Dictionary &p_params);
+ Array references(const Dictionary &p_params);
Array foldingRange(const Dictionary &p_params);
Array codeLens(const Dictionary &p_params);
Array documentLink(const Dictionary &p_params);
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 9f848b02f5..81933c8c87 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -46,7 +46,6 @@
void GDScriptWorkspace::_bind_methods() {
ClassDB::bind_method(D_METHOD("apply_new_signal"), &GDScriptWorkspace::apply_new_signal);
ClassDB::bind_method(D_METHOD("didDeleteFiles"), &GDScriptWorkspace::did_delete_files);
- ClassDB::bind_method(D_METHOD("symbol"), &GDScriptWorkspace::symbol);
ClassDB::bind_method(D_METHOD("parse_script", "path", "content"), &GDScriptWorkspace::parse_script);
ClassDB::bind_method(D_METHOD("parse_local_script", "path"), &GDScriptWorkspace::parse_local_script);
ClassDB::bind_method(D_METHOD("get_file_path", "uri"), &GDScriptWorkspace::get_file_path);
@@ -182,35 +181,33 @@ const lsp::DocumentSymbol *GDScriptWorkspace::get_parameter_symbol(const lsp::Do
return nullptr;
}
-const lsp::DocumentSymbol *GDScriptWorkspace::get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier) {
- const lsp::DocumentSymbol *class_symbol = &p_parser->get_symbols();
+const lsp::DocumentSymbol *GDScriptWorkspace::get_local_symbol_at(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier, const lsp::Position p_position) {
+ // Go down and pick closest `DocumentSymbol` with `p_symbol_identifier`.
- for (int i = 0; i < class_symbol->children.size(); ++i) {
- int kind = class_symbol->children[i].kind;
- switch (kind) {
- case lsp::SymbolKind::Function:
- case lsp::SymbolKind::Method:
- case lsp::SymbolKind::Class: {
- const lsp::DocumentSymbol *function_symbol = &class_symbol->children[i];
+ const lsp::DocumentSymbol *current = &p_parser->get_symbols();
+ const lsp::DocumentSymbol *best_match = nullptr;
- for (int l = 0; l < function_symbol->children.size(); ++l) {
- const lsp::DocumentSymbol *local = &function_symbol->children[l];
- if (!local->detail.is_empty() && local->name == p_symbol_identifier) {
- return local;
- }
- }
- } break;
+ while (current) {
+ if (current->name == p_symbol_identifier) {
+ if (current->selectionRange.contains(p_position)) {
+ // Exact match: pos is ON symbol decl identifier.
+ return current;
+ }
- case lsp::SymbolKind::Variable: {
- const lsp::DocumentSymbol *variable_symbol = &class_symbol->children[i];
- if (variable_symbol->name == p_symbol_identifier) {
- return variable_symbol;
- }
- } break;
+ best_match = current;
+ }
+
+ const lsp::DocumentSymbol *parent = current;
+ current = nullptr;
+ for (const lsp::DocumentSymbol &child : parent->children) {
+ if (child.range.contains(p_position)) {
+ current = &child;
+ break;
+ }
}
}
- return nullptr;
+ return best_match;
}
void GDScriptWorkspace::reload_all_workspace_scripts() {
@@ -275,25 +272,6 @@ ExtendGDScriptParser *GDScriptWorkspace::get_parse_result(const String &p_path)
return nullptr;
}
-Array GDScriptWorkspace::symbol(const Dictionary &p_params) {
- String query = p_params["query"];
- Array arr;
- if (!query.is_empty()) {
- for (const KeyValue<String, ExtendGDScriptParser *> &E : scripts) {
- Vector<lsp::DocumentedSymbolInformation> script_symbols;
- E.value->get_symbols().symbol_tree_as_list(E.key, script_symbols);
- for (int i = 0; i < script_symbols.size(); ++i) {
- if (query.is_subsequence_ofn(script_symbols[i].name)) {
- lsp::DocumentedSymbolInformation symbol = script_symbols[i];
- symbol.location.uri = get_file_uri(symbol.location.uri);
- arr.push_back(symbol.to_json());
- }
- }
- }
- }
- return arr;
-}
-
Error GDScriptWorkspace::initialize() {
if (initialized) {
return OK;
@@ -423,7 +401,7 @@ Error GDScriptWorkspace::initialize() {
native_members.insert(E.key, members);
}
- // cache member completions
+ // Cache member completions.
for (const KeyValue<String, ExtendGDScriptParser *> &S : scripts) {
S.value->get_member_completions();
}
@@ -458,48 +436,110 @@ Error GDScriptWorkspace::parse_script(const String &p_path, const String &p_cont
return err;
}
-Dictionary GDScriptWorkspace::rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name) {
- Error err;
- String path = get_file_path(p_doc_pos.textDocument.uri);
+static bool is_valid_rename_target(const lsp::DocumentSymbol *p_symbol) {
+ // Must be valid symbol.
+ if (!p_symbol) {
+ return false;
+ }
+
+ // Cannot rename builtin.
+ if (!p_symbol->native_class.is_empty()) {
+ return false;
+ }
+
+ // Source must be available.
+ if (p_symbol->script_path.is_empty()) {
+ return false;
+ }
+ return true;
+}
+
+Dictionary GDScriptWorkspace::rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name) {
lsp::WorkspaceEdit edit;
- List<String> paths;
- list_script_files("res://", paths);
+ const lsp::DocumentSymbol *reference_symbol = resolve_symbol(p_doc_pos);
+ if (is_valid_rename_target(reference_symbol)) {
+ Vector<lsp::Location> usages = find_all_usages(*reference_symbol);
+ for (int i = 0; i < usages.size(); ++i) {
+ lsp::Location loc = usages[i];
+
+ edit.add_change(loc.uri, loc.range.start.line, loc.range.start.character, loc.range.end.character, new_name);
+ }
+ }
+
+ return edit.to_json();
+}
+bool GDScriptWorkspace::can_rename(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::DocumentSymbol &r_symbol, lsp::Range &r_range) {
const lsp::DocumentSymbol *reference_symbol = resolve_symbol(p_doc_pos);
- if (reference_symbol) {
- String identifier = reference_symbol->name;
+ if (!is_valid_rename_target(reference_symbol)) {
+ return false;
+ }
- for (List<String>::Element *PE = paths.front(); PE; PE = PE->next()) {
- PackedStringArray content = FileAccess::get_file_as_string(PE->get(), &err).split("\n");
- for (int i = 0; i < content.size(); ++i) {
- String line = content[i];
+ String path = get_file_path(p_doc_pos.textDocument.uri);
+ if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
+ parser->get_identifier_under_position(p_doc_pos.position, r_range);
+ r_symbol = *reference_symbol;
+ return true;
+ }
- int character = line.find(identifier);
- while (character > -1) {
- lsp::TextDocumentPositionParams params;
+ return false;
+}
- lsp::TextDocumentIdentifier text_doc;
- text_doc.uri = get_file_uri(PE->get());
+Vector<lsp::Location> GDScriptWorkspace::find_usages_in_file(const lsp::DocumentSymbol &p_symbol, const String &p_file_path) {
+ Vector<lsp::Location> usages;
- params.textDocument = text_doc;
- params.position.line = i;
- params.position.character = character;
+ String identifier = p_symbol.name;
+ if (const ExtendGDScriptParser *parser = get_parse_result(p_file_path)) {
+ const PackedStringArray &content = parser->get_lines();
+ for (int i = 0; i < content.size(); ++i) {
+ String line = content[i];
- const lsp::DocumentSymbol *other_symbol = resolve_symbol(params);
+ int character = line.find(identifier);
+ while (character > -1) {
+ lsp::TextDocumentPositionParams params;
- if (other_symbol == reference_symbol) {
- edit.add_change(text_doc.uri, i, character, character + identifier.length(), new_name);
- }
+ lsp::TextDocumentIdentifier text_doc;
+ text_doc.uri = get_file_uri(p_file_path);
- character = line.find(identifier, character + 1);
+ params.textDocument = text_doc;
+ params.position.line = i;
+ params.position.character = character;
+
+ const lsp::DocumentSymbol *other_symbol = resolve_symbol(params);
+
+ if (other_symbol == &p_symbol) {
+ lsp::Location loc;
+ loc.uri = text_doc.uri;
+ loc.range.start = params.position;
+ loc.range.end.line = params.position.line;
+ loc.range.end.character = params.position.character + identifier.length();
+ usages.append(loc);
}
+
+ character = line.find(identifier, character + 1);
}
}
}
- return edit.to_json();
+ return usages;
+}
+
+Vector<lsp::Location> GDScriptWorkspace::find_all_usages(const lsp::DocumentSymbol &p_symbol) {
+ if (p_symbol.local) {
+ // Only search in current document.
+ return find_usages_in_file(p_symbol, p_symbol.script_path);
+ }
+ // Search in all documents.
+ List<String> paths;
+ list_script_files("res://", paths);
+
+ Vector<lsp::Location> usages;
+ for (List<String>::Element *PE = paths.front(); PE; PE = PE->next()) {
+ usages.append_array(find_usages_in_file(p_symbol, PE->get()));
+ }
+ return usages;
}
Error GDScriptWorkspace::parse_local_script(const String &p_path) {
@@ -636,9 +676,9 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
lsp::Position pos = p_doc_pos.position;
if (symbol_identifier.is_empty()) {
- Vector2i offset;
- symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, offset);
- pos.character += offset.y;
+ lsp::Range range;
+ symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, range);
+ pos.character = range.end.character;
}
if (!symbol_identifier.is_empty()) {
@@ -661,7 +701,7 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
}
if (const ExtendGDScriptParser *target_parser = get_parse_result(target_script_path)) {
- symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location));
+ symbol = target_parser->get_symbol_defined_at_line(LINE_NUMBER_TO_INDEX(ret.location), symbol_identifier);
if (symbol) {
switch (symbol->kind) {
@@ -670,10 +710,6 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
symbol = get_parameter_symbol(symbol, symbol_identifier);
}
} break;
-
- case lsp::SymbolKind::Variable: {
- symbol = get_local_symbol(parser, symbol_identifier);
- } break;
}
}
}
@@ -686,10 +722,9 @@ const lsp::DocumentSymbol *GDScriptWorkspace::resolve_symbol(const lsp::TextDocu
symbol = get_native_symbol(ret.class_name, member);
}
} else {
- symbol = parser->get_member_symbol(symbol_identifier);
-
+ symbol = get_local_symbol_at(parser, symbol_identifier, p_doc_pos.position);
if (!symbol) {
- symbol = get_local_symbol(parser, symbol_identifier);
+ symbol = parser->get_member_symbol(symbol_identifier);
}
}
}
@@ -703,8 +738,8 @@ void GDScriptWorkspace::resolve_related_symbols(const lsp::TextDocumentPositionP
String path = get_file_path(p_doc_pos.textDocument.uri);
if (const ExtendGDScriptParser *parser = get_parse_result(path)) {
String symbol_identifier;
- Vector2i offset;
- symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, offset);
+ lsp::Range range;
+ symbol_identifier = parser->get_identifier_under_position(p_doc_pos.position, range);
for (const KeyValue<StringName, ClassMembers> &E : native_members) {
const ClassMembers &members = native_members.get(E.key);
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index 80653778fb..0b2d43b817 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -54,7 +54,7 @@ protected:
const lsp::DocumentSymbol *get_native_symbol(const String &p_class, const String &p_member = "") const;
const lsp::DocumentSymbol *get_script_symbol(const String &p_path) const;
const lsp::DocumentSymbol *get_parameter_symbol(const lsp::DocumentSymbol *p_parent, const String &symbol_identifier);
- const lsp::DocumentSymbol *get_local_symbol(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier);
+ const lsp::DocumentSymbol *get_local_symbol_at(const ExtendGDScriptParser *p_parser, const String &p_symbol_identifier, const lsp::Position p_position);
void reload_all_workspace_scripts();
@@ -74,9 +74,6 @@ public:
HashMap<StringName, ClassMembers> native_members;
public:
- Array symbol(const Dictionary &p_params);
-
-public:
Error initialize();
Error parse_script(const String &p_path, const String &p_content);
@@ -96,6 +93,9 @@ public:
Error resolve_signature(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::SignatureHelp &r_signature);
void did_delete_files(const Dictionary &p_params);
Dictionary rename(const lsp::TextDocumentPositionParams &p_doc_pos, const String &new_name);
+ bool can_rename(const lsp::TextDocumentPositionParams &p_doc_pos, lsp::DocumentSymbol &r_symbol, lsp::Range &r_range);
+ Vector<lsp::Location> find_usages_in_file(const lsp::DocumentSymbol &p_symbol, const String &p_file_path);
+ Vector<lsp::Location> find_all_usages(const lsp::DocumentSymbol &p_symbol);
GDScriptWorkspace();
~GDScriptWorkspace();
diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h
index 3782945e07..1ac4267c7b 100644
--- a/modules/gdscript/language_server/godot_lsp.h
+++ b/modules/gdscript/language_server/godot_lsp.h
@@ -83,6 +83,14 @@ struct Position {
*/
int character = 0;
+ _FORCE_INLINE_ bool operator==(const Position &p_other) const {
+ return line == p_other.line && character == p_other.character;
+ }
+
+ String to_string() const {
+ return vformat("(%d,%d)", line, character);
+ }
+
_FORCE_INLINE_ void load(const Dictionary &p_params) {
line = p_params["line"];
character = p_params["character"];
@@ -112,6 +120,27 @@ struct Range {
*/
Position end;
+ _FORCE_INLINE_ bool operator==(const Range &p_other) const {
+ return start == p_other.start && end == p_other.end;
+ }
+
+ bool contains(const Position &p_pos) const {
+ // Inside line range.
+ if (start.line <= p_pos.line && p_pos.line <= end.line) {
+ // If on start line: must come after start char.
+ bool start_ok = p_pos.line == start.line ? start.character <= p_pos.character : true;
+ // If on end line: must come before end char.
+ bool end_ok = p_pos.line == end.line ? p_pos.character <= end.character : true;
+ return start_ok && end_ok;
+ } else {
+ return false;
+ }
+ }
+
+ String to_string() const {
+ return vformat("[%s:%s]", start.to_string(), end.to_string());
+ }
+
_FORCE_INLINE_ void load(const Dictionary &p_params) {
start.load(p_params["start"]);
end.load(p_params["end"]);
@@ -203,6 +232,17 @@ struct TextDocumentPositionParams {
}
};
+struct ReferenceContext {
+ /**
+ * Include the declaration of the current symbol.
+ */
+ bool includeDeclaration;
+};
+
+struct ReferenceParams : TextDocumentPositionParams {
+ ReferenceContext context;
+};
+
struct DocumentLinkParams {
/**
* The document to provide document links for.
@@ -343,8 +383,8 @@ struct Command {
}
};
-// Use namespace instead of enumeration to follow the LSP specifications
-// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
+// Use namespace instead of enumeration to follow the LSP specifications.
+// `lsp::EnumName::EnumValue` is OK but `lsp::EnumValue` is not.
namespace TextDocumentSyncKind {
/**
@@ -436,7 +476,7 @@ struct RenameOptions {
/**
* Renames should be checked and tested before being executed.
*/
- bool prepareProvider = false;
+ bool prepareProvider = true;
Dictionary to_json() {
Dictionary dict;
@@ -794,12 +834,12 @@ static const String Markdown = "markdown";
*/
struct MarkupContent {
/**
- * The type of the Markup
+ * The type of the Markup.
*/
String kind;
/**
- * The content itself
+ * The content itself.
*/
String value;
@@ -821,8 +861,8 @@ struct MarkupContent {
};
// Use namespace instead of enumeration to follow the LSP specifications
-// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
-// And here C++ compilers are unhappy with our enumeration name like Color, File, RefCounted etc.
+// `lsp::EnumName::EnumValue` is OK but `lsp::EnumValue` is not.
+// And here C++ compilers are unhappy with our enumeration name like `Color`, `File`, `RefCounted` etc.
/**
* The kind of a completion entry.
*/
@@ -854,7 +894,7 @@ static const int Operator = 24;
static const int TypeParameter = 25;
}; // namespace CompletionItemKind
-// Use namespace instead of enumeration to follow the LSP specifications
+// Use namespace instead of enumeration to follow the LSP specifications.
/**
* Defines whether the insert text in a completion item should be interpreted as
* plain text or a snippet.
@@ -1070,8 +1110,8 @@ struct CompletionList {
};
// Use namespace instead of enumeration to follow the LSP specifications
-// lsp::EnumName::EnumValue is OK but lsp::EnumValue is not
-// And here C++ compilers are unhappy with our enumeration name like String, Array, Object etc
+// `lsp::EnumName::EnumValue` is OK but `lsp::EnumValue` is not
+// And here C++ compilers are unhappy with our enumeration name like `String`, `Array`, `Object` etc
/**
* A symbol kind.
*/
@@ -1105,70 +1145,6 @@ static const int TypeParameter = 26;
}; // namespace SymbolKind
/**
- * Represents information about programming constructs like variables, classes,
- * interfaces etc.
- */
-struct SymbolInformation {
- /**
- * The name of this symbol.
- */
- String name;
-
- /**
- * The kind of this symbol.
- */
- int kind = SymbolKind::File;
-
- /**
- * Indicates if this symbol is deprecated.
- */
- bool deprecated = false;
-
- /**
- * The location of this symbol. The location's range is used by a tool
- * to reveal the location in the editor. If the symbol is selected in the
- * tool the range's start information is used to position the cursor. So
- * the range usually spans more then the actual symbol's name and does
- * normally include things like visibility modifiers.
- *
- * The range doesn't have to denote a node range in the sense of a abstract
- * syntax tree. It can therefore not be used to re-construct a hierarchy of
- * the symbols.
- */
- Location location;
-
- /**
- * The name of the symbol containing this symbol. This information is for
- * user interface purposes (e.g. to render a qualifier in the user interface
- * if necessary). It can't be used to re-infer a hierarchy for the document
- * symbols.
- */
- String containerName;
-
- _FORCE_INLINE_ Dictionary to_json() const {
- Dictionary dict;
- dict["name"] = name;
- dict["kind"] = kind;
- dict["deprecated"] = deprecated;
- dict["location"] = location.to_json();
- dict["containerName"] = containerName;
- return dict;
- }
-};
-
-struct DocumentedSymbolInformation : public SymbolInformation {
- /**
- * A human-readable string with additional information
- */
- String detail;
-
- /**
- * A human-readable string that represents a doc-comment.
- */
- String documentation;
-};
-
-/**
* Represents programming constructs like variables, classes, interfaces etc. that appear in a document. Document symbols can be
* hierarchical and they have two ranges: one that encloses its definition and one that points to its most interesting range,
* e.g. the range of an identifier.
@@ -1186,12 +1162,12 @@ struct DocumentSymbol {
String detail;
/**
- * Documentation for this symbol
+ * Documentation for this symbol.
*/
String documentation;
/**
- * Class name for the native symbols
+ * Class name for the native symbols.
*/
String native_class;
@@ -1206,6 +1182,13 @@ struct DocumentSymbol {
bool deprecated = false;
/**
+ * If `true`: Symbol is local to script and cannot be accessed somewhere else.
+ *
+ * For example: local variable inside a `func`.
+ */
+ bool local = false;
+
+ /**
* The range enclosing this symbol not including leading/trailing whitespace but everything else
* like comments. This information is typically used to determine if the clients cursor is
* inside the symbol to reveal in the symbol in the UI.
@@ -1238,35 +1221,21 @@ struct DocumentSymbol {
dict["documentation"] = documentation;
dict["native_class"] = native_class;
}
- Array arr;
- arr.resize(children.size());
- for (int i = 0; i < children.size(); i++) {
- arr[i] = children[i].to_json(with_doc);
+ if (!children.is_empty()) {
+ Array arr;
+ for (int i = 0; i < children.size(); i++) {
+ if (children[i].local) {
+ continue;
+ }
+ arr.push_back(children[i].to_json(with_doc));
+ }
+ if (!children.is_empty()) {
+ dict["children"] = arr;
+ }
}
- dict["children"] = arr;
return dict;
}
- void symbol_tree_as_list(const String &p_uri, Vector<DocumentedSymbolInformation> &r_list, const String &p_container = "", bool p_join_name = false) const {
- DocumentedSymbolInformation si;
- if (p_join_name && !p_container.is_empty()) {
- si.name = p_container + ">" + name;
- } else {
- si.name = name;
- }
- si.kind = kind;
- si.containerName = p_container;
- si.deprecated = deprecated;
- si.location.uri = p_uri;
- si.location.range = range;
- si.detail = detail;
- si.documentation = documentation;
- r_list.push_back(si);
- for (int i = 0; i < children.size(); i++) {
- children[i].symbol_tree_as_list(p_uri, r_list, si.name, p_join_name);
- }
- }
-
_FORCE_INLINE_ MarkupContent render() const {
MarkupContent markdown;
if (detail.length()) {
@@ -1750,7 +1719,7 @@ struct ServerCapabilities {
/**
* The server provides find references support.
*/
- bool referencesProvider = false;
+ bool referencesProvider = true;
/**
* The server provides document highlight support.
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index 874cbc6ee8..01772a2e38 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -149,6 +149,10 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l
// Set all warning levels to "Warn" in order to test them properly, even the ones that default to error.
ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true);
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
+ if (i == GDScriptWarning::UNTYPED_DECLARATION) {
+ // TODO: Add ability for test scripts to specify which warnings to enable/disable for testing.
+ continue;
+ }
String warning_setting = GDScriptWarning::get_settings_path_from_code((GDScriptWarning::Code)i);
ProjectSettings::get_singleton()->set_setting(warning_setting, (int)GDScriptWarning::WARN);
}
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/typed_array_init_with_unconvertable_in_literal.gd b/modules/gdscript/tests/scripts/analyzer/errors/typed_array_init_with_unconvertable_in_literal.gd
index 25cde1d40b..7cc5aaf44f 100644
--- a/modules/gdscript/tests/scripts/analyzer/errors/typed_array_init_with_unconvertable_in_literal.gd
+++ b/modules/gdscript/tests/scripts/analyzer/errors/typed_array_init_with_unconvertable_in_literal.gd
@@ -1,4 +1,4 @@
func test():
- var unconvertable := 1
- var typed: Array[Object] = [unconvertable]
+ var unconvertible := 1
+ var typed: Array[Object] = [unconvertible]
print('not ok')
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.gd b/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.gd
new file mode 100644
index 0000000000..57dfffdbee
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.gd
@@ -0,0 +1,5 @@
+func _init():
+ super()
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.out b/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.out
new file mode 100644
index 0000000000..e68759223c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/virtual_super_not_implemented.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Cannot call the parent class' virtual function "_init()" because it hasn't been defined.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.gd b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.gd
new file mode 100644
index 0000000000..dafd2ec0c8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.gd
@@ -0,0 +1,17 @@
+class_name TestExportEnumAsDictionary
+
+enum MyEnum {A, B, C}
+
+const Utils = preload("../../utils.notest.gd")
+
+@export var x1 = MyEnum
+@export var x2 = MyEnum.A
+@export var x3 := MyEnum
+@export var x4 := MyEnum.A
+@export var x5: MyEnum
+
+func test():
+ for property in get_property_list():
+ if property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE:
+ print(Utils.get_property_signature(property))
+ print(" ", Utils.get_property_additional_info(property))
diff --git a/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out
new file mode 100644
index 0000000000..f1a13f1045
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/export_enum_as_dictionary.out
@@ -0,0 +1,11 @@
+GDTEST_OK
+@export var x1: Dictionary
+ hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE
+@export var x2: TestExportEnumAsDictionary.MyEnum
+ hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
+@export var x3: Dictionary
+ hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE
+@export var x4: TestExportEnumAsDictionary.MyEnum
+ hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
+@export var x5: TestExportEnumAsDictionary.MyEnum
+ hint=ENUM hint_string="A:0,B:1,C:2" usage=DEFAULT|SCRIPT_VARIABLE|CLASS_IS_ENUM
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_dont_make_literal_typed_with_weak_type.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_array_dont_make_literal_typed_with_weak_type.gd
new file mode 100644
index 0000000000..e1a1f07e47
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_dont_make_literal_typed_with_weak_type.gd
@@ -0,0 +1,22 @@
+var _typed_array: Array[int]
+
+func weak_param_func(weak_param = _typed_array):
+ weak_param = [11] # Don't treat the literal as typed!
+ return weak_param
+
+func hard_param_func(hard_param := _typed_array):
+ hard_param = [12]
+ return hard_param
+
+func test():
+ var weak_var = _typed_array
+ print(weak_var.is_typed())
+ weak_var = [21] # Don't treat the literal as typed!
+ print(weak_var.is_typed())
+ print(weak_param_func().is_typed())
+
+ var hard_var := _typed_array
+ print(hard_var.is_typed())
+ hard_var = [22]
+ print(hard_var.is_typed())
+ print(hard_param_func().is_typed())
diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_dont_make_literal_typed_with_weak_type.out b/modules/gdscript/tests/scripts/analyzer/features/typed_array_dont_make_literal_typed_with_weak_type.out
new file mode 100644
index 0000000000..34b18dbe7c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_dont_make_literal_typed_with_weak_type.out
@@ -0,0 +1,7 @@
+GDTEST_OK
+true
+false
+false
+true
+true
+true
diff --git a/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.gd b/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.gd
new file mode 100644
index 0000000000..a8641e4f3b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.gd
@@ -0,0 +1,21 @@
+class BaseClass:
+ func _get_property_list():
+ return {"property" : "definition"}
+
+class SuperClassMethodsRecognized extends BaseClass:
+ func _init():
+ # Recognizes super class methods.
+ var _x = _get_property_list()
+
+class SuperMethodsRecognized extends BaseClass:
+ func _get_property_list():
+ # Recognizes super method.
+ var result = super()
+ result["new"] = "new"
+ return result
+
+func test():
+ var test1 = SuperClassMethodsRecognized.new()
+ print(test1._get_property_list()) # Calls base class's method.
+ var test2 = SuperMethodsRecognized.new()
+ print(test2._get_property_list())
diff --git a/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.out b/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.out
new file mode 100644
index 0000000000..ccff660117
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/virtual_method_implemented.out
@@ -0,0 +1,3 @@
+GDTEST_OK
+{ "property": "definition" }
+{ "property": "definition", "new": "new" }
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_equal_to_inferred.gd b/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_equal_to_inferred.gd
deleted file mode 100644
index 1b32491e48..0000000000
--- a/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_equal_to_inferred.gd
+++ /dev/null
@@ -1,4 +0,0 @@
-func test():
- var a: Array[Node] = []
- for node: Node in a:
- print(node)
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_equal_to_inferred.out b/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_equal_to_inferred.out
deleted file mode 100644
index 3b3fbd9bd1..0000000000
--- a/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_equal_to_inferred.out
+++ /dev/null
@@ -1,5 +0,0 @@
-GDTEST_OK
->> WARNING
->> Line: 3
->> REDUNDANT_FOR_VARIABLE_TYPE
->> The for loop iterator "node" already has inferred type "Node", the specified type is redundant.
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_supertype_of_inferred.gd b/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_supertype_of_inferred.gd
deleted file mode 100644
index fcbc13c53d..0000000000
--- a/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_supertype_of_inferred.gd
+++ /dev/null
@@ -1,4 +0,0 @@
-func test():
- var a: Array[Node2D] = []
- for node: Node in a:
- print(node)
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_supertype_of_inferred.out b/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_supertype_of_inferred.out
deleted file mode 100644
index 36d4a161d3..0000000000
--- a/modules/gdscript/tests/scripts/analyzer/warnings/for_loop_specified_type_is_supertype_of_inferred.out
+++ /dev/null
@@ -1,5 +0,0 @@
-GDTEST_OK
->> WARNING
->> Line: 3
->> REDUNDANT_FOR_VARIABLE_TYPE
->> The for loop iterator "node" has inferred type "Node2D" but its supertype "Node" is specified.
diff --git a/modules/gdscript/tests/scripts/lsp/class.notest.gd b/modules/gdscript/tests/scripts/lsp/class.notest.gd
new file mode 100644
index 0000000000..53d0b14d72
--- /dev/null
+++ b/modules/gdscript/tests/scripts/lsp/class.notest.gd
@@ -0,0 +1,132 @@
+extends Node
+
+class Inner1 extends Node:
+# ^^^^^^ class1 -> class1
+ var member1 := 42
+ # ^^^^^^^ class1:member1 -> class1:member1
+ var member2 : int = 13
+ # ^^^^^^^ class1:member2 -> class1:member2
+ var member3 = 1337
+ # ^^^^^^^ class1:member3 -> class1:member3
+
+ signal changed(old, new)
+ # ^^^^^^^ class1:signal -> class1:signal
+ func my_func(arg1: int, arg2: String, arg3):
+ # | | | | | | ^^^^ class1:func:arg3 -> class1:func:arg3
+ # | | | | ^^^^ class1:func:arg2 -> class1:func:arg2
+ # | | ^^^^ class1:func:arg1 -> class1:func:arg1
+ # ^^^^^^^ class1:func -> class1:func
+ print(arg1, arg2, arg3)
+ # | | | | ^^^^ -> class1:func:arg3
+ # | | ^^^^ -> class1:func:arg2
+ # ^^^^ -> class1:func:arg1
+ changed.emit(arg1, arg3)
+ # | | | ^^^^ -> class1:func:arg3
+ # | ^^^^ -> class1:func:arg1
+ #<^^^^^ -> class1:signal
+ return arg1 + arg2.length() + arg3
+ # | | | | ^^^^ -> class1:func:arg3
+ # | | ^^^^ -> class1:func:arg2
+ # ^^^^ -> class1:func:arg1
+
+class Inner2:
+# ^^^^^^ class2 -> class2
+ var member1 := 42
+ # ^^^^^^^ class2:member1 -> class2:member1
+ var member2 : int = 13
+ # ^^^^^^^ class2:member2 -> class2:member2
+ var member3 = 1337
+ # ^^^^^^^ class2:member3 -> class2:member3
+
+ signal changed(old, new)
+ # ^^^^^^^ class2:signal -> class2:signal
+ func my_func(arg1: int, arg2: String, arg3):
+ # | | | | | | ^^^^ class2:func:arg3 -> class2:func:arg3
+ # | | | | ^^^^ class2:func:arg2 -> class2:func:arg2
+ # | | ^^^^ class2:func:arg1 -> class2:func:arg1
+ # ^^^^^^^ class2:func -> class2:func
+ print(arg1, arg2, arg3)
+ # | | | | ^^^^ -> class2:func:arg3
+ # | | ^^^^ -> class2:func:arg2
+ # ^^^^ -> class2:func:arg1
+ changed.emit(arg1, arg3)
+ # | | | ^^^^ -> class2:func:arg3
+ # | ^^^^ -> class2:func:arg1
+ #<^^^^^ -> class2:signal
+ return arg1 + arg2.length() + arg3
+ # | | | | ^^^^ -> class2:func:arg3
+ # | | ^^^^ -> class2:func:arg2
+ # ^^^^ -> class2:func:arg1
+
+class Inner3 extends Inner2:
+# | | ^^^^^^ -> class2
+# ^^^^^^ class3 -> class3
+ var whatever = "foo"
+ # ^^^^^^^^ class3:whatever -> class3:whatever
+
+ func _init():
+ # ^^^^^ class3:init
+ # Note: no self-ref check here: resolves to `Object._init`.
+ # usages of `Inner3.new()` DO resolve to this `_init`
+ pass
+
+ class NestedInInner3:
+ # ^^^^^^^^^^^^^^ class3:nested1 -> class3:nested1
+ var some_value := 42
+ # ^^^^^^^^^^ class3:nested1:some_value -> class3:nested1:some_value
+
+ class AnotherNestedInInner3 extends NestedInInner3:
+ #! | | ^^^^^^^^^^^^^^ -> class3:nested1
+ # ^^^^^^^^^^^^^^^^^^^^^ class3:nested2 -> class3:nested2
+ var another_value := 13
+ # ^^^^^^^^^^^^^ class3:nested2:another_value -> class3:nested2:another_value
+
+func _ready():
+ var inner1 = Inner1.new()
+ # | | ^^^^^^ -> class1
+ # ^^^^^^ func:class1 -> func:class1
+ var value1 = inner1.my_func(1,"",3)
+ # | | | | ^^^^^^^ -> class1:func
+ # | | ^^^^^^ -> func:class1
+ # ^^^^^^ func:class1:value1 -> func:class1:value1
+ var value2 = inner1.member3
+ # | | | | ^^^^^^^ -> class1:member3
+ # | | ^^^^^^ -> func:class1
+ # ^^^^^^ func:class1:value2 -> func:class1:value2
+ print(value1, value2)
+ # | | ^^^^^^ -> func:class1:value2
+ # ^^^^^^ -> func:class1:value1
+
+ var inner3 = Inner3.new()
+ # | | | | ^^^ -> class3:init
+ # | | ^^^^^^ -> class3
+ # ^^^^^^ func:class3 -> func:class3
+ print(inner3)
+ # ^^^^^^ -> func:class3
+
+ var nested1 = Inner3.NestedInInner3.new()
+ # | | | | ^^^^^^^^^^^^^^ -> class3:nested1
+ # | | ^^^^^^ -> class3
+ # ^^^^^^^ func:class3:nested1 -> func:class3:nested1
+ var value_nested1 = nested1.some_value
+ # | | | | ^^^^^^^^^^ -> class3:nested1:some_value
+ # | | ^^^^^^^ -> func:class3:nested1
+ # ^^^^^^^^^^^^^ func:class3:nested1:value
+ print(value_nested1)
+ # ^^^^^^^^^^^^^ -> func:class3:nested1:value
+
+ var nested2 = Inner3.AnotherNestedInInner3.new()
+ # | | | | ^^^^^^^^^^^^^^^^^^^^^ -> class3:nested2
+ # | | ^^^^^^ -> class3
+ # ^^^^^^^ func:class3:nested2 -> func:class3:nested2
+ var value_nested2 = nested2.some_value
+ # | | | | ^^^^^^^^^^ -> class3:nested1:some_value
+ # | | ^^^^^^^ -> func:class3:nested2
+ # ^^^^^^^^^^^^^ func:class3:nested2:value
+ var another_value_nested2 = nested2.another_value
+ # | | | | ^^^^^^^^^^^^^ -> class3:nested2:another_value
+ # | | ^^^^^^^ -> func:class3:nested2
+ # ^^^^^^^^^^^^^^^^^^^^^ func:class3:nested2:another_value_nested
+ print(value_nested2, another_value_nested2)
+ # | | ^^^^^^^^^^^^^^^^^^^^^ -> func:class3:nested2:another_value_nested
+ # ^^^^^^^^^^^^^ -> func:class3:nested2:value
diff --git a/modules/gdscript/tests/scripts/lsp/enums.notest.gd b/modules/gdscript/tests/scripts/lsp/enums.notest.gd
new file mode 100644
index 0000000000..38b9ec110a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/lsp/enums.notest.gd
@@ -0,0 +1,26 @@
+extends Node
+
+enum {UNIT_NEUTRAL, UNIT_ENEMY, UNIT_ALLY}
+# | | | | ^^^^^^^^^ enum:unnamed:ally -> enum:unnamed:ally
+# | | ^^^^^^^^^^ enum:unnamed:enemy -> enum:unnamed:enemy
+# ^^^^^^^^^^^^ enum:unnamed:neutral -> enum:unnamed:neutral
+enum Named {THING_1, THING_2, ANOTHER_THING = -1}
+# | | | | | | ^^^^^^^^^^^^^ enum:named:thing3 -> enum:named:thing3
+# | | | | ^^^^^^^ enum:named:thing2 -> enum:named:thing2
+# | | ^^^^^^^ enum:named:thing1 -> enum:named:thing1
+# ^^^^^ enum:named -> enum:named
+
+func f(arg):
+ match arg:
+ UNIT_ENEMY: print(UNIT_ENEMY)
+ # | ^^^^^^^^^^ -> enum:unnamed:enemy
+ #<^^^^^^^^ -> enum:unnamed:enemy
+ Named.THING_2: print(Named.THING_2)
+ #! | | | | | ^^^^^^^ -> enum:named:thing2
+ # | | | ^^^^^ -> enum:named
+ #! | ^^^^^^^ -> enum:named:thing2
+ #<^^^ -> enum:named
+ _: print(UNIT_ENEMY, Named.ANOTHER_THING)
+ #! | | | | ^^^^^^^^^^^^^ -> enum:named:thing3
+ # | | ^^^^^ -> enum:named
+ # ^^^^^^^^^^ -> enum:unnamed:enemy
diff --git a/modules/gdscript/tests/scripts/lsp/indentation.notest.gd b/modules/gdscript/tests/scripts/lsp/indentation.notest.gd
new file mode 100644
index 0000000000..c25d73a719
--- /dev/null
+++ b/modules/gdscript/tests/scripts/lsp/indentation.notest.gd
@@ -0,0 +1,28 @@
+extends Node
+
+var root = 0
+# ^^^^ 0_indent -> 0_indent
+
+func a():
+ var alpha: int = root + 42
+ # | | ^^^^ -> 0_indent
+ # ^^^^^ 1_indent -> 1_indent
+ if alpha > 42:
+ # ^^^^^ -> 1_indent
+ var beta := alpha + 13
+ # | | ^^^^ -> 1_indent
+ # ^^^^ 2_indent -> 2_indent
+ if beta > alpha:
+ # | | ^^^^^ -> 1_indent
+ # ^^^^ -> 2_indent
+ var gamma = beta + 1
+ # | | ^^^^ -> 2_indent
+ # ^^^^^ 3_indent -> 3_indent
+ print(gamma)
+ # ^^^^^ -> 3_indent
+ print(beta)
+ # ^^^^ -> 2_indent
+ print(alpha)
+ # ^^^^^ -> 1_indent
+ print(root)
+ # ^^^^ -> 0_indent
diff --git a/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd b/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd
new file mode 100644
index 0000000000..6f5d468eea
--- /dev/null
+++ b/modules/gdscript/tests/scripts/lsp/lambdas.notest.gd
@@ -0,0 +1,91 @@
+extends Node
+
+var lambda_member1 := func(alpha: int, beta): return alpha + beta
+# | | | | | | | | ^^^^ -> \1:beta
+# | | | | | | ^^^^^ -> \1:alpha
+# | | | | ^^^^ \1:beta -> \1:beta
+# | | ^^^^^ \1:alpha -> \1:alpha
+# ^^^^^^^^^^^^^^ \1 -> \1
+
+var lambda_member2 := func(alpha, beta: int) -> int:
+# | | | | | |
+# | | | | | |
+# | | | | ^^^^ \2:beta -> \2:beta
+# | | ^^^^^ \2:alpha -> \2:alpha
+# ^^^^^^^^^^^^^^ \2 -> \2
+ return alpha + beta
+ # | | ^^^^ -> \2:beta
+ # ^^^^^ -> \2:alpha
+
+var lambda_member3 := func add_values(alpha, beta): return alpha + beta
+# | | | | | | | | ^^^^ -> \3:beta
+# | | | | | | ^^^^^ -> \3:alpha
+# | | | | ^^^^ \3:beta -> \3:beta
+# | | ^^^^^ \3:alpha -> \3:alpha
+# ^^^^^^^^^^^^^^ \3 -> \3
+
+var lambda_multiline = func(alpha: int, beta: int) -> int:
+# | | | | | |
+# | | | | | |
+# | | | | ^^^^ \multi:beta -> \multi:beta
+# | | ^^^^^ \multi:alpha -> \multi:alpha
+# ^^^^^^^^^^^^^^^^ \multi -> \multi
+ print(alpha + beta)
+ # | | ^^^^ -> \multi:beta
+ # ^^^^^ -> \multi:alpha
+ var tmp = alpha + beta + 42
+ # | | | | ^^^^ -> \multi:beta
+ # | | ^^^^^ -> \multi:alpha
+ # ^^^ \multi:tmp -> \multi:tmp
+ print(tmp)
+ # ^^^ -> \multi:tmp
+ if tmp > 50:
+ # ^^^ -> \multi:tmp
+ tmp += alpha
+ # | ^^^^^ -> \multi:alpha
+ #<^ -> \multi:tmp
+ else:
+ tmp -= beta
+ # | ^^^^ -> \multi:beta
+ #<^ -> \multi:tmp
+ print(tmp)
+ # ^^^ -> \multi:tmp
+ return beta + tmp + alpha
+ # | | | | ^^^^^ -> \multi:alpha
+ # | | ^^^ -> \multi:tmp
+ # ^^^^ -> \multi:beta
+
+
+var some_name := "foo bar"
+# ^^^^^^^^^ member:some_name -> member:some_name
+
+func _ready() -> void:
+ var a = lambda_member1.call(1,2)
+ # ^^^^^^^^^^^^^^ -> \1
+ var b = lambda_member2.call(1,2)
+ # ^^^^^^^^^^^^^^ -> \2
+ var c = lambda_member3.call(1,2)
+ # ^^^^^^^^^^^^^^ -> \3
+ var d = lambda_multiline.call(1,2)
+ # ^^^^^^^^^^^^^^^^ -> \multi
+ print(a,b,c,d)
+
+ var lambda_local = func(alpha, beta): return alpha + beta
+ # | | | | | | | | ^^^^ -> \local:beta
+ # | | | | | | ^^^^^ -> \local:alpha
+ # | | | | ^^^^ \local:beta -> \local:beta
+ # | | ^^^^^ \local:alpha -> \local:alpha
+ # ^^^^^^^^^^^^ \local -> \local
+
+ var value := 42
+ # ^^^^^ local:value -> local:value
+ var lambda_capture = func(): return value + some_name.length()
+ # | | | | ^^^^^^^^^ -> member:some_name
+ # | | ^^^^^ -> local:value
+ # ^^^^^^^^^^^^^^ \capture -> \capture
+
+ var z = lambda_local.call(1,2)
+ # ^^^^^^^^^^^^ -> \local
+ var x = lambda_capture.call()
+ # ^^^^^^^^^^^^^^ -> \capture
+ print(z,x)
diff --git a/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd b/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd
new file mode 100644
index 0000000000..b6cc46f7da
--- /dev/null
+++ b/modules/gdscript/tests/scripts/lsp/local_variables.notest.gd
@@ -0,0 +1,25 @@
+extends Node
+
+var member := 2
+# ^^^^^^ member -> member
+
+func test_member() -> void:
+ var test := member + 42
+ # | | ^^^^^^ -> member
+ # ^^^^ test -> test
+ test += 3
+ #<^^ -> test
+ member += 5
+ #<^^^^ -> member
+ test = return_arg(test)
+ # | ^^^^ -> test
+ #<^^ -> test
+ print(test)
+ # ^^^^ -> test
+
+func return_arg(arg: int) -> int:
+# ^^^ arg -> arg
+ arg += 2
+ #<^ -> arg
+ return arg
+ # ^^^ -> arg \ No newline at end of file
diff --git a/modules/gdscript/tests/scripts/lsp/properties.notest.gd b/modules/gdscript/tests/scripts/lsp/properties.notest.gd
new file mode 100644
index 0000000000..8dfaee2e5b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/lsp/properties.notest.gd
@@ -0,0 +1,65 @@
+extends Node
+
+var prop1 := 42
+# ^^^^^ prop1 -> prop1
+var prop2 : int = 42
+# ^^^^^ prop2 -> prop2
+var prop3 := 42:
+# ^^^^^ prop3 -> prop3
+ get:
+ return prop3 + 13
+ # ^^^^^ -> prop3
+ set(value):
+ # ^^^^^ prop3:value -> prop3:value
+ prop3 = value - 13
+ # | ^^^^^ -> prop3:value
+ #<^^^ -> prop3
+var prop4: int:
+# ^^^^^ prop4 -> prop4
+ get:
+ return 42
+var prop5 := 42:
+# ^^^^^ prop5 -> prop5
+ set(value):
+ # ^^^^^ prop5:value -> prop5:value
+ prop5 = value - 13
+ # | ^^^^^ -> prop5:value
+ #<^^^ -> prop5
+
+var prop6:
+# ^^^^^ prop6 -> prop6
+ get = get_prop6,
+ # ^^^^^^^^^ -> get_prop6
+ set = set_prop6
+ # ^^^^^^^^^ -> set_prop6
+func get_prop6():
+# ^^^^^^^^^ get_prop6 -> get_prop6
+ return 42
+func set_prop6(value):
+# | | ^^^^^ set_prop6:value -> set_prop6:value
+# ^^^^^^^^^ set_prop6 -> set_prop6
+ print(value)
+ # ^^^^^ -> set_prop6:value
+
+var prop7:
+# ^^^^^ prop7 -> prop7
+ get = get_prop7
+ # ^^^^^^^^^ -> get_prop7
+func get_prop7():
+# ^^^^^^^^^ get_prop7 -> get_prop7
+ return 42
+
+var prop8:
+# ^^^^^ prop8 -> prop8
+ set = set_prop8
+ # ^^^^^^^^^ -> set_prop8
+func set_prop8(value):
+# | | ^^^^^ set_prop8:value -> set_prop8:value
+# ^^^^^^^^^ set_prop8 -> set_prop8
+ print(value)
+ # ^^^^^ -> set_prop8:value
+
+const const_var := 42
+# ^^^^^^^^^ const_var -> const_var
+static var static_var := 42
+# ^^^^^^^^^^ static_var -> static_var
diff --git a/modules/gdscript/tests/scripts/lsp/scopes.notest.gd b/modules/gdscript/tests/scripts/lsp/scopes.notest.gd
new file mode 100644
index 0000000000..20b8fb9bd7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/lsp/scopes.notest.gd
@@ -0,0 +1,106 @@
+extends Node
+
+var member := 2
+# ^^^^^^ public -> public
+
+signal some_changed(new_value)
+# | | ^^^^^^^^^ signal:parameter -> signal:parameter
+# ^^^^^^^^^^^^ signal -> signal
+var some_value := 42:
+# ^^^^^^^^^^ property -> property
+ get:
+ return some_value
+ # ^^^^^^^^^^ -> property
+ set(value):
+ # ^^^^^ property:set:value -> property:set:value
+ some_changed.emit(value)
+ # | ^^^^^ -> property:set:value
+ #<^^^^^^^^^^ -> signal
+ some_value = value
+ # | ^^^^^ -> property:set:value
+ #<^^^^^^^^ -> property
+
+func v():
+ var value := member + 2
+ # | | ^^^^^^ -> public
+ # ^^^^^ v:value -> v:value
+ print(value)
+ # ^^^^^ -> v:value
+ if value > 0:
+ # ^^^^^ -> v:value
+ var beta := value + 2
+ # | | ^^^^^ -> v:value
+ # ^^^^ v:if:beta -> v:if:beta
+ print(beta)
+ # ^^^^ -> v:if:beta
+
+ for counter in beta:
+ # | | ^^^^ -> v:if:beta
+ # ^^^^^^^ v:if:counter -> v:if:counter
+ print (counter)
+ # ^^^^^^^ -> v:if:counter
+
+ else:
+ for counter in value:
+ # | | ^^^^^ -> v:value
+ # ^^^^^^^ v:else:counter -> v:else:counter
+ print(counter)
+ # ^^^^^^^ -> v:else:counter
+
+func f():
+ var func1 = func(value): print(value + 13)
+ # | | | | ^^^^^ -> f:func1:value
+ # | | ^^^^^ f:func1:value -> f:func1:value
+ # ^^^^^ f:func1 -> f:func1
+ var func2 = func(value): print(value + 42)
+ # | | | | ^^^^^ -> f:func2:value
+ # | | ^^^^^ f:func2:value -> f:func2:value
+ # ^^^^^ f:func2 -> f:func2
+
+ func1.call(1)
+ #<^^^ -> f:func1
+ func2.call(2)
+ #<^^^ -> f:func2
+
+func m():
+ var value = 42
+ # ^^^^^ m:value -> m:value
+
+ match value:
+ # ^^^^^ -> m:value
+ 13:
+ print(value)
+ # ^^^^^ -> m:value
+ [var start, _, var end]:
+ # | | ^^^ m:match:array:end -> m:match:array:end
+ # ^^^^^ m:match:array:start -> m:match:array:start
+ print(start + end)
+ # | | ^^^ -> m:match:array:end
+ # ^^^^^ -> m:match:array:start
+ { "name": var name }:
+ # ^^^^ m:match:dict:var -> m:match:dict:var
+ print(name)
+ # ^^^^ -> m:match:dict:var
+ var whatever:
+ # ^^^^^^^^ m:match:var -> m:match:var
+ print(whatever)
+ # ^^^^^^^^ -> m:match:var
+
+func m2():
+ var value = 42
+ # ^^^^^ m2:value -> m2:value
+
+ match value:
+ # ^^^^^ -> m2:value
+ { "name": var name }:
+ # ^^^^ m2:match:dict:var -> m2:match:dict:var
+ print(name)
+ # ^^^^ -> m2:match:dict:var
+ [var name, ..]:
+ # ^^^^ m2:match:array:var -> m2:match:array:var
+ print(name)
+ # ^^^^ -> m2:match:array:var
+ var name:
+ # ^^^^ m2:match:var -> m2:match:var
+ print(name)
+ # ^^^^ -> m2:match:var
diff --git a/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd
new file mode 100644
index 0000000000..338000fa0e
--- /dev/null
+++ b/modules/gdscript/tests/scripts/lsp/shadowing_initializer.notest.gd
@@ -0,0 +1,56 @@
+extends Node
+
+var value := 42
+# ^^^^^ member:value -> member:value
+
+func variable():
+ var value = value + 42
+ #! | | ^^^^^ -> member:value
+ # ^^^^^ variable:value -> variable:value
+ print(value)
+ # ^^^^^ -> variable:value
+
+func array():
+ var value = [1,value,3,value+4]
+ #! | | | | ^^^^^ -> member:value
+ #! | | ^^^^^ -> member:value
+ # ^^^^^ array:value -> array:value
+ print(value)
+ # ^^^^^ -> array:value
+
+func dictionary():
+ var value = {
+ # ^^^^^ dictionary:value -> dictionary:value
+ "key1": value,
+ #! ^^^^^ -> member:value
+ "key2": 1 + value + 3,
+ #! ^^^^^ -> member:value
+ }
+ print(value)
+ # ^^^^^ -> dictionary:value
+
+func for_loop():
+ for value in value:
+ # | | ^^^^^ -> member:value
+ # ^^^^^ for:value -> for:value
+ print(value)
+ # ^^^^^ -> for:value
+
+func for_range():
+ for value in range(5, value):
+ # | | ^^^^^ -> member:value
+ # ^^^^^ for:range:value -> for:range:value
+ print(value)
+ # ^^^^^ -> for:range:value
+
+func matching():
+ match value:
+ # ^^^^^ -> member:value
+ 42: print(value)
+ # ^^^^^ -> member:value
+ [var value, ..]: print(value)
+ # | | ^^^^^ -> match:array:value
+ # ^^^^^ match:array:value -> match:array:value
+ var value: print(value)
+ # | | ^^^^^ -> match:var:value
+ # ^^^^^ match:var:value -> match:var:value
diff --git a/modules/gdscript/tests/scripts/parser/errors/bad_r_string_1.gd b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_1.gd
new file mode 100644
index 0000000000..e5eecbb819
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_1.gd
@@ -0,0 +1,2 @@
+func test():
+ print(r"\")
diff --git a/modules/gdscript/tests/scripts/parser/errors/bad_r_string_1.out b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_1.out
new file mode 100644
index 0000000000..c8e843b0d7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_1.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Unterminated string.
diff --git a/modules/gdscript/tests/scripts/parser/errors/bad_r_string_2.gd b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_2.gd
new file mode 100644
index 0000000000..9168b69f86
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_2.gd
@@ -0,0 +1,2 @@
+func test():
+ print(r"\\"")
diff --git a/modules/gdscript/tests/scripts/parser/errors/bad_r_string_2.out b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_2.out
new file mode 100644
index 0000000000..c8e843b0d7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_2.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Unterminated string.
diff --git a/modules/gdscript/tests/scripts/parser/errors/bad_r_string_3.gd b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_3.gd
new file mode 100644
index 0000000000..37dc910e5f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_3.gd
@@ -0,0 +1,3 @@
+func test():
+ # v
+ print(r"['"]*")
diff --git a/modules/gdscript/tests/scripts/parser/errors/bad_r_string_3.out b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_3.out
new file mode 100644
index 0000000000..dcb5c2f289
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/bad_r_string_3.out
@@ -0,0 +1,2 @@
+GDTEST_PARSER_ERROR
+Closing "]" doesn't have an opening counterpart.
diff --git a/modules/gdscript/tests/scripts/parser/features/r_strings.gd b/modules/gdscript/tests/scripts/parser/features/r_strings.gd
new file mode 100644
index 0000000000..6f546f28be
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/r_strings.gd
@@ -0,0 +1,22 @@
+func test():
+ print(r"test ' \' \" \\ \n \t \u2023 test")
+ print(r"\n\\[\t ]*(\w+)")
+ print(r"")
+ print(r"\"")
+ print(r"\\\"")
+ print(r"\\")
+ print(r"\" \\\" \\\\\"")
+ print(r"\ \\ \\\ \\\\ \\\\\ \\")
+ print(r'"')
+ print(r'"(?:\\.|[^"])*"')
+ print(r"""""")
+ print(r"""test \t "test"="" " \" \\\" \ \\ \\\ test""")
+ print(r'''r"""test \t "test"="" " \" \\\" \ \\ \\\ test"""''')
+ print(r"\t
+ \t")
+ print(r"\t \
+ \t")
+ print(r"""\t
+ \t""")
+ print(r"""\t \
+ \t""")
diff --git a/modules/gdscript/tests/scripts/parser/features/r_strings.out b/modules/gdscript/tests/scripts/parser/features/r_strings.out
new file mode 100644
index 0000000000..114ef0a6c3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/r_strings.out
@@ -0,0 +1,22 @@
+GDTEST_OK
+test ' \' \" \\ \n \t \u2023 test
+\n\\[\t ]*(\w+)
+
+\"
+\\\"
+\\
+\" \\\" \\\\\"
+\ \\ \\\ \\\\ \\\\\ \\
+"
+"(?:\\.|[^"])*"
+
+test \t "test"="" " \" \\\" \ \\ \\\ test
+r"""test \t "test"="" " \" \\\" \ \\ \\\ test"""
+\t
+ \t
+\t \
+ \t
+\t
+ \t
+\t \
+ \t
diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.gd b/modules/gdscript/tests/scripts/runtime/features/member_info.gd
new file mode 100644
index 0000000000..805ea42455
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/member_info.gd
@@ -0,0 +1,72 @@
+class_name TestMemberInfo
+
+class MyClass:
+ pass
+
+enum MyEnum {}
+
+const Utils = preload("../../utils.notest.gd")
+
+static var test_static_var_untyped
+static var test_static_var_weak_null = null
+static var test_static_var_weak_int = 1
+static var test_static_var_hard_int: int
+
+var test_var_untyped
+var test_var_weak_null = null
+var test_var_weak_int = 1
+@export var test_var_weak_int_exported = 1
+var test_var_weak_variant_type = TYPE_NIL
+@export var test_var_weak_variant_type_exported = TYPE_NIL
+var test_var_hard_variant: Variant
+var test_var_hard_int: int
+var test_var_hard_variant_type: Variant.Type
+@export var test_var_hard_variant_type_exported: Variant.Type
+var test_var_hard_node_process_mode: Node.ProcessMode
+var test_var_hard_my_enum: MyEnum
+var test_var_hard_array: Array
+var test_var_hard_array_int: Array[int]
+var test_var_hard_array_variant_type: Array[Variant.Type]
+var test_var_hard_array_node_process_mode: Array[Node.ProcessMode]
+var test_var_hard_array_my_enum: Array[MyEnum]
+var test_var_hard_array_resource: Array[Resource]
+var test_var_hard_array_this: Array[TestMemberInfo]
+var test_var_hard_array_my_class: Array[MyClass]
+var test_var_hard_resource: Resource
+var test_var_hard_this: TestMemberInfo
+var test_var_hard_my_class: MyClass
+
+static func test_static_func(): pass
+
+func test_func_implicit_void(): pass
+func test_func_explicit_void() -> void: pass
+func test_func_weak_null(): return null
+func test_func_weak_int(): return 1
+func test_func_hard_variant() -> Variant: return null
+func test_func_hard_int() -> int: return 1
+func test_func_args_1(_a: int, _b: Array[int], _c: int = 1, _d = 2): pass
+func test_func_args_2(_a = 1, _b = _a, _c = [2], _d = 3): pass
+
+signal test_signal_1()
+signal test_signal_2(a: Variant, b)
+signal test_signal_3(a: int, b: Array[int])
+signal test_signal_4(a: Variant.Type, b: Array[Variant.Type])
+signal test_signal_5(a: MyEnum, b: Array[MyEnum])
+signal test_signal_6(a: Resource, b: Array[Resource])
+signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo])
+signal test_signal_8(a: MyClass, b: Array[MyClass])
+
+func test():
+ var script: Script = get_script()
+ for property in script.get_property_list():
+ if str(property.name).begins_with("test_"):
+ print(Utils.get_property_signature(property, true))
+ for property in get_property_list():
+ if str(property.name).begins_with("test_"):
+ print(Utils.get_property_signature(property))
+ for method in get_method_list():
+ if str(method.name).begins_with("test_"):
+ print(Utils.get_method_signature(method))
+ for method in get_signal_list():
+ if str(method.name).begins_with("test_"):
+ print(Utils.get_method_signature(method, true))
diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.out b/modules/gdscript/tests/scripts/runtime/features/member_info.out
new file mode 100644
index 0000000000..3a91507da9
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/member_info.out
@@ -0,0 +1,45 @@
+GDTEST_OK
+static var test_static_var_untyped: Variant
+static var test_static_var_weak_null: Variant
+static var test_static_var_weak_int: Variant
+static var test_static_var_hard_int: int
+var test_var_untyped: Variant
+var test_var_weak_null: Variant
+var test_var_weak_int: Variant
+@export var test_var_weak_int_exported: int
+var test_var_weak_variant_type: Variant
+@export var test_var_weak_variant_type_exported: Variant.Type
+var test_var_hard_variant: Variant
+var test_var_hard_int: int
+var test_var_hard_variant_type: Variant.Type
+@export var test_var_hard_variant_type_exported: Variant.Type
+var test_var_hard_node_process_mode: Node.ProcessMode
+var test_var_hard_my_enum: TestMemberInfo.MyEnum
+var test_var_hard_array: Array
+var test_var_hard_array_int: Array[int]
+var test_var_hard_array_variant_type: Array[Variant.Type]
+var test_var_hard_array_node_process_mode: Array[Node.ProcessMode]
+var test_var_hard_array_my_enum: Array[TestMemberInfo.MyEnum]
+var test_var_hard_array_resource: Array[Resource]
+var test_var_hard_array_this: Array[TestMemberInfo]
+var test_var_hard_array_my_class: Array[RefCounted]
+var test_var_hard_resource: Resource
+var test_var_hard_this: TestMemberInfo
+var test_var_hard_my_class: RefCounted
+static func test_static_func() -> void
+func test_func_implicit_void() -> void
+func test_func_explicit_void() -> void
+func test_func_weak_null() -> Variant
+func test_func_weak_int() -> Variant
+func test_func_hard_variant() -> Variant
+func test_func_hard_int() -> int
+func test_func_args_1(_a: int, _b: Array[int], _c: int = 1, _d: Variant = 2) -> void
+func test_func_args_2(_a: Variant = 1, _b: Variant = null, _c: Variant = null, _d: Variant = 3) -> void
+signal test_signal_1()
+signal test_signal_2(a: Variant, b: Variant)
+signal test_signal_3(a: int, b: Array[int])
+signal test_signal_4(a: Variant.Type, b: Array[Variant.Type])
+signal test_signal_5(a: TestMemberInfo.MyEnum, b: Array[TestMemberInfo.MyEnum])
+signal test_signal_6(a: Resource, b: Array[Resource])
+signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo])
+signal test_signal_8(a: RefCounted, b: Array[RefCounted])
diff --git a/modules/gdscript/tests/scripts/runtime/features/metatypes.gd b/modules/gdscript/tests/scripts/runtime/features/metatypes.gd
new file mode 100644
index 0000000000..6c5df32ffe
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/metatypes.gd
@@ -0,0 +1,36 @@
+class MyClass:
+ const TEST = 10
+
+enum MyEnum {A, B, C}
+
+const Utils = preload("../../utils.notest.gd")
+const Other = preload("./metatypes.notest.gd")
+
+var test_native := JSON
+var test_script := Other
+var test_class := MyClass
+var test_enum := MyEnum
+
+func check_gdscript_native_class(value: Variant) -> void:
+ print(var_to_str(value).get_slice(",", 0).trim_prefix("Object("))
+
+func check_gdscript(value: GDScript) -> void:
+ print(value.get_class())
+
+func check_enum(value: Dictionary) -> void:
+ print(value)
+
+func test():
+ for property in get_property_list():
+ if str(property.name).begins_with("test_"):
+ print(Utils.get_property_signature(property))
+
+ check_gdscript_native_class(test_native)
+ check_gdscript(test_script)
+ check_gdscript(test_class)
+ check_enum(test_enum)
+
+ print(test_native.stringify([]))
+ print(test_script.TEST)
+ print(test_class.TEST)
+ print(test_enum.keys())
diff --git a/modules/gdscript/tests/scripts/runtime/features/metatypes.notest.gd b/modules/gdscript/tests/scripts/runtime/features/metatypes.notest.gd
new file mode 100644
index 0000000000..e6a591b927
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/metatypes.notest.gd
@@ -0,0 +1 @@
+const TEST = 100
diff --git a/modules/gdscript/tests/scripts/runtime/features/metatypes.out b/modules/gdscript/tests/scripts/runtime/features/metatypes.out
new file mode 100644
index 0000000000..352d1caa59
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/metatypes.out
@@ -0,0 +1,13 @@
+GDTEST_OK
+var test_native: GDScriptNativeClass
+var test_script: GDScript
+var test_class: GDScript
+var test_enum: Dictionary
+GDScriptNativeClass
+GDScript
+GDScript
+{ "A": 0, "B": 1, "C": 2 }
+[]
+100
+10
+["A", "B", "C"]
diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd
new file mode 100644
index 0000000000..fb20817117
--- /dev/null
+++ b/modules/gdscript/tests/scripts/utils.notest.gd
@@ -0,0 +1,281 @@
+static func get_type(property: Dictionary, is_return: bool = false) -> String:
+ match property.type:
+ TYPE_NIL:
+ if property.usage & PROPERTY_USAGE_NIL_IS_VARIANT:
+ return "Variant"
+ return "void" if is_return else "null"
+ TYPE_INT:
+ if property.usage & PROPERTY_USAGE_CLASS_IS_ENUM:
+ if property.class_name == &"":
+ return "<unknown enum>"
+ return property.class_name
+ TYPE_ARRAY:
+ if property.hint == PROPERTY_HINT_ARRAY_TYPE:
+ if str(property.hint_string).is_empty():
+ return "Array[<unknown type>]"
+ return "Array[%s]" % property.hint_string
+ TYPE_OBJECT:
+ if not str(property.class_name).is_empty():
+ return property.class_name
+ return variant_get_type_name(property.type)
+
+
+static func get_property_signature(property: Dictionary, is_static: bool = false) -> String:
+ var result: String = ""
+ if not (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE):
+ printerr("Missing `PROPERTY_USAGE_SCRIPT_VARIABLE` flag.")
+ if property.usage & PROPERTY_USAGE_DEFAULT:
+ result += "@export "
+ if is_static:
+ result += "static "
+ result += "var " + property.name + ": " + get_type(property)
+ return result
+
+
+static func get_property_additional_info(property: Dictionary) -> String:
+ return 'hint=%s hint_string="%s" usage=%s' % [
+ get_property_hint_name(property.hint).trim_prefix("PROPERTY_HINT_"),
+ str(property.hint_string).c_escape(),
+ get_property_usage_string(property.usage).replace("PROPERTY_USAGE_", ""),
+ ]
+
+
+static func get_method_signature(method: Dictionary, is_signal: bool = false) -> String:
+ var result: String = ""
+ if method.flags & METHOD_FLAG_STATIC:
+ result += "static "
+ result += ("signal " if is_signal else "func ") + method.name + "("
+
+ var args: Array[Dictionary] = method.args
+ var default_args: Array = method.default_args
+ var mandatory_argc: int = args.size() - default_args.size()
+ for i in args.size():
+ if i > 0:
+ result += ", "
+ var arg: Dictionary = args[i]
+ result += arg.name + ": " + get_type(arg)
+ if i >= mandatory_argc:
+ result += " = " + var_to_str(default_args[i - mandatory_argc])
+
+ result += ")"
+ if is_signal:
+ if get_type(method.return, true) != "void":
+ printerr("Signal return type must be `void`.")
+ else:
+ result += " -> " + get_type(method.return, true)
+ return result
+
+
+static func variant_get_type_name(type: Variant.Type) -> String:
+ match type:
+ TYPE_NIL:
+ return "Nil" # `Nil` in core, `null` in GDScript.
+ TYPE_BOOL:
+ return "bool"
+ TYPE_INT:
+ return "int"
+ TYPE_FLOAT:
+ return "float"
+ TYPE_STRING:
+ return "String"
+ TYPE_VECTOR2:
+ return "Vector2"
+ TYPE_VECTOR2I:
+ return "Vector2i"
+ TYPE_RECT2:
+ return "Rect2"
+ TYPE_RECT2I:
+ return "Rect2i"
+ TYPE_VECTOR3:
+ return "Vector3"
+ TYPE_VECTOR3I:
+ return "Vector3i"
+ TYPE_TRANSFORM2D:
+ return "Transform2D"
+ TYPE_VECTOR4:
+ return "Vector4"
+ TYPE_VECTOR4I:
+ return "Vector4i"
+ TYPE_PLANE:
+ return "Plane"
+ TYPE_QUATERNION:
+ return "Quaternion"
+ TYPE_AABB:
+ return "AABB"
+ TYPE_BASIS:
+ return "Basis"
+ TYPE_TRANSFORM3D:
+ return "Transform3D"
+ TYPE_PROJECTION:
+ return "Projection"
+ TYPE_COLOR:
+ return "Color"
+ TYPE_STRING_NAME:
+ return "StringName"
+ TYPE_NODE_PATH:
+ return "NodePath"
+ TYPE_RID:
+ return "RID"
+ TYPE_OBJECT:
+ return "Object"
+ TYPE_CALLABLE:
+ return "Callable"
+ TYPE_SIGNAL:
+ return "Signal"
+ TYPE_DICTIONARY:
+ return "Dictionary"
+ TYPE_ARRAY:
+ return "Array"
+ TYPE_PACKED_BYTE_ARRAY:
+ return "PackedByteArray"
+ TYPE_PACKED_INT32_ARRAY:
+ return "PackedInt32Array"
+ TYPE_PACKED_INT64_ARRAY:
+ return "PackedInt64Array"
+ TYPE_PACKED_FLOAT32_ARRAY:
+ return "PackedFloat32Array"
+ TYPE_PACKED_FLOAT64_ARRAY:
+ return "PackedFloat64Array"
+ TYPE_PACKED_STRING_ARRAY:
+ return "PackedStringArray"
+ TYPE_PACKED_VECTOR2_ARRAY:
+ return "PackedVector2Array"
+ TYPE_PACKED_VECTOR3_ARRAY:
+ return "PackedVector3Array"
+ TYPE_PACKED_COLOR_ARRAY:
+ return "PackedColorArray"
+ push_error("Argument `type` is invalid. Use `TYPE_*` constants.")
+ return "<invalid type>"
+
+
+static func get_property_hint_name(hint: PropertyHint) -> String:
+ match hint:
+ PROPERTY_HINT_NONE:
+ return "PROPERTY_HINT_NONE"
+ PROPERTY_HINT_RANGE:
+ return "PROPERTY_HINT_RANGE"
+ PROPERTY_HINT_ENUM:
+ return "PROPERTY_HINT_ENUM"
+ PROPERTY_HINT_ENUM_SUGGESTION:
+ return "PROPERTY_HINT_ENUM_SUGGESTION"
+ PROPERTY_HINT_EXP_EASING:
+ return "PROPERTY_HINT_EXP_EASING"
+ PROPERTY_HINT_LINK:
+ return "PROPERTY_HINT_LINK"
+ PROPERTY_HINT_FLAGS:
+ return "PROPERTY_HINT_FLAGS"
+ PROPERTY_HINT_LAYERS_2D_RENDER:
+ return "PROPERTY_HINT_LAYERS_2D_RENDER"
+ PROPERTY_HINT_LAYERS_2D_PHYSICS:
+ return "PROPERTY_HINT_LAYERS_2D_PHYSICS"
+ PROPERTY_HINT_LAYERS_2D_NAVIGATION:
+ return "PROPERTY_HINT_LAYERS_2D_NAVIGATION"
+ PROPERTY_HINT_LAYERS_3D_RENDER:
+ return "PROPERTY_HINT_LAYERS_3D_RENDER"
+ PROPERTY_HINT_LAYERS_3D_PHYSICS:
+ return "PROPERTY_HINT_LAYERS_3D_PHYSICS"
+ PROPERTY_HINT_LAYERS_3D_NAVIGATION:
+ return "PROPERTY_HINT_LAYERS_3D_NAVIGATION"
+ PROPERTY_HINT_LAYERS_AVOIDANCE:
+ return "PROPERTY_HINT_LAYERS_AVOIDANCE"
+ PROPERTY_HINT_FILE:
+ return "PROPERTY_HINT_FILE"
+ PROPERTY_HINT_DIR:
+ return "PROPERTY_HINT_DIR"
+ PROPERTY_HINT_GLOBAL_FILE:
+ return "PROPERTY_HINT_GLOBAL_FILE"
+ PROPERTY_HINT_GLOBAL_DIR:
+ return "PROPERTY_HINT_GLOBAL_DIR"
+ PROPERTY_HINT_RESOURCE_TYPE:
+ return "PROPERTY_HINT_RESOURCE_TYPE"
+ PROPERTY_HINT_MULTILINE_TEXT:
+ return "PROPERTY_HINT_MULTILINE_TEXT"
+ PROPERTY_HINT_EXPRESSION:
+ return "PROPERTY_HINT_EXPRESSION"
+ PROPERTY_HINT_PLACEHOLDER_TEXT:
+ return "PROPERTY_HINT_PLACEHOLDER_TEXT"
+ PROPERTY_HINT_COLOR_NO_ALPHA:
+ return "PROPERTY_HINT_COLOR_NO_ALPHA"
+ PROPERTY_HINT_OBJECT_ID:
+ return "PROPERTY_HINT_OBJECT_ID"
+ PROPERTY_HINT_TYPE_STRING:
+ return "PROPERTY_HINT_TYPE_STRING"
+ PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE:
+ return "PROPERTY_HINT_NODE_PATH_TO_EDITED_NODE"
+ PROPERTY_HINT_OBJECT_TOO_BIG:
+ return "PROPERTY_HINT_OBJECT_TOO_BIG"
+ PROPERTY_HINT_NODE_PATH_VALID_TYPES:
+ return "PROPERTY_HINT_NODE_PATH_VALID_TYPES"
+ PROPERTY_HINT_SAVE_FILE:
+ return "PROPERTY_HINT_SAVE_FILE"
+ PROPERTY_HINT_GLOBAL_SAVE_FILE:
+ return "PROPERTY_HINT_GLOBAL_SAVE_FILE"
+ PROPERTY_HINT_INT_IS_OBJECTID:
+ return "PROPERTY_HINT_INT_IS_OBJECTID"
+ PROPERTY_HINT_INT_IS_POINTER:
+ return "PROPERTY_HINT_INT_IS_POINTER"
+ PROPERTY_HINT_ARRAY_TYPE:
+ return "PROPERTY_HINT_ARRAY_TYPE"
+ PROPERTY_HINT_LOCALE_ID:
+ return "PROPERTY_HINT_LOCALE_ID"
+ PROPERTY_HINT_LOCALIZABLE_STRING:
+ return "PROPERTY_HINT_LOCALIZABLE_STRING"
+ PROPERTY_HINT_NODE_TYPE:
+ return "PROPERTY_HINT_NODE_TYPE"
+ PROPERTY_HINT_HIDE_QUATERNION_EDIT:
+ return "PROPERTY_HINT_HIDE_QUATERNION_EDIT"
+ PROPERTY_HINT_PASSWORD:
+ return "PROPERTY_HINT_PASSWORD"
+ push_error("Argument `hint` is invalid. Use `PROPERTY_HINT_*` constants.")
+ return "<invalid hint>"
+
+
+static func get_property_usage_string(usage: int) -> String:
+ if usage == PROPERTY_USAGE_NONE:
+ return "PROPERTY_USAGE_NONE"
+
+ const FLAGS: Array[Array] = [
+ [PROPERTY_USAGE_DEFAULT, "PROPERTY_USAGE_DEFAULT"],
+ [PROPERTY_USAGE_STORAGE, "PROPERTY_USAGE_STORAGE"],
+ [PROPERTY_USAGE_EDITOR, "PROPERTY_USAGE_EDITOR"],
+ [PROPERTY_USAGE_INTERNAL, "PROPERTY_USAGE_INTERNAL"],
+ [PROPERTY_USAGE_CHECKABLE, "PROPERTY_USAGE_CHECKABLE"],
+ [PROPERTY_USAGE_CHECKED, "PROPERTY_USAGE_CHECKED"],
+ [PROPERTY_USAGE_GROUP, "PROPERTY_USAGE_GROUP"],
+ [PROPERTY_USAGE_CATEGORY, "PROPERTY_USAGE_CATEGORY"],
+ [PROPERTY_USAGE_SUBGROUP, "PROPERTY_USAGE_SUBGROUP"],
+ [PROPERTY_USAGE_CLASS_IS_BITFIELD, "PROPERTY_USAGE_CLASS_IS_BITFIELD"],
+ [PROPERTY_USAGE_NO_INSTANCE_STATE, "PROPERTY_USAGE_NO_INSTANCE_STATE"],
+ [PROPERTY_USAGE_RESTART_IF_CHANGED, "PROPERTY_USAGE_RESTART_IF_CHANGED"],
+ [PROPERTY_USAGE_SCRIPT_VARIABLE, "PROPERTY_USAGE_SCRIPT_VARIABLE"],
+ [PROPERTY_USAGE_STORE_IF_NULL, "PROPERTY_USAGE_STORE_IF_NULL"],
+ [PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED, "PROPERTY_USAGE_UPDATE_ALL_IF_MODIFIED"],
+ [PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE, "PROPERTY_USAGE_SCRIPT_DEFAULT_VALUE"],
+ [PROPERTY_USAGE_CLASS_IS_ENUM, "PROPERTY_USAGE_CLASS_IS_ENUM"],
+ [PROPERTY_USAGE_NIL_IS_VARIANT, "PROPERTY_USAGE_NIL_IS_VARIANT"],
+ [PROPERTY_USAGE_ARRAY, "PROPERTY_USAGE_ARRAY"],
+ [PROPERTY_USAGE_ALWAYS_DUPLICATE, "PROPERTY_USAGE_ALWAYS_DUPLICATE"],
+ [PROPERTY_USAGE_NEVER_DUPLICATE, "PROPERTY_USAGE_NEVER_DUPLICATE"],
+ [PROPERTY_USAGE_HIGH_END_GFX, "PROPERTY_USAGE_HIGH_END_GFX"],
+ [PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT, "PROPERTY_USAGE_NODE_PATH_FROM_SCENE_ROOT"],
+ [PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT, "PROPERTY_USAGE_RESOURCE_NOT_PERSISTENT"],
+ [PROPERTY_USAGE_KEYING_INCREMENTS, "PROPERTY_USAGE_KEYING_INCREMENTS"],
+ [PROPERTY_USAGE_DEFERRED_SET_RESOURCE, "PROPERTY_USAGE_DEFERRED_SET_RESOURCE"],
+ [PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT, "PROPERTY_USAGE_EDITOR_INSTANTIATE_OBJECT"],
+ [PROPERTY_USAGE_EDITOR_BASIC_SETTING, "PROPERTY_USAGE_EDITOR_BASIC_SETTING"],
+ [PROPERTY_USAGE_READ_ONLY, "PROPERTY_USAGE_READ_ONLY"],
+ [PROPERTY_USAGE_SECRET, "PROPERTY_USAGE_SECRET"],
+ ]
+
+ var result: String = ""
+
+ for flag in FLAGS:
+ if usage & flag[0]:
+ result += flag[1] + "|"
+ usage &= ~flag[0]
+
+ if usage != PROPERTY_USAGE_NONE:
+ push_error("Argument `usage` is invalid. Use `PROPERTY_USAGE_*` constants.")
+ return "<invalid usage flags>"
+
+ return result.left(-1)
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index 0446a7aad6..b86a8b3cb1 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -138,12 +138,13 @@ static void recursively_disassemble_functions(const Ref<GDScript> script, const
for (const KeyValue<StringName, GDScriptFunction *> &E : script->get_member_functions()) {
const GDScriptFunction *func = E.value;
- String signature = "Disassembling " + func->get_name().operator String() + "(";
- for (int i = 0; i < func->get_argument_count(); i++) {
+ const MethodInfo &mi = func->get_method_info();
+ String signature = "Disassembling " + mi.name + "(";
+ for (int i = 0; i < mi.arguments.size(); i++) {
if (i > 0) {
signature += ", ";
}
- signature += func->get_argument_name(i);
+ signature += mi.arguments[i].name;
}
print_line(signature + ")");
#ifdef TOOLS_ENABLED
@@ -156,7 +157,7 @@ static void recursively_disassemble_functions(const Ref<GDScript> script, const
for (const KeyValue<StringName, Ref<GDScript>> &F : script->get_subclasses()) {
const Ref<GDScript> inner_script = F.value;
print_line("");
- print_line(vformat("Inner Class: %s", inner_script->get_script_class_name()));
+ print_line(vformat("Inner Class: %s", inner_script->get_local_name()));
print_line("");
recursively_disassemble_functions(inner_script, p_lines);
}
diff --git a/modules/gdscript/tests/test_lsp.h b/modules/gdscript/tests/test_lsp.h
new file mode 100644
index 0000000000..e57df00e2d
--- /dev/null
+++ b/modules/gdscript/tests/test_lsp.h
@@ -0,0 +1,480 @@
+/**************************************************************************/
+/* test_lsp.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_LSP_H
+#define TEST_LSP_H
+
+#ifdef TOOLS_ENABLED
+
+#include "tests/test_macros.h"
+
+#include "../language_server/gdscript_extend_parser.h"
+#include "../language_server/gdscript_language_protocol.h"
+#include "../language_server/gdscript_workspace.h"
+#include "../language_server/godot_lsp.h"
+
+#include "core/io/dir_access.h"
+#include "core/io/file_access_pack.h"
+#include "core/os/os.h"
+#include "editor/editor_help.h"
+#include "editor/editor_node.h"
+#include "modules/gdscript/gdscript_analyzer.h"
+#include "modules/regex/regex.h"
+
+#include "thirdparty/doctest/doctest.h"
+
+template <>
+struct doctest::StringMaker<lsp::Position> {
+ static doctest::String convert(const lsp::Position &p_val) {
+ return p_val.to_string().utf8().get_data();
+ }
+};
+
+template <>
+struct doctest::StringMaker<lsp::Range> {
+ static doctest::String convert(const lsp::Range &p_val) {
+ return p_val.to_string().utf8().get_data();
+ }
+};
+
+template <>
+struct doctest::StringMaker<GodotPosition> {
+ static doctest::String convert(const GodotPosition &p_val) {
+ return p_val.to_string().utf8().get_data();
+ }
+};
+
+namespace GDScriptTests {
+
+// LSP GDScript test scripts are located inside project of other GDScript tests:
+// Cannot reset `ProjectSettings` (singleton) -> Cannot load another workspace and resources in there.
+// -> Reuse GDScript test project. LSP specific scripts are then placed inside `lsp` folder.
+// Access via `res://lsp/my_script.notest.gd`.
+const String root = "modules/gdscript/tests/scripts/";
+
+/*
+ * After use:
+ * * `memdelete` returned `GDScriptLanguageProtocol`.
+ * * Call `GDScriptTests::::finish_language`.
+ */
+GDScriptLanguageProtocol *initialize(const String &p_root) {
+ Error err = OK;
+ Ref<DirAccess> dir(DirAccess::open(p_root, &err));
+ REQUIRE_MESSAGE(err == OK, "Could not open specified root directory");
+ String absolute_root = dir->get_current_dir();
+ init_language(absolute_root);
+
+ GDScriptLanguageProtocol *proto = memnew(GDScriptLanguageProtocol);
+
+ Ref<GDScriptWorkspace> workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace();
+ workspace->root = absolute_root;
+ // On windows: `C:/...` -> `C%3A/...`.
+ workspace->root_uri = "file:///" + absolute_root.lstrip("/").replace_first(":", "%3A");
+
+ return proto;
+}
+
+lsp::Position pos(const int p_line, const int p_character) {
+ lsp::Position p;
+ p.line = p_line;
+ p.character = p_character;
+ return p;
+}
+
+lsp::Range range(const lsp::Position p_start, const lsp::Position p_end) {
+ lsp::Range r;
+ r.start = p_start;
+ r.end = p_end;
+ return r;
+}
+
+lsp::TextDocumentPositionParams pos_in(const lsp::DocumentUri &p_uri, const lsp::Position p_pos) {
+ lsp::TextDocumentPositionParams params;
+ params.textDocument.uri = p_uri;
+ params.position = p_pos;
+ return params;
+}
+
+const lsp::DocumentSymbol *test_resolve_symbol_at(const String &p_uri, const lsp::Position p_pos, const String &p_expected_uri, const String &p_expected_name, const lsp::Range &p_expected_range) {
+ Ref<GDScriptWorkspace> workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace();
+
+ lsp::TextDocumentPositionParams params = pos_in(p_uri, p_pos);
+ const lsp::DocumentSymbol *symbol = workspace->resolve_symbol(params);
+ CHECK(symbol);
+
+ if (symbol) {
+ CHECK_EQ(symbol->uri, p_expected_uri);
+ CHECK_EQ(symbol->name, p_expected_name);
+ CHECK_EQ(symbol->selectionRange, p_expected_range);
+ }
+
+ return symbol;
+}
+
+struct InlineTestData {
+ lsp::Range range;
+ String text;
+ String name;
+ String ref;
+
+ static bool try_parse(const Vector<String> &p_lines, const int p_line_number, InlineTestData &r_data) {
+ String line = p_lines[p_line_number];
+
+ RegEx regex = RegEx("^\\t*#[ |]*(?<range>(?<left><)?\\^+)(\\s+(?<name>(?!->)\\S+))?(\\s+->\\s+(?<ref>\\S+))?");
+ Ref<RegExMatch> match = regex.search(line);
+ if (match.is_null()) {
+ return false;
+ }
+
+ // Find first line without leading comment above current line.
+ int target_line = p_line_number;
+ while (target_line >= 0) {
+ String dedented = p_lines[target_line].lstrip("\t");
+ if (!dedented.begins_with("#")) {
+ break;
+ }
+ target_line--;
+ }
+ if (target_line < 0) {
+ return false;
+ }
+ r_data.range.start.line = r_data.range.end.line = target_line;
+
+ String marker = match->get_string("range");
+ int i = line.find(marker);
+ REQUIRE(i >= 0);
+ r_data.range.start.character = i;
+ if (!match->get_string("left").is_empty()) {
+ // Include `#` (comment char) in range.
+ r_data.range.start.character--;
+ }
+ r_data.range.end.character = i + marker.length();
+
+ String target = p_lines[target_line];
+ r_data.text = target.substr(r_data.range.start.character, r_data.range.end.character - r_data.range.start.character);
+
+ r_data.name = match->get_string("name");
+ r_data.ref = match->get_string("ref");
+
+ return true;
+ }
+};
+
+Vector<InlineTestData> read_tests(const String &p_path) {
+ Error err;
+ String source = FileAccess::get_file_as_string(p_path, &err);
+ REQUIRE_MESSAGE(err == OK, vformat("Cannot read '%s'", p_path));
+
+ // Format:
+ // ```gdscript
+ // var foo = bar + baz
+ // # | | | | ^^^ name -> ref
+ // # | | ^^^ -> ref
+ // # ^^^ name
+ //
+ // func my_func():
+ // # ^^^^^^^ name
+ // var value = foo + 42
+ // # ^^^^^ name
+ // print(value)
+ // # ^^^^^ -> ref
+ // ```
+ //
+ // * `^`: Range marker.
+ // * `name`: Unique name. Can contain any characters except whitespace chars.
+ // * `ref`: Reference to unique name.
+ //
+ // Notes:
+ // * If range should include first content-char (which is occupied by `#`): use `<` for next marker.
+ // -> Range expands 1 to left (-> includes `#`).
+ // * Note: Means: Range cannot be single char directly marked by `#`, but must be at least two chars (marked with `#<`).
+ // * Comment must start at same ident as line its marked (-> because of tab alignment...).
+ // * Use spaces to align after `#`! -> for correct alignment
+ // * Between `#` and `^` can be spaces or `|` (to better visualize what's marked below).
+ PackedStringArray lines = source.split("\n");
+
+ PackedStringArray names;
+ Vector<InlineTestData> data;
+ for (int i = 0; i < lines.size(); i++) {
+ InlineTestData d;
+ if (InlineTestData::try_parse(lines, i, d)) {
+ if (!d.name.is_empty()) {
+ // Safety check: names must be unique.
+ if (names.find(d.name) != -1) {
+ FAIL(vformat("Duplicated name '%s' in '%s'. Names must be unique!", d.name, p_path));
+ }
+ names.append(d.name);
+ }
+
+ data.append(d);
+ }
+ }
+
+ return data;
+}
+
+void test_resolve_symbol(const String &p_uri, const InlineTestData &p_test_data, const Vector<InlineTestData> &p_all_data) {
+ if (p_test_data.ref.is_empty()) {
+ return;
+ }
+
+ SUBCASE(vformat("Can resolve symbol '%s' at %s to '%s'", p_test_data.text, p_test_data.range.to_string(), p_test_data.ref).utf8().get_data()) {
+ const InlineTestData *target = nullptr;
+ for (int i = 0; i < p_all_data.size(); i++) {
+ if (p_all_data[i].name == p_test_data.ref) {
+ target = &p_all_data[i];
+ break;
+ }
+ }
+ REQUIRE_MESSAGE(target, vformat("No target for ref '%s'", p_test_data.ref));
+
+ Ref<GDScriptWorkspace> workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace();
+ lsp::Position pos = p_test_data.range.start;
+
+ SUBCASE("start of identifier") {
+ pos.character = p_test_data.range.start.character;
+ test_resolve_symbol_at(p_uri, pos, p_uri, target->text, target->range);
+ }
+
+ SUBCASE("inside identifier") {
+ pos.character = (p_test_data.range.end.character + p_test_data.range.start.character) / 2;
+ test_resolve_symbol_at(p_uri, pos, p_uri, target->text, target->range);
+ }
+
+ SUBCASE("end of identifier") {
+ pos.character = p_test_data.range.end.character;
+ test_resolve_symbol_at(p_uri, pos, p_uri, target->text, target->range);
+ }
+ }
+}
+
+Vector<InlineTestData> filter_ref_towards(const Vector<InlineTestData> &p_data, const String &p_name) {
+ Vector<InlineTestData> res;
+
+ for (const InlineTestData &d : p_data) {
+ if (d.ref == p_name) {
+ res.append(d);
+ }
+ }
+
+ return res;
+}
+
+void test_resolve_symbols(const String &p_uri, const Vector<InlineTestData> &p_test_data, const Vector<InlineTestData> &p_all_data) {
+ for (const InlineTestData &d : p_test_data) {
+ test_resolve_symbol(p_uri, d, p_all_data);
+ }
+}
+
+void assert_no_errors_in(const String &p_path) {
+ Error err;
+ String source = FileAccess::get_file_as_string(p_path, &err);
+ REQUIRE_MESSAGE(err == OK, vformat("Cannot read '%s'", p_path));
+
+ GDScriptParser parser;
+ err = parser.parse(source, p_path, true);
+ REQUIRE_MESSAGE(err == OK, vformat("Errors while parsing '%s'", p_path));
+
+ GDScriptAnalyzer analyzer(&parser);
+ err = analyzer.analyze();
+ REQUIRE_MESSAGE(err == OK, vformat("Errors while analyzing '%s'", p_path));
+}
+
+inline lsp::Position lsp_pos(int line, int character) {
+ lsp::Position p;
+ p.line = line;
+ p.character = character;
+ return p;
+}
+
+void test_position_roundtrip(lsp::Position p_lsp, GodotPosition p_gd, const PackedStringArray &p_lines) {
+ GodotPosition actual_gd = GodotPosition::from_lsp(p_lsp, p_lines);
+ CHECK_EQ(p_gd, actual_gd);
+ lsp::Position actual_lsp = p_gd.to_lsp(p_lines);
+ CHECK_EQ(p_lsp, actual_lsp);
+}
+
+// Note:
+// * Cursor is BETWEEN chars
+// * `va|r` -> cursor between `a`&`r`
+// * `var`
+// ^
+// -> Character on `r` -> cursor between `a`&`r`s for tests:
+// * Line & Char:
+// * LSP: both 0-based
+// * Godot: both 1-based
+TEST_SUITE("[Modules][GDScript][LSP]") {
+ TEST_CASE("Can convert positions to and from Godot") {
+ String code = R"(extends Node
+
+var member := 42
+
+func f():
+ var value := 42
+ return value + member)";
+ PackedStringArray lines = code.split("\n");
+
+ SUBCASE("line after end") {
+ lsp::Position lsp = lsp_pos(7, 0);
+ GodotPosition gd(8, 1);
+ test_position_roundtrip(lsp, gd, lines);
+ }
+ SUBCASE("first char in first line") {
+ lsp::Position lsp = lsp_pos(0, 0);
+ GodotPosition gd(1, 1);
+ test_position_roundtrip(lsp, gd, lines);
+ }
+
+ SUBCASE("with tabs") {
+ // On `v` in `value` in `var value := ...`.
+ lsp::Position lsp = lsp_pos(5, 6);
+ GodotPosition gd(6, 13);
+ test_position_roundtrip(lsp, gd, lines);
+ }
+
+ SUBCASE("doesn't fail with column outside of character length") {
+ lsp::Position lsp = lsp_pos(2, 100);
+ GodotPosition::from_lsp(lsp, lines);
+
+ GodotPosition gd(3, 100);
+ gd.to_lsp(lines);
+ }
+
+ SUBCASE("doesn't fail with line outside of line length") {
+ lsp::Position lsp = lsp_pos(200, 100);
+ GodotPosition::from_lsp(lsp, lines);
+
+ GodotPosition gd(300, 100);
+ gd.to_lsp(lines);
+ }
+
+ SUBCASE("special case: negative line for root class") {
+ GodotPosition gd(-1, 0);
+ lsp::Position expected = lsp_pos(0, 0);
+ lsp::Position actual = gd.to_lsp(lines);
+ CHECK_EQ(actual, expected);
+ }
+ SUBCASE("special case: lines.length() + 1 for root class") {
+ GodotPosition gd(lines.size() + 1, 0);
+ lsp::Position expected = lsp_pos(lines.size(), 0);
+ lsp::Position actual = gd.to_lsp(lines);
+ CHECK_EQ(actual, expected);
+ }
+ }
+ TEST_CASE("[workspace][resolve_symbol]") {
+ GDScriptLanguageProtocol *proto = initialize(root);
+ REQUIRE(proto);
+ Ref<GDScriptWorkspace> workspace = GDScriptLanguageProtocol::get_singleton()->get_workspace();
+
+ {
+ String path = "res://lsp/local_variables.notest.gd";
+ assert_no_errors_in(path);
+ String uri = workspace->get_file_uri(path);
+ Vector<InlineTestData> all_test_data = read_tests(path);
+ SUBCASE("Can get correct ranges for public variables") {
+ Vector<InlineTestData> test_data = filter_ref_towards(all_test_data, "member");
+ test_resolve_symbols(uri, test_data, all_test_data);
+ }
+ SUBCASE("Can get correct ranges for local variables") {
+ Vector<InlineTestData> test_data = filter_ref_towards(all_test_data, "test");
+ test_resolve_symbols(uri, test_data, all_test_data);
+ }
+ SUBCASE("Can get correct ranges for local parameters") {
+ Vector<InlineTestData> test_data = filter_ref_towards(all_test_data, "arg");
+ test_resolve_symbols(uri, test_data, all_test_data);
+ }
+ }
+
+ SUBCASE("Can get correct ranges for indented variables") {
+ String path = "res://lsp/indentation.notest.gd";
+ assert_no_errors_in(path);
+ String uri = workspace->get_file_uri(path);
+ Vector<InlineTestData> all_test_data = read_tests(path);
+ test_resolve_symbols(uri, all_test_data, all_test_data);
+ }
+
+ SUBCASE("Can get correct ranges for scopes") {
+ String path = "res://lsp/scopes.notest.gd";
+ assert_no_errors_in(path);
+ String uri = workspace->get_file_uri(path);
+ Vector<InlineTestData> all_test_data = read_tests(path);
+ test_resolve_symbols(uri, all_test_data, all_test_data);
+ }
+
+ SUBCASE("Can get correct ranges for lambda") {
+ String path = "res://lsp/lambdas.notest.gd";
+ assert_no_errors_in(path);
+ String uri = workspace->get_file_uri(path);
+ Vector<InlineTestData> all_test_data = read_tests(path);
+ test_resolve_symbols(uri, all_test_data, all_test_data);
+ }
+
+ SUBCASE("Can get correct ranges for inner class") {
+ String path = "res://lsp/class.notest.gd";
+ assert_no_errors_in(path);
+ String uri = workspace->get_file_uri(path);
+ Vector<InlineTestData> all_test_data = read_tests(path);
+ test_resolve_symbols(uri, all_test_data, all_test_data);
+ }
+
+ SUBCASE("Can get correct ranges for inner class") {
+ String path = "res://lsp/enums.notest.gd";
+ assert_no_errors_in(path);
+ String uri = workspace->get_file_uri(path);
+ Vector<InlineTestData> all_test_data = read_tests(path);
+ test_resolve_symbols(uri, all_test_data, all_test_data);
+ }
+
+ SUBCASE("Can get correct ranges for shadowing & shadowed variables") {
+ String path = "res://lsp/shadowing_initializer.notest.gd";
+ assert_no_errors_in(path);
+ String uri = workspace->get_file_uri(path);
+ Vector<InlineTestData> all_test_data = read_tests(path);
+ test_resolve_symbols(uri, all_test_data, all_test_data);
+ }
+
+ SUBCASE("Can get correct ranges for properties and getter/setter") {
+ String path = "res://lsp/properties.notest.gd";
+ assert_no_errors_in(path);
+ String uri = workspace->get_file_uri(path);
+ Vector<InlineTestData> all_test_data = read_tests(path);
+ test_resolve_symbols(uri, all_test_data, all_test_data);
+ }
+
+ memdelete(proto);
+ finish_language();
+ }
+}
+
+} // namespace GDScriptTests
+
+#endif // TOOLS_ENABLED
+
+#endif // TEST_LSP_H
diff --git a/modules/gltf/doc_classes/GLTFDocument.xml b/modules/gltf/doc_classes/GLTFDocument.xml
index 9b760a997a..9b84397c7e 100644
--- a/modules/gltf/doc_classes/GLTFDocument.xml
+++ b/modules/gltf/doc_classes/GLTFDocument.xml
@@ -5,7 +5,7 @@
</brief_description>
<description>
GLTFDocument supports reading data from a glTF file, buffer, or Godot scene. This data can then be written to the filesystem, buffer, or used to create a Godot scene.
- All of the data in a GLTF scene is stored in the [GLTFState] class. GLTFDocument processes state objects, but does not contain any scene data itself.
+ All of the data in a GLTF scene is stored in the [GLTFState] class. GLTFDocument processes state objects, but does not contain any scene data itself. GLTFDocument has member variables to store export configuration settings such as the image format, but is otherwise stateless. Multiple scenes can be processed with the same settings using the same GLTFDocument object and different [GLTFState] objects.
GLTFDocument can be extended with arbitrary functionality by extending the [GLTFDocumentExtension] class and registering it with GLTFDocument via [method register_gltf_document_extension]. This allows for custom data to be imported and exported.
</description>
<tutorials>
@@ -87,4 +87,13 @@
</description>
</method>
</methods>
+ <members>
+ <member name="image_format" type="String" setter="set_image_format" getter="get_image_format" default="&quot;PNG&quot;">
+ The user-friendly name of the export image format. This is used when exporting the GLTF file, including writing to a file and writing to a byte array.
+ By default, Godot allows the following options: "None", "PNG", "JPEG", "Lossless WebP", and "Lossy WebP". Support for more image formats can be added in [GLTFDocumentExtension] classes.
+ </member>
+ <member name="lossy_quality" type="float" setter="set_lossy_quality" getter="get_lossy_quality" default="0.75">
+ If [member image_format] is a lossy image format, this determines the lossy quality of the image. On a range of [code]0.0[/code] to [code]1.0[/code], where [code]0.0[/code] is the lowest quality and [code]1.0[/code] is the highest quality. A lossy quality of [code]1.0[/code] is not the same as lossless.
+ </member>
+ </members>
</class>
diff --git a/modules/gltf/doc_classes/GLTFDocumentExtension.xml b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
index bae980fb56..dbfbf63da6 100644
--- a/modules/gltf/doc_classes/GLTFDocumentExtension.xml
+++ b/modules/gltf/doc_classes/GLTFDocumentExtension.xml
@@ -28,7 +28,7 @@
<param index="2" name="json" type="Dictionary" />
<param index="3" name="node" type="Node" />
<description>
- Part of the export process. This method is run after [method _export_preserialize] and before [method _export_post].
+ Part of the export process. This method is run after [method _get_saveable_image_formats] and before [method _export_post]. If this [GLTFDocumentExtension] is used for exporting images, this runs after [method _serialize_texture_json].
This method can be used to modify the final JSON of each node.
</description>
</method>
@@ -53,7 +53,7 @@
<return type="int" enum="Error" />
<param index="0" name="state" type="GLTFState" />
<description>
- Part of the export process. This method is run after [method _convert_scene_node] and before [method _export_node].
+ Part of the export process. This method is run after [method _convert_scene_node] and before [method _get_saveable_image_formats].
This method can be used to alter the state before performing serialization. It runs every time when generating a buffer with [method GLTFDocument.generate_buffer] or writing to the file system with [method GLTFDocument.write_to_filesystem].
</description>
</method>
@@ -63,7 +63,7 @@
<param index="1" name="gltf_node" type="GLTFNode" />
<param index="2" name="scene_parent" type="Node" />
<description>
- Part of the import process. This method is run after [method _parse_node_extensions] and before [method _import_post_parse].
+ Part of the import process. This method is run after [method _import_post_parse] and before [method _import_node].
Runs when generating a Godot scene node from a GLTFNode. The returned node will be added to the scene tree. Multiple nodes can be generated in this step if they are added as a child of the returned node.
</description>
</method>
@@ -73,6 +73,13 @@
Returns the file extension to use for saving image data into, for example, [code]".png"[/code]. If defined, when this extension is used to handle images, and the images are saved to a separate file, the image bytes will be copied to a file with this extension. If this is set, there should be a [ResourceImporter] class able to import the file. If not defined or empty, Godot will save the image into a PNG file.
</description>
</method>
+ <method name="_get_saveable_image_formats" qualifiers="virtual">
+ <return type="PackedStringArray" />
+ <description>
+ Part of the export process. This method is run after [method _convert_scene_node] and before [method _export_node].
+ Returns an array of the image formats that can be saved/exported by this extension. This extension will only be selected as the image exporter if the [GLTFDocument]'s [member GLTFDocument.image_format] is in this array. If this [GLTFDocumentExtension] is selected as the image exporter, one of the [method _save_image_at_path] or [method _serialize_image_to_bytes] methods will run next, otherwise [method _export_node] will run next. If the format name contains [code]"Lossy"[/code], the lossy quality slider will be displayed.
+ </description>
+ </method>
<method name="_get_supported_extensions" qualifiers="virtual">
<return type="PackedStringArray" />
<description>
@@ -87,7 +94,7 @@
<param index="2" name="json" type="Dictionary" />
<param index="3" name="node" type="Node" />
<description>
- Part of the import process. This method is run after [method _import_post_parse] and before [method _import_post].
+ Part of the import process. This method is run after [method _generate_scene_node] and before [method _import_post].
This method can be used to make modifications to each of the generated Godot scene nodes.
</description>
</method>
@@ -104,7 +111,7 @@
<return type="int" enum="Error" />
<param index="0" name="state" type="GLTFState" />
<description>
- Part of the import process. This method is run after [method _generate_scene_node] and before [method _import_node].
+ Part of the import process. This method is run after [method _parse_node_extensions] and before [method _generate_scene_node].
This method can be used to modify any of the data imported so far, including any scene nodes, before running the final per-node import step.
</description>
</method>
@@ -134,7 +141,7 @@
<param index="1" name="gltf_node" type="GLTFNode" />
<param index="2" name="extensions" type="Dictionary" />
<description>
- Part of the import process. This method is run after [method _get_supported_extensions] and before [method _generate_scene_node].
+ Part of the import process. This method is run after [method _get_supported_extensions] and before [method _import_post_parse].
Runs when parsing the node extensions of a GLTFNode. This method can be used to process the extension JSON data into a format that can be used by [method _generate_scene_node]. The return value should be a member of the [enum Error] enum.
</description>
</method>
@@ -148,5 +155,41 @@
Runs when parsing the texture JSON from the GLTF textures array. This can be used to set the source image index to use as the texture.
</description>
</method>
+ <method name="_save_image_at_path" qualifiers="virtual">
+ <return type="int" enum="Error" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="image" type="Image" />
+ <param index="2" name="file_path" type="String" />
+ <param index="3" name="image_format" type="String" />
+ <param index="4" name="lossy_quality" type="float" />
+ <description>
+ Part of the export process. This method is run after [method _get_saveable_image_formats] and before [method _serialize_texture_json].
+ This method is run when saving images separately from the GLTF file. When images are embedded, [method _serialize_image_to_bytes] runs instead. Note that these methods only run when this [GLTFDocumentExtension] is selected as the image exporter.
+ </description>
+ </method>
+ <method name="_serialize_image_to_bytes" qualifiers="virtual">
+ <return type="PackedByteArray" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="image" type="Image" />
+ <param index="2" name="image_dict" type="Dictionary" />
+ <param index="3" name="image_format" type="String" />
+ <param index="4" name="lossy_quality" type="float" />
+ <description>
+ Part of the export process. This method is run after [method _get_saveable_image_formats] and before [method _serialize_texture_json].
+ This method is run when embedding images in the GLTF file. When images are saved separately, [method _save_image_at_path] runs instead. Note that these methods only run when this [GLTFDocumentExtension] is selected as the image exporter.
+ This method must set the image MIME type in the [param image_dict] with the [code]"mimeType"[/code] key. For example, for a PNG image, it would be set to [code]"image/png"[/code]. The return value must be a [PackedByteArray] containing the image data.
+ </description>
+ </method>
+ <method name="_serialize_texture_json" qualifiers="virtual">
+ <return type="int" enum="Error" />
+ <param index="0" name="state" type="GLTFState" />
+ <param index="1" name="texture_json" type="Dictionary" />
+ <param index="2" name="gltf_texture" type="GLTFTexture" />
+ <param index="3" name="image_format" type="String" />
+ <description>
+ Part of the export process. This method is run after [method _save_image_at_path] or [method _serialize_image_to_bytes], and before [method _export_node]. Note that this method only runs when this [GLTFDocumentExtension] is selected as the image exporter.
+ This method can be used to set up the extensions for the texture JSON by editing [param texture_json]. The extension must also be added as used extension with [method GLTFState.add_used_extension], be sure to set [code]required[/code] to [code]true[/code] if you are not providing a fallback.
+ </description>
+ </method>
</methods>
</class>
diff --git a/modules/gltf/extensions/gltf_document_extension.cpp b/modules/gltf/extensions/gltf_document_extension.cpp
index 11718ba78a..e16e366692 100644
--- a/modules/gltf/extensions/gltf_document_extension.cpp
+++ b/modules/gltf/extensions/gltf_document_extension.cpp
@@ -46,6 +46,10 @@ void GLTFDocumentExtension::_bind_methods() {
GDVIRTUAL_BIND(_export_preflight, "state", "root");
GDVIRTUAL_BIND(_convert_scene_node, "state", "gltf_node", "scene_node");
GDVIRTUAL_BIND(_export_preserialize, "state");
+ GDVIRTUAL_BIND(_get_saveable_image_formats);
+ GDVIRTUAL_BIND(_serialize_image_to_bytes, "state", "image", "image_dict", "image_format", "lossy_quality");
+ GDVIRTUAL_BIND(_save_image_at_path, "state", "image", "file_path", "image_format", "lossy_quality");
+ GDVIRTUAL_BIND(_serialize_texture_json, "state", "texture_json", "gltf_texture", "image_format");
GDVIRTUAL_BIND(_export_node, "state", "gltf_node", "json", "node");
GDVIRTUAL_BIND(_export_post, "state");
}
@@ -149,6 +153,36 @@ Error GLTFDocumentExtension::export_preserialize(Ref<GLTFState> p_state) {
return err;
}
+Vector<String> GLTFDocumentExtension::get_saveable_image_formats() {
+ Vector<String> ret;
+ GDVIRTUAL_CALL(_get_saveable_image_formats, ret);
+ return ret;
+}
+
+PackedByteArray GLTFDocumentExtension::serialize_image_to_bytes(Ref<GLTFState> p_state, Ref<Image> p_image, Dictionary p_image_dict, const String &p_image_format, float p_lossy_quality) {
+ PackedByteArray ret;
+ ERR_FAIL_NULL_V(p_state, ret);
+ ERR_FAIL_NULL_V(p_image, ret);
+ GDVIRTUAL_CALL(_serialize_image_to_bytes, p_state, p_image, p_image_dict, p_image_format, p_lossy_quality, ret);
+ return ret;
+}
+
+Error GLTFDocumentExtension::save_image_at_path(Ref<GLTFState> p_state, Ref<Image> p_image, const String &p_file_path, const String &p_image_format, float p_lossy_quality) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_image, ERR_INVALID_PARAMETER);
+ Error ret = OK;
+ GDVIRTUAL_CALL(_save_image_at_path, p_state, p_image, p_file_path, p_image_format, p_lossy_quality, ret);
+ return ret;
+}
+
+Error GLTFDocumentExtension::serialize_texture_json(Ref<GLTFState> p_state, Dictionary p_texture_json, Ref<GLTFTexture> p_gltf_texture, const String &p_image_format) {
+ ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
+ ERR_FAIL_NULL_V(p_gltf_texture, ERR_INVALID_PARAMETER);
+ Error err = OK;
+ GDVIRTUAL_CALL(_serialize_texture_json, p_state, p_texture_json, p_gltf_texture, p_image_format, err);
+ return err;
+}
+
Error GLTFDocumentExtension::export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_dict, Node *p_node) {
ERR_FAIL_NULL_V(p_state, ERR_INVALID_PARAMETER);
ERR_FAIL_NULL_V(p_gltf_node, ERR_INVALID_PARAMETER);
diff --git a/modules/gltf/extensions/gltf_document_extension.h b/modules/gltf/extensions/gltf_document_extension.h
index 0a631bb6c5..512b7aba91 100644
--- a/modules/gltf/extensions/gltf_document_extension.h
+++ b/modules/gltf/extensions/gltf_document_extension.h
@@ -47,14 +47,18 @@ public:
virtual Error parse_image_data(Ref<GLTFState> p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref<Image> r_image);
virtual String get_image_file_extension();
virtual Error parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture);
- virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
virtual Error import_post_parse(Ref<GLTFState> p_state);
+ virtual Node3D *generate_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_parent);
virtual Error import_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
virtual Error import_post(Ref<GLTFState> p_state, Node *p_node);
// Export process.
virtual Error export_preflight(Ref<GLTFState> p_state, Node *p_root);
virtual void convert_scene_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Node *p_scene_node);
virtual Error export_preserialize(Ref<GLTFState> p_state);
+ virtual Vector<String> get_saveable_image_formats();
+ virtual PackedByteArray serialize_image_to_bytes(Ref<GLTFState> p_state, Ref<Image> p_image, Dictionary p_image_dict, const String &p_image_format, float p_lossy_quality);
+ virtual Error save_image_at_path(Ref<GLTFState> p_state, Ref<Image> p_image, const String &p_file_path, const String &p_image_format, float p_lossy_quality);
+ virtual Error serialize_texture_json(Ref<GLTFState> p_state, Dictionary p_texture_json, Ref<GLTFTexture> p_gltf_texture, const String &p_image_format);
virtual Error export_node(Ref<GLTFState> p_state, Ref<GLTFNode> p_gltf_node, Dictionary &r_json, Node *p_node);
virtual Error export_post(Ref<GLTFState> p_state);
@@ -73,6 +77,10 @@ public:
GDVIRTUAL2R(Error, _export_preflight, Ref<GLTFState>, Node *);
GDVIRTUAL3(_convert_scene_node, Ref<GLTFState>, Ref<GLTFNode>, Node *);
GDVIRTUAL1R(Error, _export_preserialize, Ref<GLTFState>);
+ GDVIRTUAL0R(Vector<String>, _get_saveable_image_formats);
+ GDVIRTUAL5R(PackedByteArray, _serialize_image_to_bytes, Ref<GLTFState>, Ref<Image>, Dictionary, String, float);
+ GDVIRTUAL5R(Error, _save_image_at_path, Ref<GLTFState>, Ref<Image>, String, String, float);
+ GDVIRTUAL4R(Error, _serialize_texture_json, Ref<GLTFState>, Dictionary, Ref<GLTFTexture>, String);
GDVIRTUAL4R(Error, _export_node, Ref<GLTFState>, Ref<GLTFNode>, Dictionary, Node *);
GDVIRTUAL1R(Error, _export_post, Ref<GLTFState>);
};
diff --git a/modules/gltf/extensions/gltf_document_extension_texture_webp.cpp b/modules/gltf/extensions/gltf_document_extension_texture_webp.cpp
index 73c869be3b..f8bd6d57cf 100644
--- a/modules/gltf/extensions/gltf_document_extension_texture_webp.cpp
+++ b/modules/gltf/extensions/gltf_document_extension_texture_webp.cpp
@@ -68,3 +68,42 @@ Error GLTFDocumentExtensionTextureWebP::parse_texture_json(Ref<GLTFState> p_stat
r_gltf_texture->set_src_image(texture_webp["source"]);
return OK;
}
+
+Vector<String> GLTFDocumentExtensionTextureWebP::get_saveable_image_formats() {
+ Vector<String> ret;
+ ret.push_back("Lossless WebP");
+ ret.push_back("Lossy WebP");
+ return ret;
+}
+
+PackedByteArray GLTFDocumentExtensionTextureWebP::serialize_image_to_bytes(Ref<GLTFState> p_state, Ref<Image> p_image, Dictionary p_image_dict, const String &p_image_format, float p_lossy_quality) {
+ if (p_image_format == "Lossless WebP") {
+ p_image_dict["mimeType"] = "image/webp";
+ return p_image->save_webp_to_buffer(false);
+ } else if (p_image_format == "Lossy WebP") {
+ p_image_dict["mimeType"] = "image/webp";
+ return p_image->save_webp_to_buffer(true, p_lossy_quality);
+ }
+ ERR_FAIL_V(PackedByteArray());
+}
+
+Error GLTFDocumentExtensionTextureWebP::save_image_at_path(Ref<GLTFState> p_state, Ref<Image> p_image, const String &p_file_path, const String &p_image_format, float p_lossy_quality) {
+ if (p_image_format == "Lossless WebP") {
+ p_image->save_webp(p_file_path, false);
+ return OK;
+ } else if (p_image_format == "Lossy WebP") {
+ p_image->save_webp(p_file_path, true, p_lossy_quality);
+ return OK;
+ }
+ return ERR_INVALID_PARAMETER;
+}
+
+Error GLTFDocumentExtensionTextureWebP::serialize_texture_json(Ref<GLTFState> p_state, Dictionary p_texture_json, Ref<GLTFTexture> p_gltf_texture, const String &p_image_format) {
+ Dictionary ext_texture_webp;
+ ext_texture_webp["source"] = p_gltf_texture->get_src_image();
+ Dictionary texture_extensions;
+ texture_extensions["EXT_texture_webp"] = ext_texture_webp;
+ p_texture_json["extensions"] = texture_extensions;
+ p_state->add_used_extension("EXT_texture_webp", true);
+ return OK;
+}
diff --git a/modules/gltf/extensions/gltf_document_extension_texture_webp.h b/modules/gltf/extensions/gltf_document_extension_texture_webp.h
index d2654aae8c..2113bd4768 100644
--- a/modules/gltf/extensions/gltf_document_extension_texture_webp.h
+++ b/modules/gltf/extensions/gltf_document_extension_texture_webp.h
@@ -43,6 +43,11 @@ public:
Error parse_image_data(Ref<GLTFState> p_state, const PackedByteArray &p_image_data, const String &p_mime_type, Ref<Image> r_image) override;
String get_image_file_extension() override;
Error parse_texture_json(Ref<GLTFState> p_state, const Dictionary &p_texture_json, Ref<GLTFTexture> r_gltf_texture) override;
+ // Export process.
+ Vector<String> get_saveable_image_formats() override;
+ PackedByteArray serialize_image_to_bytes(Ref<GLTFState> p_state, Ref<Image> p_image, Dictionary p_image_dict, const String &p_image_format, float p_lossy_quality) override;
+ Error save_image_at_path(Ref<GLTFState> p_state, Ref<Image> p_image, const String &p_full_path, const String &p_image_format, float p_lossy_quality) override;
+ Error serialize_texture_json(Ref<GLTFState> p_state, Dictionary p_texture_json, Ref<GLTFTexture> p_gltf_texture, const String &p_image_format) override;
};
#endif // GLTF_DOCUMENT_EXTENSION_TEXTURE_WEBP_H
diff --git a/modules/gltf/gltf_document.cpp b/modules/gltf/gltf_document.cpp
index 984052d2ca..e98b83359d 100644
--- a/modules/gltf/gltf_document.cpp
+++ b/modules/gltf/gltf_document.cpp
@@ -42,7 +42,6 @@
#include "core/io/stream_peer.h"
#include "core/math/disjoint_set.h"
#include "core/version.h"
-#include "drivers/png/png_driver_common.h"
#include "scene/3d/bone_attachment_3d.h"
#include "scene/3d/camera_3d.h"
#include "scene/3d/importer_mesh_instance_3d.h"
@@ -3001,8 +3000,35 @@ Error GLTFDocument::_parse_meshes(Ref<GLTFState> p_state) {
return OK;
}
+void GLTFDocument::set_image_format(const String &p_image_format) {
+ _image_format = p_image_format;
+}
+
+String GLTFDocument::get_image_format() const {
+ return _image_format;
+}
+
+void GLTFDocument::set_lossy_quality(float p_lossy_quality) {
+ _lossy_quality = p_lossy_quality;
+}
+
+float GLTFDocument::get_lossy_quality() const {
+ return _lossy_quality;
+}
+
Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state) {
Array images;
+ // Check if any extension wants to be the image saver.
+ _image_save_extension = Ref<GLTFDocumentExtension>();
+ for (Ref<GLTFDocumentExtension> ext : document_extensions) {
+ ERR_CONTINUE(ext.is_null());
+ Vector<String> image_formats = ext->get_saveable_image_formats();
+ if (image_formats.has(_image_format)) {
+ _image_save_extension = ext;
+ break;
+ }
+ }
+ // Serialize every image in the state's images array.
for (int i = 0; i < p_state->images.size(); i++) {
Dictionary image_dict;
@@ -3010,6 +3036,10 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state) {
Ref<Image> image = p_state->images[i]->get_image();
ERR_CONTINUE(image.is_null());
+ if (image->is_compressed()) {
+ image->decompress();
+ ERR_FAIL_COND_V_MSG(image->is_compressed(), ERR_INVALID_DATA, "GLTF: Image was compressed, but could not be decompressed.");
+ }
if (p_state->filename.to_lower().ends_with("gltf")) {
String img_name = p_state->images[i]->get_name();
@@ -3017,14 +3047,26 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state) {
img_name = itos(i);
}
img_name = _gen_unique_name(p_state, img_name);
- img_name = img_name.pad_zeros(3) + ".png";
+ img_name = img_name.pad_zeros(3);
String relative_texture_dir = "textures";
String full_texture_dir = p_state->base_path.path_join(relative_texture_dir);
Ref<DirAccess> da = DirAccess::open(p_state->base_path);
if (!da->dir_exists(full_texture_dir)) {
da->make_dir(full_texture_dir);
}
- image->save_png(full_texture_dir.path_join(img_name));
+ if (_image_save_extension.is_valid()) {
+ img_name = img_name + _image_save_extension->get_image_file_extension();
+ Error err = _image_save_extension->save_image_at_path(p_state, image, full_texture_dir.path_join(img_name), _image_format, _lossy_quality);
+ ERR_FAIL_COND_V_MSG(err != OK, err, "GLTF: Failed to save image in '" + _image_format + "' format as a separate file.");
+ } else if (_image_format == "PNG") {
+ img_name = img_name + ".png";
+ image->save_png(full_texture_dir.path_join(img_name));
+ } else if (_image_format == "JPEG") {
+ img_name = img_name + ".jpg";
+ image->save_jpg(full_texture_dir.path_join(img_name), _lossy_quality);
+ } else {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "GLTF: Unknown image format '" + _image_format + "'.");
+ }
image_dict["uri"] = relative_texture_dir.path_join(img_name).uri_encode();
} else {
GLTFBufferViewIndex bvi;
@@ -3042,8 +3084,20 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state) {
if (img_tex.is_valid()) {
image = img_tex->get_image();
}
- Error err = PNGDriverCommon::image_to_png(image, buffer);
- ERR_FAIL_COND_V_MSG(err, err, "Can't convert image to PNG.");
+ // Save in various image formats. Note that if the format is "None",
+ // the state's images will be empty, so this code will not be reached.
+ if (_image_save_extension.is_valid()) {
+ buffer = _image_save_extension->serialize_image_to_bytes(p_state, image, image_dict, _image_format, _lossy_quality);
+ } else if (_image_format == "PNG") {
+ buffer = image->save_png_to_buffer();
+ image_dict["mimeType"] = "image/png";
+ } else if (_image_format == "JPEG") {
+ buffer = image->save_jpg_to_buffer(_lossy_quality);
+ image_dict["mimeType"] = "image/jpeg";
+ } else {
+ ERR_FAIL_V_MSG(ERR_UNAVAILABLE, "GLTF: Unknown image format '" + _image_format + "'.");
+ }
+ ERR_FAIL_COND_V_MSG(buffer.is_empty(), ERR_INVALID_DATA, "GLTF: Failed to save image in '" + _image_format + "' format.");
bv->byte_length = buffer.size();
p_state->buffers.write[bi].resize(p_state->buffers[bi].size() + bv->byte_length);
@@ -3053,7 +3107,6 @@ Error GLTFDocument::_serialize_images(Ref<GLTFState> p_state) {
p_state->buffer_views.push_back(bv);
bvi = p_state->buffer_views.size() - 1;
image_dict["bufferView"] = bvi;
- image_dict["mimeType"] = "image/png";
}
images.push_back(image_dict);
}
@@ -3332,9 +3385,13 @@ Error GLTFDocument::_serialize_textures(Ref<GLTFState> p_state) {
for (int32_t i = 0; i < p_state->textures.size(); i++) {
Dictionary texture_dict;
Ref<GLTFTexture> gltf_texture = p_state->textures[i];
- ERR_CONTINUE(gltf_texture->get_src_image() == -1);
- texture_dict["source"] = gltf_texture->get_src_image();
-
+ if (_image_save_extension.is_valid()) {
+ Error err = _image_save_extension->serialize_texture_json(p_state, texture_dict, gltf_texture, _image_format);
+ ERR_FAIL_COND_V(err != OK, err);
+ } else {
+ ERR_CONTINUE(gltf_texture->get_src_image() == -1);
+ texture_dict["source"] = gltf_texture->get_src_image();
+ }
GLTFTextureSamplerIndex sampler_index = gltf_texture->get_sampler();
if (sampler_index != -1) {
texture_dict["sampler"] = sampler_index;
@@ -3543,7 +3600,7 @@ Error GLTFDocument::_serialize_materials(Ref<GLTFState> p_state) {
arr.push_back(c.a);
mr["baseColorFactor"] = arr;
}
- {
+ if (_image_format != "None") {
Dictionary bct;
Ref<Texture2D> albedo_texture = base_material->get_texture(BaseMaterial3D::TEXTURE_ALBEDO);
GLTFTextureIndex gltf_texture_index = -1;
@@ -5280,7 +5337,7 @@ void GLTFDocument::_assign_node_names(Ref<GLTFState> p_state) {
if (gltf_node->mesh >= 0) {
gltf_node_name = "Mesh";
} else if (gltf_node->camera >= 0) {
- gltf_node_name = "Camera3D";
+ gltf_node_name = "Camera";
} else {
gltf_node_name = "Node";
}
@@ -5821,6 +5878,10 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, const GLTFNodeIn
current_node = _generate_spatial(p_state, p_node_index);
}
}
+ String gltf_node_name = gltf_node->get_name();
+ if (!gltf_node_name.is_empty()) {
+ current_node->set_name(gltf_node_name);
+ }
// Add the node we generated and set the owner to the scene root.
p_scene_parent->add_child(current_node, true);
if (current_node != p_scene_root) {
@@ -5829,7 +5890,6 @@ void GLTFDocument::_generate_scene_node(Ref<GLTFState> p_state, const GLTFNodeIn
current_node->propagate_call(StringName("set_owner"), args);
}
current_node->set_transform(gltf_node->xform);
- current_node->set_name(gltf_node->get_name());
p_state->scene_nodes.insert(p_node_index, current_node);
for (int i = 0; i < gltf_node->children.size(); ++i) {
@@ -6443,7 +6503,7 @@ float GLTFDocument::get_max_component(const Color &p_color) {
return MAX(MAX(r, g), b);
}
-void GLTFDocument::_process_mesh_instances(Ref<GLTFState> p_state, Node *p_scene_root) {
+void GLTFDocument::_process_mesh_instances(Ref<GLTFState> p_state) {
for (GLTFNodeIndex node_i = 0; node_i < p_state->nodes.size(); ++node_i) {
Ref<GLTFNode> node = p_state->nodes[node_i];
@@ -7158,6 +7218,14 @@ void GLTFDocument::_bind_methods() {
ClassDB::bind_method(D_METHOD("write_to_filesystem", "state", "path"),
&GLTFDocument::write_to_filesystem);
+ ClassDB::bind_method(D_METHOD("set_image_format", "image_format"), &GLTFDocument::set_image_format);
+ ClassDB::bind_method(D_METHOD("get_image_format"), &GLTFDocument::get_image_format);
+ ClassDB::bind_method(D_METHOD("set_lossy_quality", "lossy_quality"), &GLTFDocument::set_lossy_quality);
+ ClassDB::bind_method(D_METHOD("get_lossy_quality"), &GLTFDocument::get_lossy_quality);
+
+ ADD_PROPERTY(PropertyInfo(Variant::STRING, "image_format"), "set_image_format", "get_image_format");
+ ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "lossy_quality"), "set_lossy_quality", "get_lossy_quality");
+
ClassDB::bind_static_method("GLTFDocument", D_METHOD("register_gltf_document_extension", "extension", "first_priority"),
&GLTFDocument::register_gltf_document_extension, DEFVAL(false));
ClassDB::bind_static_method("GLTFDocument", D_METHOD("unregister_gltf_document_extension", "extension"),
@@ -7266,15 +7334,28 @@ Error GLTFDocument::write_to_filesystem(Ref<GLTFState> p_state, const String &p_
return OK;
}
+Node *GLTFDocument::_generate_scene_node_tree(Ref<GLTFState> p_state) {
+ Node *single_root = memnew(Node3D);
+ for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) {
+ _generate_scene_node(p_state, p_state->root_nodes[root_i], single_root, single_root);
+ }
+ // Assign the scene name and single root name to each other
+ // if one is missing, or do nothing if both are already set.
+ if (unlikely(p_state->scene_name.is_empty())) {
+ p_state->scene_name = single_root->get_name();
+ } else if (single_root->get_name() == StringName()) {
+ single_root->set_name(_gen_unique_name(p_state, p_state->scene_name));
+ }
+ return single_root;
+}
+
Node *GLTFDocument::generate_scene(Ref<GLTFState> p_state, float p_bake_fps, bool p_trimming, bool p_remove_immutable_tracks) {
ERR_FAIL_NULL_V(p_state, nullptr);
ERR_FAIL_INDEX_V(0, p_state->root_nodes.size(), nullptr);
Error err = OK;
- GLTFNodeIndex gltf_root = p_state->root_nodes.write[0];
- Node *gltf_root_node = p_state->get_scene_node(gltf_root);
- Node *root = gltf_root_node->get_parent();
+ Node *root = _generate_scene_node_tree(p_state);
ERR_FAIL_NULL_V(root, nullptr);
- _process_mesh_instances(p_state, root);
+ _process_mesh_instances(p_state);
if (p_state->get_create_animations() && p_state->animations.size()) {
AnimationPlayer *ap = memnew(AnimationPlayer);
root->add_child(ap, true);
@@ -7454,11 +7535,6 @@ Error GLTFDocument::_parse_gltf_state(Ref<GLTFState> p_state, const String &p_se
/* ASSIGN SCENE NAMES */
_assign_node_names(p_state);
- Node3D *root = memnew(Node3D);
- for (int32_t root_i = 0; root_i < p_state->root_nodes.size(); root_i++) {
- _generate_scene_node(p_state, p_state->root_nodes[root_i], root, root);
- }
-
return OK;
}
diff --git a/modules/gltf/gltf_document.h b/modules/gltf/gltf_document.h
index f2e36a0457..febe04b55f 100644
--- a/modules/gltf/gltf_document.h
+++ b/modules/gltf/gltf_document.h
@@ -42,6 +42,9 @@ class GLTFDocument : public Resource {
private:
const float BAKE_FPS = 30.0f;
+ String _image_format = "PNG";
+ float _lossy_quality = 0.75f;
+ Ref<GLTFDocumentExtension> _image_save_extension;
public:
const int32_t JOINT_GROUP_SIZE = 4;
@@ -77,6 +80,11 @@ public:
static void unregister_gltf_document_extension(Ref<GLTFDocumentExtension> p_extension);
static void unregister_all_gltf_document_extensions();
+ void set_image_format(const String &p_image_format);
+ String get_image_format() const;
+ void set_lossy_quality(float p_lossy_quality);
+ float get_lossy_quality() const;
+
private:
void _build_parent_hierachy(Ref<GLTFState> p_state);
double _filter_number(double p_float);
@@ -306,7 +314,8 @@ public:
Error _parse_gltf_state(Ref<GLTFState> p_state, const String &p_search_path);
Error _parse_asset_header(Ref<GLTFState> p_state);
Error _parse_gltf_extensions(Ref<GLTFState> p_state);
- void _process_mesh_instances(Ref<GLTFState> p_state, Node *p_scene_root);
+ void _process_mesh_instances(Ref<GLTFState> p_state);
+ Node *_generate_scene_node_tree(Ref<GLTFState> p_state);
void _generate_scene_node(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root);
void _generate_skeleton_bone_node(Ref<GLTFState> p_state, const GLTFNodeIndex p_node_index, Node *p_scene_parent, Node *p_scene_root);
void _import_animation(Ref<GLTFState> p_state, AnimationPlayer *p_animation_player,
diff --git a/modules/gridmap/editor/grid_map_editor_plugin.cpp b/modules/gridmap/editor/grid_map_editor_plugin.cpp
index f96cc86142..6a20768583 100644
--- a/modules/gridmap/editor/grid_map_editor_plugin.cpp
+++ b/modules/gridmap/editor/grid_map_editor_plugin.cpp
@@ -749,6 +749,7 @@ EditorPlugin::AfterGUIInput GridMapEditor::forward_spatial_input_event(Camera3D
for (int i = 0; i < options->get_popup()->get_item_count(); ++i) {
const Ref<Shortcut> &shortcut = options->get_popup()->get_item_shortcut(i);
if (shortcut.is_valid() && shortcut->matches_event(p_event)) {
+ accept_event();
_menu_option(options->get_popup()->get_item_id(i));
return EditorPlugin::AFTER_GUI_INPUT_STOP;
}
diff --git a/modules/gridmap/grid_map.cpp b/modules/gridmap/grid_map.cpp
index 4ac143c7ff..6f493f48e3 100644
--- a/modules/gridmap/grid_map.cpp
+++ b/modules/gridmap/grid_map.cpp
@@ -267,6 +267,7 @@ void GridMap::set_mesh_library(const Ref<MeshLibrary> &p_mesh_library) {
}
_recreate_octant_data();
+ emit_signal(CoreStringNames::get_singleton()->changed);
}
Ref<MeshLibrary> GridMap::get_mesh_library() const {
diff --git a/modules/lightmapper_rd/lightmapper_rd.cpp b/modules/lightmapper_rd/lightmapper_rd.cpp
index 748e8ae50c..4ed730b3af 100644
--- a/modules/lightmapper_rd/lightmapper_rd.cpp
+++ b/modules/lightmapper_rd/lightmapper_rd.cpp
@@ -589,8 +589,12 @@ void LightmapperRD::_raster_geometry(RenderingDevice *rd, Size2i atlas_size, int
raster_push_constant.grid_size[0] = grid_size;
raster_push_constant.grid_size[1] = grid_size;
raster_push_constant.grid_size[2] = grid_size;
- raster_push_constant.uv_offset[0] = 0;
- raster_push_constant.uv_offset[1] = 0;
+
+ // Half pixel offset is required so the rasterizer doesn't output face edges directly aligned into pixels.
+ // This fixes artifacts where the pixel would be traced from the edge of a face, causing half the rays to
+ // be outside of the boundaries of the geometry. See <https://github.com/godotengine/godot/issues/69126>.
+ raster_push_constant.uv_offset[0] = -0.5f / float(atlas_size.x);
+ raster_push_constant.uv_offset[1] = -0.5f / float(atlas_size.y);
RD::DrawListID draw_list = rd->draw_list_begin(framebuffers[i], RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_READ, RD::INITIAL_ACTION_CLEAR, RD::FINAL_ACTION_DISCARD, clear_colors);
//draw opaque
@@ -1579,8 +1583,8 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
{
seams_push_constant.base_index = seam_offset;
rd->draw_list_bind_render_pipeline(draw_list, blendseams_line_raster_pipeline);
- seams_push_constant.uv_offset[0] = uv_offsets[0].x / float(atlas_size.width);
- seams_push_constant.uv_offset[1] = uv_offsets[0].y / float(atlas_size.height);
+ seams_push_constant.uv_offset[0] = (uv_offsets[0].x - 0.5f) / float(atlas_size.width);
+ seams_push_constant.uv_offset[1] = (uv_offsets[0].y - 0.5f) / float(atlas_size.height);
seams_push_constant.blend = uv_offsets[0].z;
rd->draw_list_set_push_constant(draw_list, &seams_push_constant, sizeof(RasterSeamsPushConstant));
@@ -1603,8 +1607,8 @@ LightmapperRD::BakeError LightmapperRD::bake(BakeQuality p_quality, bool p_use_d
for (int j = 1; j < uv_offset_count; j++) {
seams_push_constant.base_index = seam_offset;
- seams_push_constant.uv_offset[0] = uv_offsets[j].x / float(atlas_size.width);
- seams_push_constant.uv_offset[1] = uv_offsets[j].y / float(atlas_size.height);
+ seams_push_constant.uv_offset[0] = (uv_offsets[j].x - 0.5f) / float(atlas_size.width);
+ seams_push_constant.uv_offset[1] = (uv_offsets[j].y - 0.5f) / float(atlas_size.height);
seams_push_constant.blend = uv_offsets[0].z;
rd->draw_list_set_push_constant(draw_list, &seams_push_constant, sizeof(RasterSeamsPushConstant));
diff --git a/modules/lightmapper_rd/lm_compute.glsl b/modules/lightmapper_rd/lm_compute.glsl
index c2557dfed3..4d3f2d46a4 100644
--- a/modules/lightmapper_rd/lm_compute.glsl
+++ b/modules/lightmapper_rd/lm_compute.glsl
@@ -415,7 +415,7 @@ void main() {
);
for (uint j = 0; j < 4; j++) {
- sh_accum[j].rgb += light * c[j] * (1.0 / 3.0);
+ sh_accum[j].rgb += light * c[j] * 8.0;
}
#endif
diff --git a/modules/mono/csharp_script.cpp b/modules/mono/csharp_script.cpp
index 9e23a27093..26c684f769 100644
--- a/modules/mono/csharp_script.cpp
+++ b/modules/mono/csharp_script.cpp
@@ -435,6 +435,11 @@ static String variant_type_to_managed_name(const String &p_var_type_name) {
return "Collections.Dictionary";
}
+ if (p_var_type_name.begins_with(Variant::get_type_name(Variant::ARRAY) + "[")) {
+ String element_type = p_var_type_name.trim_prefix(Variant::get_type_name(Variant::ARRAY) + "[").trim_suffix("]");
+ return "Collections.Array<" + variant_type_to_managed_name(element_type) + ">";
+ }
+
if (p_var_type_name == Variant::get_type_name(Variant::ARRAY)) {
return "Collections.Array";
}
@@ -2348,6 +2353,8 @@ void CSharpScript::update_script_class_info(Ref<CSharpScript> p_script) {
mi.arguments.push_back(arg_info);
}
+ mi.flags = (uint32_t)method_info_dict["flags"];
+
p_script->methods.set(push_index++, CSharpMethodInfo{ name, mi });
}
@@ -2597,6 +2604,18 @@ MethodInfo CSharpScript::get_method_info(const StringName &p_method) const {
return MethodInfo();
}
+Variant CSharpScript::callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) {
+ ERR_FAIL_COND_V(!valid, Variant());
+
+ Variant ret;
+ bool ok = GDMonoCache::managed_callbacks.ScriptManagerBridge_CallStatic(this, &p_method, p_args, p_argcount, &r_error, &ret);
+ if (ok) {
+ return ret;
+ }
+
+ return Script::callp(p_method, p_args, p_argcount, r_error);
+}
+
Error CSharpScript::reload(bool p_keep_state) {
if (!reload_invalidated) {
return OK;
diff --git a/modules/mono/csharp_script.h b/modules/mono/csharp_script.h
index 33862016a4..fd9e281e63 100644
--- a/modules/mono/csharp_script.h
+++ b/modules/mono/csharp_script.h
@@ -199,6 +199,7 @@ public:
void get_script_method_list(List<MethodInfo> *p_list) const override;
bool has_method(const StringName &p_method) const override;
MethodInfo get_method_info(const StringName &p_method) const override;
+ Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error) override;
int get_member_line(const StringName &p_member) const override;
diff --git a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
index 5ea0ca53c3..7b643914bb 100644
--- a/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
+++ b/modules/mono/editor/Godot.NET.Sdk/Godot.SourceGenerators/ScriptMethodsGenerator.cs
@@ -125,7 +125,7 @@ namespace Godot.SourceGenerators
var members = symbol.GetMembers();
var methodSymbols = members
- .Where(s => !s.IsStatic && s.Kind == SymbolKind.Method && !s.IsImplicitlyDeclared)
+ .Where(s => s.Kind == SymbolKind.Method && !s.IsImplicitlyDeclared)
.Cast<IMethodSymbol>()
.Where(m => m.MethodKind == MethodKind.Ordinary);
@@ -221,6 +221,29 @@ namespace Godot.SourceGenerators
source.Append(" }\n");
}
+ // Generate InvokeGodotClassStaticMethod
+
+ var godotClassStaticMethods = godotClassMethods.Where(m => m.Method.IsStatic).ToArray();
+
+ if (godotClassStaticMethods.Length > 0)
+ {
+ source.Append("#pragma warning disable CS0109 // Disable warning about redundant 'new' keyword\n");
+ source.Append(" [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)]\n");
+ source.Append(" internal new static bool InvokeGodotClassStaticMethod(in godot_string_name method, ");
+ source.Append("NativeVariantPtrArgs args, out godot_variant ret)\n {\n");
+
+ foreach (var method in godotClassStaticMethods)
+ {
+ GenerateMethodInvoker(method, source);
+ }
+
+ source.Append(" ret = default;\n");
+ source.Append(" return false;\n");
+ source.Append(" }\n");
+
+ source.Append("#pragma warning restore CS0109\n");
+ }
+
// Generate HasGodotClassMethod
if (distinctMethodNames.Length > 0)
@@ -356,7 +379,14 @@ namespace Godot.SourceGenerators
arguments = null;
}
- return new MethodInfo(method.Method.Name, returnVal, MethodFlags.Default, arguments,
+ MethodFlags flags = MethodFlags.Default;
+
+ if (method.Method.IsStatic)
+ {
+ flags |= MethodFlags.Static;
+ }
+
+ return new MethodInfo(method.Method.Name, returnVal, flags, arguments,
defaultArguments: null);
}
diff --git a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
index f01fbbd1b9..e186c0302b 100644
--- a/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/GodotSharpEditor.cs
@@ -190,6 +190,9 @@ namespace GodotTools
case ExternalEditorId.CustomEditor:
{
string file = ProjectSettings.GlobalizePath(script.ResourcePath);
+ string project = ProjectSettings.GlobalizePath("res://");
+ // Since ProjectSettings.GlobalizePath replaces only "res:/", leaving a trailing slash, it is removed here.
+ project = project[..^1];
var execCommand = _editorSettings.GetSetting(Settings.CustomExecPath).As<string>();
var execArgs = _editorSettings.GetSetting(Settings.CustomExecPathArgs).As<string>();
var args = new List<string>();
@@ -226,6 +229,7 @@ namespace GodotTools
hasFileFlag = true;
}
+ arg = arg.ReplaceN("{project}", project);
arg = arg.ReplaceN("{file}", file);
args.Add(arg);
@@ -499,7 +503,7 @@ namespace GodotTools
_toolBarBuildButton = new Button
{
Flat = true,
- Icon = editorBaseControl.GetThemeIcon("BuildCSharp", "EditorIcons"),
+ Icon = EditorInterface.Singleton.GetEditorTheme().GetIcon("BuildCSharp", "EditorIcons"),
FocusMode = Control.FocusModeEnum.None,
Shortcut = EditorDefShortcut("mono/build_solution", "Build Project".TTR(), (Key)KeyModifierMask.MaskAlt | Key.B),
ShortcutInTooltip = true,
diff --git a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
index fbbd01dafd..a0ab381b9b 100644
--- a/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
+++ b/modules/mono/editor/GodotTools/GodotTools/Ides/Rider/RiderPathManager.cs
@@ -5,10 +5,14 @@ using Godot;
using GodotTools.Internals;
using JetBrains.Rider.PathLocator;
+#nullable enable
+
namespace GodotTools.Ides.Rider
{
public static class RiderPathManager
{
+ private const string EditorPathSettingName = "dotnet/editor/editor_path_optional";
+
private static readonly RiderPathLocator RiderPathLocator;
private static readonly RiderFileOpener RiderFileOpener;
@@ -19,13 +23,14 @@ namespace GodotTools.Ides.Rider
RiderFileOpener = new RiderFileOpener(riderLocatorEnvironment);
}
- public static readonly string EditorPathSettingName = "dotnet/editor/editor_path_optional";
-
- private static string GetRiderPathFromSettings()
+ private static string? GetRiderPathFromSettings()
{
var editorSettings = EditorInterface.Singleton.GetEditorSettings();
if (editorSettings.HasSetting(EditorPathSettingName))
+ {
return (string)editorSettings.GetSetting(EditorPathSettingName);
+ }
+
return null;
}
@@ -37,7 +42,7 @@ namespace GodotTools.Ides.Rider
{
if (!editorSettings.HasSetting(EditorPathSettingName))
{
- Globals.EditorDef(EditorPathSettingName, "Optional");
+ Globals.EditorDef(EditorPathSettingName, "");
editorSettings.AddPropertyInfo(new Godot.Collections.Dictionary
{
["type"] = (int)Variant.Type.String,
@@ -55,9 +60,10 @@ namespace GodotTools.Ides.Rider
}
var paths = RiderPathLocator.GetAllRiderPaths();
-
- if (!paths.Any())
+ if (paths.Length == 0)
+ {
return;
+ }
string newPath = paths.Last().Path;
Globals.EditorDef(EditorPathSettingName, newPath);
@@ -67,18 +73,16 @@ namespace GodotTools.Ides.Rider
public static bool IsRider(string path)
{
- if (string.IsNullOrEmpty(path))
- return false;
-
if (path.IndexOfAny(Path.GetInvalidPathChars()) != -1)
+ {
return false;
+ }
var fileInfo = new FileInfo(path);
- string filename = fileInfo.Name.ToLowerInvariant();
- return filename.StartsWith("rider", StringComparison.Ordinal);
+ return fileInfo.Name.StartsWith("rider", StringComparison.OrdinalIgnoreCase);
}
- private static string CheckAndUpdatePath(string riderPath)
+ private static string? CheckAndUpdatePath(string? riderPath)
{
if (File.Exists(riderPath))
{
@@ -87,11 +91,14 @@ namespace GodotTools.Ides.Rider
var allInfos = RiderPathLocator.GetAllRiderPaths();
if (allInfos.Length == 0)
+ {
return null;
- var riderInfos = allInfos.Where(info => IsRider(info.Path)).ToArray();
- string newPath = riderInfos.Length > 0
- ? riderInfos[riderInfos.Length - 1].Path
- : allInfos[allInfos.Length - 1].Path;
+ }
+
+ // RiderPathLocator includes Rider and Fleet locations, prefer Rider when available.
+ var preferredInfo = allInfos.LastOrDefault(info => IsRider(info.Path), allInfos[allInfos.Length - 1]);
+ string newPath = preferredInfo.Path;
+
var editorSettings = EditorInterface.Singleton.GetEditorSettings();
editorSettings.SetSetting(EditorPathSettingName, newPath);
Globals.EditorDef(EditorPathSettingName, newPath);
@@ -100,8 +107,14 @@ namespace GodotTools.Ides.Rider
public static void OpenFile(string slnPath, string scriptPath, int line, int column)
{
- string pathFromSettings = GetRiderPathFromSettings();
- string path = CheckAndUpdatePath(pathFromSettings);
+ string? pathFromSettings = GetRiderPathFromSettings();
+ string? path = CheckAndUpdatePath(pathFromSettings);
+ if (string.IsNullOrEmpty(path))
+ {
+ GD.PushError($"Error when trying to run code editor: JetBrains Rider or Fleet. Could not find path to the editor.");
+ return;
+ }
+
RiderFileOpener.OpenFile(path, slnPath, scriptPath, line, column);
}
}
diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp
index 9b41f9cd1b..839846f963 100644
--- a/modules/mono/editor/bindings_generator.cpp
+++ b/modules/mono/editor/bindings_generator.cpp
@@ -989,9 +989,6 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append("namespace " BINDINGS_NAMESPACE ";\n\n");
- p_output.append("\n#pragma warning disable CS1591 // Disable warning: "
- "'Missing XML comment for publicly visible type or member'\n");
-
p_output.append("public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n{");
for (const ConstantInterface &iconstant : global_constants) {
@@ -1089,8 +1086,6 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
p_output.append(CLOSE_BLOCK);
}
}
-
- p_output.append("\n#pragma warning restore CS1591\n");
}
Error BindingsGenerator::generate_cs_core_project(const String &p_proj_dir) {
@@ -1406,12 +1401,6 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append("using System.Diagnostics;\n"); // DebuggerBrowsable
output.append("using Godot.NativeInterop;\n");
- output.append("\n"
- "#pragma warning disable CS1591 // Disable warning: "
- "'Missing XML comment for publicly visible type or member'\n"
- "#pragma warning disable CS1573 // Disable warning: "
- "'Parameter has no matching param tag in the XML comment'\n");
-
output.append("\n#nullable disable\n");
const DocData::ClassDoc *class_doc = itype.class_doc;
@@ -1904,10 +1893,6 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
output.append(CLOSE_BLOCK /* class */);
- output.append("\n"
- "#pragma warning restore CS1591\n"
- "#pragma warning restore CS1573\n");
-
return _save_file(p_output_file, output);
}
diff --git a/modules/mono/editor/hostfxr_resolver.cpp b/modules/mono/editor/hostfxr_resolver.cpp
index 04bd6a9207..4f15335c1e 100644
--- a/modules/mono/editor/hostfxr_resolver.cpp
+++ b/modules/mono/editor/hostfxr_resolver.cpp
@@ -320,7 +320,12 @@ bool get_dotnet_root_from_env(String &r_dotnet_root) {
bool godotsharp::hostfxr_resolver::try_get_path_from_dotnet_root(const String &p_dotnet_root, String &r_fxr_path) {
String fxr_dir = path::join(p_dotnet_root, "host", "fxr");
- ERR_FAIL_COND_V_MSG(!DirAccess::exists(fxr_dir), false, "The host fxr folder does not exist: " + fxr_dir);
+ if (!DirAccess::exists(fxr_dir)) {
+ if (OS::get_singleton()->is_stdout_verbose()) {
+ ERR_PRINT("The host fxr folder does not exist: " + fxr_dir + ".");
+ }
+ return false;
+ }
return get_latest_fxr(fxr_dir, r_fxr_path);
}
diff --git a/modules/mono/glue/GodotSharp/.editorconfig b/modules/mono/glue/GodotSharp/.editorconfig
index d4e71b1bd9..df4a6c2d0d 100644
--- a/modules/mono/glue/GodotSharp/.editorconfig
+++ b/modules/mono/glue/GodotSharp/.editorconfig
@@ -1,8 +1,17 @@
[**/Generated/**.cs]
-# Validate parameter is non-null before using it
+# CA1062: Validate parameter is non-null before using it
# Useful for generated code, as it disables nullable
dotnet_diagnostic.CA1062.severity = error
# CA1069: Enums should not have duplicate values
dotnet_diagnostic.CA1069.severity = none
# CA1708: Identifiers should differ by more than case
dotnet_diagnostic.CA1708.severity = none
+# CS1591: Missing XML comment for publicly visible type or member
+dotnet_diagnostic.CS1591.severity = none
+# CS1573: Parameter has no matching param tag in the XML comment
+dotnet_diagnostic.CS1573.severity = none
+
+[GodotSharp/Core/**.cs]
+# CS1591: Missing XML comment for publicly visible type or member
+# TODO: Temporary change to not pollute the warnings, but we need to document public APIs
+dotnet_diagnostic.CS1591.severity = suggestion
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
index 109643c2d4..5d6583b404 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ManagedCallbacks.cs
@@ -29,6 +29,7 @@ namespace Godot.Bridge
public delegate* unmanaged<IntPtr, IntPtr*, godot_bool, godot_bool> ScriptManagerBridge_SwapGCHandleForType;
public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, godot_string*, void*, int, void>, void> ScriptManagerBridge_GetPropertyInfoList;
public delegate* unmanaged<IntPtr, delegate* unmanaged<IntPtr, void*, int, void>, void> ScriptManagerBridge_GetPropertyDefaultValues;
+ public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_variant_call_error*, godot_variant*, godot_bool> ScriptManagerBridge_CallStatic;
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant**, int, godot_variant_call_error*, godot_variant*, godot_bool> CSharpInstanceBridge_Call;
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Set;
public delegate* unmanaged<IntPtr, godot_string_name*, godot_variant*, godot_bool> CSharpInstanceBridge_Get;
@@ -70,6 +71,7 @@ namespace Godot.Bridge
ScriptManagerBridge_SwapGCHandleForType = &ScriptManagerBridge.SwapGCHandleForType,
ScriptManagerBridge_GetPropertyInfoList = &ScriptManagerBridge.GetPropertyInfoList,
ScriptManagerBridge_GetPropertyDefaultValues = &ScriptManagerBridge.GetPropertyDefaultValues,
+ ScriptManagerBridge_CallStatic = &ScriptManagerBridge.CallStatic,
CSharpInstanceBridge_Call = &CSharpInstanceBridge.Call,
CSharpInstanceBridge_Set = &CSharpInstanceBridge.Set,
CSharpInstanceBridge_Get = &CSharpInstanceBridge.Get,
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
index 0fe4bcdfce..1a7d2d9075 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Bridge/ScriptManagerBridge.cs
@@ -90,7 +90,7 @@ namespace Godot.Bridge
internal static unsafe IntPtr CreateManagedForGodotObjectBinding(godot_string_name* nativeTypeName,
IntPtr godotObject)
{
- // TODO: Optimize with source generators and delegate pointers
+ // TODO: Optimize with source generators and delegate pointers.
try
{
@@ -124,7 +124,7 @@ namespace Godot.Bridge
IntPtr godotObject,
godot_variant** args, int argCount)
{
- // TODO: Optimize with source generators and delegate pointers
+ // TODO: Optimize with source generators and delegate pointers.
try
{
@@ -677,6 +677,8 @@ namespace Godot.Bridge
methodInfo.Add("params", methodParams);
+ methodInfo.Add("flags", (int)method.Flags);
+
methods.Add(methodInfo);
}
}
@@ -958,6 +960,54 @@ namespace Godot.Bridge
public godot_variant Value; // Not owned
}
+ private delegate bool InvokeGodotClassStaticMethodDelegate(in godot_string_name method, NativeVariantPtrArgs args, out godot_variant ret);
+
+ [UnmanagedCallersOnly]
+ internal static unsafe godot_bool CallStatic(IntPtr scriptPtr, godot_string_name* method,
+ godot_variant** args, int argCount, godot_variant_call_error* refCallError, godot_variant* ret)
+ {
+ // TODO: Optimize with source generators and delegate pointers.
+
+ try
+ {
+ Type scriptType = _scriptTypeBiMap.GetScriptType(scriptPtr);
+
+ Type? top = scriptType;
+ Type native = GodotObject.InternalGetClassNativeBase(top);
+
+ while (top != null && top != native)
+ {
+ var invokeGodotClassStaticMethod = top.GetMethod(
+ "InvokeGodotClassStaticMethod",
+ BindingFlags.DeclaredOnly | BindingFlags.Static |
+ BindingFlags.NonPublic | BindingFlags.Public);
+
+ if (invokeGodotClassStaticMethod != null)
+ {
+ var invoked = invokeGodotClassStaticMethod.CreateDelegate<InvokeGodotClassStaticMethodDelegate>()(
+ CustomUnsafe.AsRef(method), new NativeVariantPtrArgs(args, argCount), out godot_variant retValue);
+ if (invoked)
+ {
+ *ret = retValue;
+ return godot_bool.True;
+ }
+ }
+
+ top = top.BaseType;
+ }
+ }
+ catch (Exception e)
+ {
+ ExceptionUtils.LogException(e);
+ *ret = default;
+ return godot_bool.False;
+ }
+
+ *ret = default;
+ (*refCallError).Error = godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD;
+ return godot_bool.False;
+ }
+
[UnmanagedCallersOnly]
internal static unsafe void GetPropertyDefaultValues(IntPtr scriptPtr,
delegate* unmanaged<IntPtr, void*, int, void> addDefValFunc)
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
index 231e791904..b5ff744c55 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector2I.cs
@@ -182,6 +182,9 @@ namespace Godot
}
// Constants
+ private static readonly Vector2I _min = new Vector2I(int.MinValue, int.MinValue);
+ private static readonly Vector2I _max = new Vector2I(int.MaxValue, int.MaxValue);
+
private static readonly Vector2I _zero = new Vector2I(0, 0);
private static readonly Vector2I _one = new Vector2I(1, 1);
@@ -191,6 +194,17 @@ namespace Godot
private static readonly Vector2I _left = new Vector2I(-1, 0);
/// <summary>
+ /// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector2.Inf"/>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector2I(int.MinValue, int.MinValue)</c>.</value>
+ public static Vector2I Min { get { return _min; } }
+ /// <summary>
+ /// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector2.Inf"/>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector2I(int.MaxValue, int.MaxValue)</c>.</value>
+ public static Vector2I Max { get { return _max; } }
+
+ /// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
/// </summary>
/// <value>Equivalent to <c>new Vector2I(0, 0)</c>.</value>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
index 8543052f56..62aa02e512 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector3I.cs
@@ -193,6 +193,9 @@ namespace Godot
}
// Constants
+ private static readonly Vector3I _min = new Vector3I(int.MinValue, int.MinValue, int.MinValue);
+ private static readonly Vector3I _max = new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue);
+
private static readonly Vector3I _zero = new Vector3I(0, 0, 0);
private static readonly Vector3I _one = new Vector3I(1, 1, 1);
@@ -204,6 +207,17 @@ namespace Godot
private static readonly Vector3I _back = new Vector3I(0, 0, 1);
/// <summary>
+ /// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector3.Inf"/>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector3I(int.MinValue, int.MinValue, int.MinValue)</c>.</value>
+ public static Vector3I Min { get { return _min; } }
+ /// <summary>
+ /// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector3.Inf"/>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector3I(int.MaxValue, int.MaxValue, int.MaxValue)</c>.</value>
+ public static Vector3I Max { get { return _max; } }
+
+ /// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
/// </summary>
/// <value>Equivalent to <c>new Vector3I(0, 0, 0)</c>.</value>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
index f813903177..56c1df4c64 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
+++ b/modules/mono/glue/GodotSharp/GodotSharp/Core/Vector4I.cs
@@ -228,10 +228,24 @@ namespace Godot
}
// Constants
+ private static readonly Vector4I _min = new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue);
+ private static readonly Vector4I _max = new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue);
+
private static readonly Vector4I _zero = new Vector4I(0, 0, 0, 0);
private static readonly Vector4I _one = new Vector4I(1, 1, 1, 1);
/// <summary>
+ /// Min vector, a vector with all components equal to <see cref="int.MinValue"/>. Can be used as a negative integer equivalent of <see cref="Vector4.Inf"/>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector4I(int.MinValue, int.MinValue, int.MinValue, int.MinValue)</c>.</value>
+ public static Vector4I Min { get { return _min; } }
+ /// <summary>
+ /// Max vector, a vector with all components equal to <see cref="int.MaxValue"/>. Can be used as an integer equivalent of <see cref="Vector4.Inf"/>.
+ /// </summary>
+ /// <value>Equivalent to <c>new Vector4I(int.MaxValue, int.MaxValue, int.MaxValue, int.MaxValue)</c>.</value>
+ public static Vector4I Max { get { return _max; } }
+
+ /// <summary>
/// Zero vector, a vector with all components set to <c>0</c>.
/// </summary>
/// <value>Equivalent to <c>new Vector4I(0, 0, 0, 0)</c>.</value>
diff --git a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
index 8a36b3e514..a55b8d693b 100644
--- a/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
+++ b/modules/mono/glue/GodotSharp/GodotSharp/GodotSharp.csproj
@@ -11,9 +11,6 @@
<LangVersion>10</LangVersion>
<AnalysisMode>Recommended</AnalysisMode>
-
- <!-- Disabled temporarily as it pollutes the warnings, but we need to document public APIs. -->
- <NoWarn>CS1591</NoWarn>
</PropertyGroup>
<PropertyGroup>
<Description>Godot C# Core API.</Description>
diff --git a/modules/mono/mono_gd/gd_mono_cache.cpp b/modules/mono/mono_gd/gd_mono_cache.cpp
index 8fdf163b26..5a1f90fa1d 100644
--- a/modules/mono/mono_gd/gd_mono_cache.cpp
+++ b/modules/mono/mono_gd/gd_mono_cache.cpp
@@ -70,6 +70,7 @@ void update_godot_api_cache(const ManagedCallbacks &p_managed_callbacks) {
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, SwapGCHandleForType);
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyInfoList);
CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, GetPropertyDefaultValues);
+ CHECK_CALLBACK_NOT_NULL(ScriptManagerBridge, CallStatic);
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Call);
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Set);
CHECK_CALLBACK_NOT_NULL(CSharpInstanceBridge, Get);
diff --git a/modules/mono/mono_gd/gd_mono_cache.h b/modules/mono/mono_gd/gd_mono_cache.h
index f604e4d681..6ddc688ea0 100644
--- a/modules/mono/mono_gd/gd_mono_cache.h
+++ b/modules/mono/mono_gd/gd_mono_cache.h
@@ -95,6 +95,7 @@ struct ManagedCallbacks {
using FuncScriptManagerBridge_SwapGCHandleForType = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, GCHandleIntPtr *, bool);
using FuncScriptManagerBridge_GetPropertyInfoList = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyInfoList_Add);
using FuncScriptManagerBridge_GetPropertyDefaultValues = void(GD_CLR_STDCALL *)(CSharpScript *, Callback_ScriptManagerBridge_GetPropertyDefaultValues_Add);
+ using FuncScriptManagerBridge_CallStatic = bool(GD_CLR_STDCALL *)(const CSharpScript *, const StringName *, const Variant **, int32_t, Callable::CallError *, Variant *);
using FuncCSharpInstanceBridge_Call = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant **, int32_t, Callable::CallError *, Variant *);
using FuncCSharpInstanceBridge_Set = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, const Variant *);
using FuncCSharpInstanceBridge_Get = bool(GD_CLR_STDCALL *)(GCHandleIntPtr, const StringName *, Variant *);
@@ -130,6 +131,7 @@ struct ManagedCallbacks {
FuncScriptManagerBridge_SwapGCHandleForType ScriptManagerBridge_SwapGCHandleForType;
FuncScriptManagerBridge_GetPropertyInfoList ScriptManagerBridge_GetPropertyInfoList;
FuncScriptManagerBridge_GetPropertyDefaultValues ScriptManagerBridge_GetPropertyDefaultValues;
+ FuncScriptManagerBridge_CallStatic ScriptManagerBridge_CallStatic;
FuncCSharpInstanceBridge_Call CSharpInstanceBridge_Call;
FuncCSharpInstanceBridge_Set CSharpInstanceBridge_Set;
FuncCSharpInstanceBridge_Get CSharpInstanceBridge_Get;
diff --git a/modules/multiplayer/editor/replication_editor.cpp b/modules/multiplayer/editor/replication_editor.cpp
index 0051d82e99..1c7546436b 100644
--- a/modules/multiplayer/editor/replication_editor.cpp
+++ b/modules/multiplayer/editor/replication_editor.cpp
@@ -359,7 +359,7 @@ void ReplicationEditor::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE:
case EditorSettings::NOTIFICATION_EDITOR_SETTINGS_CHANGED: {
- add_theme_style_override("panel", EditorNode::get_singleton()->get_gui_base()->get_theme_stylebox(SNAME("panel"), SNAME("Panel")));
+ add_theme_style_override("panel", EditorNode::get_singleton()->get_editor_theme()->get_stylebox(SNAME("panel"), SNAME("Panel")));
add_pick_button->set_icon(get_theme_icon(SNAME("Add"), EditorStringName(EditorIcons)));
pin->set_icon(get_theme_icon(SNAME("Pin"), EditorStringName(EditorIcons)));
} break;
diff --git a/modules/openxr/action_map/openxr_action_map.cpp b/modules/openxr/action_map/openxr_action_map.cpp
index 652e5fc407..6d79e33de8 100644
--- a/modules/openxr/action_map/openxr_action_map.cpp
+++ b/modules/openxr/action_map/openxr_action_map.cpp
@@ -470,6 +470,7 @@ void OpenXRActionMap::create_default_action_sets() {
profile->add_new_binding(primary_click, "/user/hand/left/input/trackpad/click,/user/hand/right/input/trackpad/click");
profile->add_new_binding(primary_touch, "/user/hand/left/input/trackpad/touch,/user/hand/right/input/trackpad/touch");
profile->add_new_binding(haptic, "/user/hand/left/output/haptic,/user/hand/right/output/haptic");
+ add_interaction_profile(profile);
// Create our HTC Vive tracker profile
profile = OpenXRInteractionProfile::new_profile("/interaction_profiles/htc/vive_tracker_htcx");
diff --git a/modules/openxr/extensions/openxr_opengl_extension.h b/modules/openxr/extensions/openxr_opengl_extension.h
index 598d3415ad..1537f13067 100644
--- a/modules/openxr/extensions/openxr_opengl_extension.h
+++ b/modules/openxr/extensions/openxr_opengl_extension.h
@@ -56,7 +56,6 @@
#endif
#ifdef X11_ENABLED
-#include OPENGL_INCLUDE_H
#define GL_GLEXT_PROTOTYPES 1
#define GL3_PROTOTYPES 1
#include "thirdparty/glad/glad/gl.h"
diff --git a/modules/openxr/openxr_api.cpp b/modules/openxr/openxr_api.cpp
index a66afee1c5..972b6539e3 100644
--- a/modules/openxr/openxr_api.cpp
+++ b/modules/openxr/openxr_api.cpp
@@ -59,7 +59,6 @@
#define XR_USE_GRAPHICS_API_OPENGL
#endif // ANDROID_ENABLED
#ifdef X11_ENABLED
-#include OPENGL_INCLUDE_H
#define GL_GLEXT_PROTOTYPES 1
#define GL3_PROTOTYPES 1
#include "thirdparty/glad/glad/gl.h"
@@ -481,11 +480,19 @@ bool OpenXRAPI::load_supported_view_configuration_types() {
result = xrEnumerateViewConfigurations(instance, system_id, num_view_configuration_types, &num_view_configuration_types, supported_view_configuration_types);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerateview configurations");
+ ERR_FAIL_COND_V_MSG(num_view_configuration_types == 0, false, "OpenXR: Failed to enumerateview configurations"); // JIC there should be at least 1!
for (uint32_t i = 0; i < num_view_configuration_types; i++) {
print_verbose(String("OpenXR: Found supported view configuration ") + OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[i]));
}
+ // Check value we loaded at startup...
+ if (!is_view_configuration_supported(view_configuration)) {
+ print_verbose(String("OpenXR: ") + OpenXRUtil::get_view_configuration_name(view_configuration) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_view_configuration_name(supported_view_configuration_types[0]));
+
+ view_configuration = supported_view_configuration_types[0];
+ }
+
return true;
}
@@ -512,11 +519,19 @@ bool OpenXRAPI::load_supported_environmental_blend_modes() {
result = xrEnumerateEnvironmentBlendModes(instance, system_id, view_configuration, num_supported_environment_blend_modes, &num_supported_environment_blend_modes, supported_environment_blend_modes);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate environmental blend modes");
+ ERR_FAIL_COND_V_MSG(num_supported_environment_blend_modes == 0, false, "OpenXR: Failed to enumerate environmental blend modes"); // JIC there should be at least 1!
for (uint32_t i = 0; i < num_supported_environment_blend_modes; i++) {
print_verbose(String("OpenXR: Found environmental blend mode ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[i]));
}
+ // Check value we loaded at startup...
+ if (!is_environment_blend_mode_supported(environment_blend_mode)) {
+ print_verbose(String("OpenXR: ") + OpenXRUtil::get_environment_blend_mode_name(environment_blend_mode) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_environment_blend_mode_name(supported_environment_blend_modes[0]));
+
+ environment_blend_mode = supported_environment_blend_modes[0];
+ }
+
return true;
}
@@ -665,11 +680,19 @@ bool OpenXRAPI::load_supported_reference_spaces() {
result = xrEnumerateReferenceSpaces(session, num_reference_spaces, &num_reference_spaces, supported_reference_spaces);
ERR_FAIL_COND_V_MSG(XR_FAILED(result), false, "OpenXR: Failed to enumerate reference spaces");
+ ERR_FAIL_COND_V_MSG(num_reference_spaces == 0, false, "OpenXR: Failed to enumerate reference spaces");
for (uint32_t i = 0; i < num_reference_spaces; i++) {
print_verbose(String("OpenXR: Found supported reference space ") + OpenXRUtil::get_reference_space_name(supported_reference_spaces[i]));
}
+ // Check value we loaded at startup...
+ if (!is_reference_space_supported(reference_space)) {
+ print_verbose(String("OpenXR: ") + OpenXRUtil::get_reference_space_name(reference_space) + String(" isn't supported, defaulting to ") + OpenXRUtil::get_reference_space_name(supported_reference_spaces[0]));
+
+ reference_space = supported_reference_spaces[0];
+ }
+
return true;
}
@@ -1434,7 +1457,9 @@ Size2 OpenXRAPI::get_recommended_target_size() {
XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform, Vector3 &r_linear_velocity, Vector3 &r_angular_velocity) {
XrResult result;
- ERR_FAIL_COND_V(!running, XRPose::XR_TRACKING_CONFIDENCE_NONE);
+ if (!running) {
+ return XRPose::XR_TRACKING_CONFIDENCE_NONE;
+ }
// xrWaitFrame not run yet
if (frame_state.predictedDisplayTime == 0) {
@@ -1487,7 +1512,9 @@ XRPose::TrackingConfidence OpenXRAPI::get_head_center(Transform3D &r_transform,
}
bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) {
- ERR_FAIL_COND_V(!running, false);
+ if (!running) {
+ return false;
+ }
// xrWaitFrame not run yet
if (frame_state.predictedDisplayTime == 0) {
@@ -1506,9 +1533,12 @@ bool OpenXRAPI::get_view_transform(uint32_t p_view, Transform3D &r_transform) {
}
bool OpenXRAPI::get_view_projection(uint32_t p_view, double p_z_near, double p_z_far, Projection &p_camera_matrix) {
- ERR_FAIL_COND_V(!running, false);
ERR_FAIL_NULL_V(graphics_extension, false);
+ if (!running) {
+ return false;
+ }
+
// xrWaitFrame not run yet
if (frame_state.predictedDisplayTime == 0) {
return false;
@@ -1917,10 +1947,15 @@ void OpenXRAPI::end_frame() {
}
}
+ XrCompositionLayerFlags layer_flags = XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT;
+ if (layers_list.size() > 0 || environment_blend_mode != XR_ENVIRONMENT_BLEND_MODE_OPAQUE) {
+ layer_flags |= XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT;
+ }
+
XrCompositionLayerProjection projection_layer = {
XR_TYPE_COMPOSITION_LAYER_PROJECTION, // type
nullptr, // next
- layers_list.size() > 0 ? XR_COMPOSITION_LAYER_BLEND_TEXTURE_SOURCE_ALPHA_BIT | XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT : XR_COMPOSITION_LAYER_CORRECT_CHROMATIC_ABERRATION_BIT, // layerFlags
+ layer_flags, // layerFlags
play_space, // space
view_count, // viewCount
projection_views, // views
@@ -1984,8 +2019,8 @@ OpenXRAPI::OpenXRAPI() {
} else {
// Load settings from project settings
- int ff = GLOBAL_GET("xr/openxr/form_factor");
- switch (ff) {
+ int form_factor_setting = GLOBAL_GET("xr/openxr/form_factor");
+ switch (form_factor_setting) {
case 0: {
form_factor = XR_FORM_FACTOR_HEAD_MOUNTED_DISPLAY;
} break;
@@ -1996,8 +2031,8 @@ OpenXRAPI::OpenXRAPI() {
break;
}
- int vc = GLOBAL_GET("xr/openxr/view_configuration");
- switch (vc) {
+ int view_configuration_setting = GLOBAL_GET("xr/openxr/view_configuration");
+ switch (view_configuration_setting) {
case 0: {
view_configuration = XR_VIEW_CONFIGURATION_TYPE_PRIMARY_MONO;
} break;
@@ -2016,8 +2051,8 @@ OpenXRAPI::OpenXRAPI() {
break;
}
- int rs = GLOBAL_GET("xr/openxr/reference_space");
- switch (rs) {
+ int reference_space_setting = GLOBAL_GET("xr/openxr/reference_space");
+ switch (reference_space_setting) {
case 0: {
reference_space = XR_REFERENCE_SPACE_TYPE_LOCAL;
} break;
@@ -2028,6 +2063,21 @@ OpenXRAPI::OpenXRAPI() {
break;
}
+ int environment_blend_mode_setting = GLOBAL_GET("xr/openxr/environment_blend_mode");
+ switch (environment_blend_mode_setting) {
+ case 0: {
+ environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_OPAQUE;
+ } break;
+ case 1: {
+ environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ADDITIVE;
+ } break;
+ case 2: {
+ environment_blend_mode = XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND;
+ } break;
+ default:
+ break;
+ }
+
submit_depth_buffer = GLOBAL_GET("xr/openxr/submit_depth_buffer");
}
@@ -2857,12 +2907,24 @@ const XrEnvironmentBlendMode *OpenXRAPI::get_supported_environment_blend_modes(u
return supported_environment_blend_modes;
}
-bool OpenXRAPI::set_environment_blend_mode(XrEnvironmentBlendMode mode) {
+bool OpenXRAPI::is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const {
+ ERR_FAIL_NULL_V(supported_environment_blend_modes, false);
+
for (uint32_t i = 0; i < num_supported_environment_blend_modes; i++) {
- if (supported_environment_blend_modes[i] == mode) {
- environment_blend_mode = mode;
+ if (supported_environment_blend_modes[i] == p_blend_mode) {
return true;
}
}
+
+ return false;
+}
+
+bool OpenXRAPI::set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode) {
+ // We allow setting this when not initialized and will check if it is supported when initializing.
+ // After OpenXR is initialized we verify we're setting a supported blend mode.
+ if (!is_initialized() || is_environment_blend_mode_supported(p_blend_mode)) {
+ environment_blend_mode = p_blend_mode;
+ return true;
+ }
return false;
}
diff --git a/modules/openxr/openxr_api.h b/modules/openxr/openxr_api.h
index 2498cd1eb4..26de535153 100644
--- a/modules/openxr/openxr_api.h
+++ b/modules/openxr/openxr_api.h
@@ -289,7 +289,7 @@ private:
bool on_state_loss_pending();
bool on_state_exiting();
- // convencience
+ // convenience
void copy_string_to_char_buffer(const String p_string, char *p_buffer, int p_buffer_len);
public:
@@ -405,7 +405,9 @@ public:
void unregister_composition_layer_provider(OpenXRCompositionLayerProvider *provider);
const XrEnvironmentBlendMode *get_supported_environment_blend_modes(uint32_t &count);
- bool set_environment_blend_mode(XrEnvironmentBlendMode mode);
+ bool is_environment_blend_mode_supported(XrEnvironmentBlendMode p_blend_mode) const;
+ bool set_environment_blend_mode(XrEnvironmentBlendMode p_blend_mode);
+ XrEnvironmentBlendMode get_environment_blend_mode() const { return environment_blend_mode; }
OpenXRAPI();
~OpenXRAPI();
diff --git a/modules/openxr/openxr_interface.cpp b/modules/openxr/openxr_interface.cpp
index 4dda51147b..cf8d1654b1 100644
--- a/modules/openxr/openxr_interface.cpp
+++ b/modules/openxr/openxr_interface.cpp
@@ -985,6 +985,27 @@ Array OpenXRInterface::get_supported_environment_blend_modes() {
return modes;
}
+XRInterface::EnvironmentBlendMode OpenXRInterface::get_environment_blend_mode() const {
+ if (openxr_api) {
+ XrEnvironmentBlendMode oxr_blend_mode = openxr_api->get_environment_blend_mode();
+ switch (oxr_blend_mode) {
+ case XR_ENVIRONMENT_BLEND_MODE_OPAQUE: {
+ return XR_ENV_BLEND_MODE_OPAQUE;
+ } break;
+ case XR_ENVIRONMENT_BLEND_MODE_ADDITIVE: {
+ return XR_ENV_BLEND_MODE_ADDITIVE;
+ } break;
+ case XR_ENVIRONMENT_BLEND_MODE_ALPHA_BLEND: {
+ return XR_ENV_BLEND_MODE_ALPHA_BLEND;
+ } break;
+ default:
+ break;
+ }
+ }
+
+ return XR_ENV_BLEND_MODE_OPAQUE;
+}
+
bool OpenXRInterface::set_environment_blend_mode(XRInterface::EnvironmentBlendMode mode) {
if (openxr_api) {
XrEnvironmentBlendMode oxr_blend_mode;
diff --git a/modules/openxr/openxr_interface.h b/modules/openxr/openxr_interface.h
index 09e1c31728..81efbd6777 100644
--- a/modules/openxr/openxr_interface.h
+++ b/modules/openxr/openxr_interface.h
@@ -152,6 +152,7 @@ public:
/** environment blend mode. */
virtual Array get_supported_environment_blend_modes() override;
+ virtual XRInterface::EnvironmentBlendMode get_environment_blend_mode() const override;
virtual bool set_environment_blend_mode(XRInterface::EnvironmentBlendMode mode) override;
void on_state_ready();
diff --git a/modules/regex/doc_classes/RegEx.xml b/modules/regex/doc_classes/RegEx.xml
index 5770e7155e..ab74fce3a9 100644
--- a/modules/regex/doc_classes/RegEx.xml
+++ b/modules/regex/doc_classes/RegEx.xml
@@ -10,7 +10,7 @@
var regex = RegEx.new()
regex.compile("\\w-(\\d+)")
[/codeblock]
- The search pattern must be escaped first for GDScript before it is escaped for the expression. For example, [code]compile("\\d+")[/code] would be read by RegEx as [code]\d+[/code]. Similarly, [code]compile("\"(?:\\\\.|[^\"])*\"")[/code] would be read as [code]"(?:\\.|[^"])*"[/code].
+ The search pattern must be escaped first for GDScript before it is escaped for the expression. For example, [code]compile("\\d+")[/code] would be read by RegEx as [code]\d+[/code]. Similarly, [code]compile("\"(?:\\\\.|[^\"])*\"")[/code] would be read as [code]"(?:\\.|[^"])*"[/code]. In GDScript, you can also use raw string literals (r-strings). For example, [code]compile(r'"(?:\\.|[^"])*"')[/code] would be read the same.
Using [method search], you can find the pattern within the given text. If a pattern is found, [RegExMatch] is returned and you can retrieve details of the results using methods such as [method RegExMatch.get_string] and [method RegExMatch.get_start].
[codeblock]
var regex = RegEx.new()
diff --git a/modules/vorbis/audio_stream_ogg_vorbis.cpp b/modules/vorbis/audio_stream_ogg_vorbis.cpp
index b54335b724..b155dfc5d9 100644
--- a/modules/vorbis/audio_stream_ogg_vorbis.cpp
+++ b/modules/vorbis/audio_stream_ogg_vorbis.cpp
@@ -328,9 +328,9 @@ void AudioStreamPlaybackOggVorbis::seek(double p_time) {
int64_t samples_to_burn = samples_in_page - (granule_pos - desired_sample);
if (samples_to_burn > samples_in_page) {
- WARN_PRINT("Burning more samples than we have in this page. Check seek algorithm.");
+ WARN_PRINT_ONCE("Burning more samples than we have in this page. Check seek algorithm.");
} else if (samples_to_burn < 0) {
- WARN_PRINT("Burning negative samples doesn't make sense. Check seek algorithm.");
+ WARN_PRINT_ONCE("Burning negative samples doesn't make sense. Check seek algorithm.");
}
// Seek again, this time we'll burn a specific number of samples instead of all of them.
diff --git a/modules/webrtc/register_types.cpp b/modules/webrtc/register_types.cpp
index 687c7b711e..28ce36f1e8 100644
--- a/modules/webrtc/register_types.cpp
+++ b/modules/webrtc/register_types.cpp
@@ -42,11 +42,7 @@ void initialize_webrtc_module(ModuleInitializationLevel p_level) {
if (p_level != MODULE_INITIALIZATION_LEVEL_SCENE) {
return;
}
-
-#define SET_HINT(NAME, _VAL_, _MAX_) \
- GLOBAL_DEF(PropertyInfo(Variant::INT, NAME, PROPERTY_HINT_RANGE, "2," #_MAX_ ",1,or_greater"), _VAL_);
-
- SET_HINT(WRTC_IN_BUF, 64, 4096);
+ GLOBAL_DEF(PropertyInfo(Variant::INT, "network/limits/webrtc/max_channel_in_buffer_kb", PROPERTY_HINT_RANGE, "2,4096,1,or_greater"), 64);
ClassDB::register_custom_instance_class<WebRTCPeerConnection>();
GDREGISTER_CLASS(WebRTCPeerConnectionExtension);
@@ -55,8 +51,6 @@ void initialize_webrtc_module(ModuleInitializationLevel p_level) {
GDREGISTER_CLASS(WebRTCDataChannelExtension);
GDREGISTER_CLASS(WebRTCMultiplayerPeer);
-
-#undef SET_HINT
}
void uninitialize_webrtc_module(ModuleInitializationLevel p_level) {
diff --git a/modules/webrtc/webrtc_data_channel.cpp b/modules/webrtc/webrtc_data_channel.cpp
index bebf5c2741..6c0d0bea37 100644
--- a/modules/webrtc/webrtc_data_channel.cpp
+++ b/modules/webrtc/webrtc_data_channel.cpp
@@ -61,7 +61,7 @@ void WebRTCDataChannel::_bind_methods() {
}
WebRTCDataChannel::WebRTCDataChannel() {
- _in_buffer_shift = nearest_shift((int)GLOBAL_GET(WRTC_IN_BUF) - 1) + 10;
+ _in_buffer_shift = nearest_shift((int)GLOBAL_GET("network/limits/webrtc/max_channel_in_buffer_kb") - 1) + 10;
}
WebRTCDataChannel::~WebRTCDataChannel() {
diff --git a/modules/webrtc/webrtc_data_channel.h b/modules/webrtc/webrtc_data_channel.h
index e884c8425d..f35461a5a0 100644
--- a/modules/webrtc/webrtc_data_channel.h
+++ b/modules/webrtc/webrtc_data_channel.h
@@ -33,8 +33,6 @@
#include "core/io/packet_peer.h"
-#define WRTC_IN_BUF PNAME("network/limits/webrtc/max_channel_in_buffer_kb")
-
class WebRTCDataChannel : public PacketPeer {
GDCLASS(WebRTCDataChannel, PacketPeer);
diff --git a/modules/zip/zip_packer.cpp b/modules/zip/zip_packer.cpp
index c8b4fb4e77..5f623476fc 100644
--- a/modules/zip/zip_packer.cpp
+++ b/modules/zip/zip_packer.cpp
@@ -33,7 +33,7 @@
#include "core/io/zip_io.h"
#include "core/os/os.h"
-Error ZIPPacker::open(String p_path, ZipAppend p_append) {
+Error ZIPPacker::open(const String &p_path, ZipAppend p_append) {
if (fa.is_valid()) {
close();
}
@@ -55,7 +55,7 @@ Error ZIPPacker::close() {
return err;
}
-Error ZIPPacker::start_file(String p_path) {
+Error ZIPPacker::start_file(const String &p_path) {
ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker must be opened before use.");
zip_fileinfo zipfi;
@@ -76,7 +76,7 @@ Error ZIPPacker::start_file(String p_path) {
return err == ZIP_OK ? OK : FAILED;
}
-Error ZIPPacker::write_file(Vector<uint8_t> p_data) {
+Error ZIPPacker::write_file(const Vector<uint8_t> &p_data) {
ERR_FAIL_COND_V_MSG(fa.is_null(), FAILED, "ZIPPacker must be opened before use.");
return zipWriteInFileInZip(zf, p_data.ptr(), p_data.size()) == ZIP_OK ? OK : FAILED;
diff --git a/modules/zip/zip_packer.h b/modules/zip/zip_packer.h
index 142d0fddbf..e194f5ebbe 100644
--- a/modules/zip/zip_packer.h
+++ b/modules/zip/zip_packer.h
@@ -52,11 +52,11 @@ public:
APPEND_ADDINZIP = 2,
};
- Error open(String p_path, ZipAppend p_append);
+ Error open(const String &p_path, ZipAppend p_append);
Error close();
- Error start_file(String p_path);
- Error write_file(Vector<uint8_t> p_data);
+ Error start_file(const String &p_path);
+ Error write_file(const Vector<uint8_t> &p_data);
Error close_file();
ZIPPacker();
diff --git a/modules/zip/zip_reader.cpp b/modules/zip/zip_reader.cpp
index 5752b829ef..f4a92dce5b 100644
--- a/modules/zip/zip_reader.cpp
+++ b/modules/zip/zip_reader.cpp
@@ -33,7 +33,7 @@
#include "core/error/error_macros.h"
#include "core/io/zip_io.h"
-Error ZIPReader::open(String p_path) {
+Error ZIPReader::open(const String &p_path) {
if (fa.is_valid()) {
close();
}
@@ -81,7 +81,7 @@ PackedStringArray ZIPReader::get_files() {
return arr;
}
-PackedByteArray ZIPReader::read_file(String p_path, bool p_case_sensitive) {
+PackedByteArray ZIPReader::read_file(const String &p_path, bool p_case_sensitive) {
ERR_FAIL_COND_V_MSG(fa.is_null(), PackedByteArray(), "ZIPReader must be opened before use.");
int err = UNZ_OK;
@@ -118,7 +118,7 @@ PackedByteArray ZIPReader::read_file(String p_path, bool p_case_sensitive) {
return data;
}
-bool ZIPReader::file_exists(String p_path, bool p_case_sensitive) {
+bool ZIPReader::file_exists(const String &p_path, bool p_case_sensitive) {
ERR_FAIL_COND_V_MSG(fa.is_null(), false, "ZIPReader must be opened before use.");
int cs = p_case_sensitive ? 1 : 2;
diff --git a/modules/zip/zip_reader.h b/modules/zip/zip_reader.h
index 0f78352e3f..874bd81ed3 100644
--- a/modules/zip/zip_reader.h
+++ b/modules/zip/zip_reader.h
@@ -46,12 +46,12 @@ protected:
static void _bind_methods();
public:
- Error open(String p_path);
+ Error open(const String &p_path);
Error close();
PackedStringArray get_files();
- PackedByteArray read_file(String p_path, bool p_case_sensitive);
- bool file_exists(String p_path, bool p_case_sensitive);
+ PackedByteArray read_file(const String &p_path, bool p_case_sensitive);
+ bool file_exists(const String &p_path, bool p_case_sensitive);
ZIPReader();
~ZIPReader();
diff --git a/platform/android/android_input_handler.cpp b/platform/android/android_input_handler.cpp
index f6a0776017..bd194478d9 100644
--- a/platform/android/android_input_handler.cpp
+++ b/platform/android/android_input_handler.cpp
@@ -292,7 +292,7 @@ void AndroidInputHandler::_release_mouse_event_info(bool p_source_mouse_relative
mouse_event_info.valid = false;
}
-void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative) {
+void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative, float p_pressure, Vector2 p_tilt) {
BitField<MouseButtonMask> event_buttons_mask = _android_button_mask_to_godot_button_mask(p_event_android_buttons_mask);
switch (p_event_action) {
case AMOTION_EVENT_ACTION_HOVER_MOVE: // hover move
@@ -349,6 +349,8 @@ void AndroidInputHandler::process_mouse_event(int p_event_action, int p_event_an
hover_prev_pos = p_event_pos;
}
ev->set_button_mask(event_buttons_mask);
+ ev->set_pressure(p_pressure);
+ ev->set_tilt(p_tilt);
Input::get_singleton()->parse_input_event(ev);
} break;
diff --git a/platform/android/android_input_handler.h b/platform/android/android_input_handler.h
index c74c5020e3..78a484cf05 100644
--- a/platform/android/android_input_handler.h
+++ b/platform/android/android_input_handler.h
@@ -96,7 +96,7 @@ private:
void _cancel_all_touch();
public:
- void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative);
+ void process_mouse_event(int p_event_action, int p_event_android_buttons_mask, Point2 p_event_pos, Vector2 p_delta, bool p_double_click, bool p_source_mouse_relative, float p_pressure, Vector2 p_tilt);
void process_touch_event(int p_event, int p_pointer, const Vector<TouchPos> &p_points, bool p_double_tap);
void process_magnify(Point2 p_pos, float p_factor);
void process_pan(Point2 p_pos, Vector2 p_delta);
diff --git a/platform/android/dir_access_jandroid.cpp b/platform/android/dir_access_jandroid.cpp
index 6bd09fe00a..d24d3fa389 100644
--- a/platform/android/dir_access_jandroid.cpp
+++ b/platform/android/dir_access_jandroid.cpp
@@ -67,7 +67,7 @@ String DirAccessJAndroid::get_next() {
ERR_FAIL_COND_V(id == 0, "");
if (_dir_next) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, "");
+ ERR_FAIL_NULL_V(env, "");
jstring str = (jstring)env->CallObjectMethod(dir_access_handler, _dir_next, get_access_type(), id);
if (!str) {
return "";
@@ -84,7 +84,7 @@ String DirAccessJAndroid::get_next() {
bool DirAccessJAndroid::current_is_dir() const {
if (_dir_is_dir) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
return env->CallBooleanMethod(dir_access_handler, _dir_is_dir, get_access_type(), id);
} else {
return false;
@@ -94,7 +94,7 @@ bool DirAccessJAndroid::current_is_dir() const {
bool DirAccessJAndroid::current_is_hidden() const {
if (_current_is_hidden) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
return env->CallBooleanMethod(dir_access_handler, _current_is_hidden, get_access_type(), id);
}
return false;
@@ -112,7 +112,7 @@ void DirAccessJAndroid::list_dir_end() {
int DirAccessJAndroid::get_drive_count() {
if (_get_drive_count) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, 0);
+ ERR_FAIL_NULL_V(env, 0);
return env->CallIntMethod(dir_access_handler, _get_drive_count, get_access_type());
} else {
return 0;
@@ -122,7 +122,7 @@ int DirAccessJAndroid::get_drive_count() {
String DirAccessJAndroid::get_drive(int p_drive) {
if (_get_drive) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, "");
+ ERR_FAIL_NULL_V(env, "");
jstring j_drive = (jstring)env->CallObjectMethod(dir_access_handler, _get_drive, get_access_type(), p_drive);
if (!j_drive) {
return "";
@@ -191,7 +191,7 @@ String DirAccessJAndroid::get_absolute_path(String p_path) {
bool DirAccessJAndroid::file_exists(String p_file) {
if (_file_exists) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
String path = get_absolute_path(p_file);
jstring j_path = env->NewStringUTF(path.utf8().get_data());
@@ -206,7 +206,7 @@ bool DirAccessJAndroid::file_exists(String p_file) {
bool DirAccessJAndroid::dir_exists(String p_dir) {
if (_dir_exists) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
String path = get_absolute_path(p_dir);
jstring j_path = env->NewStringUTF(path.utf8().get_data());
@@ -226,7 +226,7 @@ Error DirAccessJAndroid::make_dir_recursive(String p_dir) {
if (_make_dir) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
String path = get_absolute_path(p_dir);
jstring j_dir = env->NewStringUTF(path.utf8().get_data());
@@ -249,7 +249,7 @@ Error DirAccessJAndroid::make_dir(String p_dir) {
Error DirAccessJAndroid::rename(String p_from, String p_to) {
if (_rename) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
String from_path = get_absolute_path(p_from);
jstring j_from = env->NewStringUTF(from_path.utf8().get_data());
@@ -273,7 +273,7 @@ Error DirAccessJAndroid::rename(String p_from, String p_to) {
Error DirAccessJAndroid::remove(String p_name) {
if (_remove) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
String path = get_absolute_path(p_name);
jstring j_name = env->NewStringUTF(path.utf8().get_data());
@@ -292,7 +292,7 @@ Error DirAccessJAndroid::remove(String p_name) {
uint64_t DirAccessJAndroid::get_space_left() {
if (_get_space_left) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, 0);
+ ERR_FAIL_NULL_V(env, 0);
return env->CallLongMethod(dir_access_handler, _get_space_left, get_access_type());
} else {
return 0;
@@ -331,7 +331,7 @@ DirAccessJAndroid::~DirAccessJAndroid() {
int DirAccessJAndroid::dir_open(String p_path) {
if (_dir_open) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, 0);
+ ERR_FAIL_NULL_V(env, 0);
String path = get_absolute_path(p_path);
jstring js = env->NewStringUTF(path.utf8().get_data());
@@ -346,7 +346,7 @@ int DirAccessJAndroid::dir_open(String p_path) {
void DirAccessJAndroid::dir_close(int p_id) {
if (_dir_close) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
env->CallVoidMethod(dir_access_handler, _dir_close, get_access_type(), p_id);
}
}
diff --git a/platform/android/display_server_android.cpp b/platform/android/display_server_android.cpp
index f02b292868..3904d3afc4 100644
--- a/platform/android/display_server_android.cpp
+++ b/platform/android/display_server_android.cpp
@@ -543,7 +543,7 @@ DisplayServerAndroid::DisplayServerAndroid(const String &p_rendering_driver, Dis
#if defined(GLES3_ENABLED)
if (rendering_driver == "opengl3") {
- RasterizerGLES3::make_current();
+ RasterizerGLES3::make_current(false);
}
#endif
diff --git a/platform/android/export/export_plugin.cpp b/platform/android/export/export_plugin.cpp
index 15ded5c61e..661f7cbc80 100644
--- a/platform/android/export/export_plugin.cpp
+++ b/platform/android/export/export_plugin.cpp
@@ -1832,7 +1832,7 @@ void EditorExportPlatformAndroid::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "version/code", PROPERTY_HINT_RANGE, "1,4096,1,or_greater"), 1));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "version/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Leave empty to use project version"), ""));
- r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "org.godotengine.$genname", false, true));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/unique_name", PROPERTY_HINT_PLACEHOLDER_TEXT, "ext.domain.name"), "com.example.$genname", false, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "package/name", PROPERTY_HINT_PLACEHOLDER_TEXT, "Game Name [default if blank]"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "package/signed"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "package/app_category", PROPERTY_HINT_ENUM, "Accessibility,Audio,Game,Image,Maps,News,Productivity,Social,Video"), APP_CATEGORY_GAME));
diff --git a/platform/android/file_access_filesystem_jandroid.cpp b/platform/android/file_access_filesystem_jandroid.cpp
index a1865fb1d4..beea73fd61 100644
--- a/platform/android/file_access_filesystem_jandroid.cpp
+++ b/platform/android/file_access_filesystem_jandroid.cpp
@@ -69,7 +69,7 @@ Error FileAccessFilesystemJAndroid::open_internal(const String &p_path, int p_mo
if (_file_open) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(env, ERR_UNCONFIGURED);
String path = fix_path(p_path).simplify_path();
jstring js = env->NewStringUTF(path.utf8().get_data());
@@ -103,7 +103,7 @@ void FileAccessFilesystemJAndroid::_close() {
if (_file_close) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
env->CallVoidMethod(file_access_handler, _file_close, id);
}
id = 0;
@@ -116,7 +116,7 @@ bool FileAccessFilesystemJAndroid::is_open() const {
void FileAccessFilesystemJAndroid::seek(uint64_t p_position) {
if (_file_seek) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
env->CallVoidMethod(file_access_handler, _file_seek, id, p_position);
}
@@ -125,7 +125,7 @@ void FileAccessFilesystemJAndroid::seek(uint64_t p_position) {
void FileAccessFilesystemJAndroid::seek_end(int64_t p_position) {
if (_file_seek_end) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
env->CallVoidMethod(file_access_handler, _file_seek_end, id, p_position);
}
@@ -134,7 +134,7 @@ void FileAccessFilesystemJAndroid::seek_end(int64_t p_position) {
uint64_t FileAccessFilesystemJAndroid::get_position() const {
if (_file_tell) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, 0);
+ ERR_FAIL_NULL_V(env, 0);
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
return env->CallLongMethod(file_access_handler, _file_tell, id);
} else {
@@ -145,7 +145,7 @@ uint64_t FileAccessFilesystemJAndroid::get_position() const {
uint64_t FileAccessFilesystemJAndroid::get_length() const {
if (_file_get_size) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, 0);
+ ERR_FAIL_NULL_V(env, 0);
ERR_FAIL_COND_V_MSG(!is_open(), 0, "File must be opened before use.");
return env->CallLongMethod(file_access_handler, _file_get_size, id);
} else {
@@ -156,7 +156,7 @@ uint64_t FileAccessFilesystemJAndroid::get_length() const {
bool FileAccessFilesystemJAndroid::eof_reached() const {
if (_file_eof) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
ERR_FAIL_COND_V_MSG(!is_open(), false, "File must be opened before use.");
return env->CallBooleanMethod(file_access_handler, _file_eof, id);
} else {
@@ -169,7 +169,7 @@ void FileAccessFilesystemJAndroid::_set_eof(bool eof) {
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
env->CallVoidMethod(file_access_handler, _file_set_eof, id, eof);
}
}
@@ -235,7 +235,7 @@ uint64_t FileAccessFilesystemJAndroid::get_buffer(uint8_t *p_dst, uint64_t p_len
}
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, 0);
+ ERR_FAIL_NULL_V(env, 0);
jobject j_buffer = env->NewDirectByteBuffer(p_dst, p_length);
int length = env->CallIntMethod(file_access_handler, _file_read, id, j_buffer);
@@ -258,7 +258,7 @@ void FileAccessFilesystemJAndroid::store_buffer(const uint8_t *p_src, uint64_t p
}
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
jobject j_buffer = env->NewDirectByteBuffer((void *)p_src, p_length);
env->CallVoidMethod(file_access_handler, _file_write, id, j_buffer);
@@ -276,7 +276,7 @@ Error FileAccessFilesystemJAndroid::get_error() const {
void FileAccessFilesystemJAndroid::flush() {
if (_file_flush) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
ERR_FAIL_COND_MSG(!is_open(), "File must be opened before use.");
env->CallVoidMethod(file_access_handler, _file_flush, id);
}
@@ -285,7 +285,7 @@ void FileAccessFilesystemJAndroid::flush() {
bool FileAccessFilesystemJAndroid::file_exists(const String &p_path) {
if (_file_exists) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
String path = fix_path(p_path).simplify_path();
jstring js = env->NewStringUTF(path.utf8().get_data());
@@ -300,7 +300,7 @@ bool FileAccessFilesystemJAndroid::file_exists(const String &p_path) {
uint64_t FileAccessFilesystemJAndroid::_get_modified_time(const String &p_file) {
if (_file_last_modified) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
String path = fix_path(p_file).simplify_path();
jstring js = env->NewStringUTF(path.utf8().get_data());
diff --git a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
index b9ecd6971d..fee50e93c2 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/GodotLib.java
@@ -114,7 +114,7 @@ public class GodotLib {
/**
* Dispatch mouse events
*/
- public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative);
+ public static native void dispatchMouseEvent(int event, int buttonMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY);
public static native void magnify(float x, float y, float factor);
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
index a7064dfc1d..3070a8a207 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotEditText.java
@@ -33,6 +33,7 @@ package org.godotengine.godot.input;
import org.godotengine.godot.*;
import android.content.Context;
+import android.content.res.Configuration;
import android.os.Handler;
import android.os.Message;
import android.text.InputFilter;
@@ -209,6 +210,13 @@ public class GodotEditText extends EditText {
mRenderView.getView().requestFocus();
}
+ // When a hardware keyboard is connected, all key events come through so we can route them
+ // directly to the engine.
+ // This is not the case when using a soft keyboard, requiring extra processing from this class.
+ if (hasHardwareKeyboard()) {
+ return mRenderView.getInputHandler().onKeyDown(keyCode, keyEvent);
+ }
+
// pass event to godot in special cases
if (needHandlingInGodot(keyCode, keyEvent) && mRenderView.getInputHandler().onKeyDown(keyCode, keyEvent)) {
return true;
@@ -219,6 +227,13 @@ public class GodotEditText extends EditText {
@Override
public boolean onKeyUp(int keyCode, KeyEvent keyEvent) {
+ // When a hardware keyboard is connected, all key events come through so we can route them
+ // directly to the engine.
+ // This is not the case when using a soft keyboard, requiring extra processing from this class.
+ if (hasHardwareKeyboard()) {
+ return mRenderView.getInputHandler().onKeyUp(keyCode, keyEvent);
+ }
+
if (needHandlingInGodot(keyCode, keyEvent) && mRenderView.getInputHandler().onKeyUp(keyCode, keyEvent)) {
return true;
} else {
@@ -235,10 +250,20 @@ public class GodotEditText extends EditText {
isModifiedKey;
}
+ boolean hasHardwareKeyboard() {
+ Configuration config = getResources().getConfiguration();
+ return config.keyboard != Configuration.KEYBOARD_NOKEYS &&
+ config.hardKeyboardHidden == Configuration.HARDKEYBOARDHIDDEN_NO;
+ }
+
// ===========================================================
// Methods
// ===========================================================
public void showKeyboard(String p_existing_text, VirtualKeyboardType p_type, int p_max_input_length, int p_cursor_start, int p_cursor_end) {
+ if (hasHardwareKeyboard()) {
+ return;
+ }
+
int maxInputLength = (p_max_input_length <= 0) ? Integer.MAX_VALUE : p_max_input_length;
if (p_cursor_start == -1) { // cursor position not given
this.mOriginText = p_existing_text;
@@ -262,6 +287,10 @@ public class GodotEditText extends EditText {
}
public void hideKeyboard() {
+ if (hasHardwareKeyboard()) {
+ return;
+ }
+
final Message msg = new Message();
msg.what = HANDLER_CLOSE_IME_KEYBOARD;
msg.obj = this;
diff --git a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
index 1a25be0460..c8b222254e 100644
--- a/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
+++ b/platform/android/java/lib/src/org/godotengine/godot/input/GodotInputHandler.java
@@ -433,7 +433,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
private static boolean isMouseEvent(int eventSource) {
- boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & (InputDevice.SOURCE_TOUCHSCREEN | InputDevice.SOURCE_STYLUS)) == InputDevice.SOURCE_STYLUS);
+ boolean mouseSource = ((eventSource & InputDevice.SOURCE_MOUSE) == InputDevice.SOURCE_MOUSE) || ((eventSource & InputDevice.SOURCE_STYLUS) == InputDevice.SOURCE_STYLUS);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
mouseSource = mouseSource || ((eventSource & InputDevice.SOURCE_MOUSE_RELATIVE) == InputDevice.SOURCE_MOUSE_RELATIVE);
}
@@ -470,13 +470,27 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
final float y = event.getY();
final int buttonsMask = event.getButtonState();
+ final float pressure = event.getPressure();
+
+ // Orientation is returned as a radian value between 0 to pi clockwise or 0 to -pi counterclockwise.
+ final float orientation = event.getOrientation();
+
+ // Tilt is zero is perpendicular to the screen and pi/2 is flat on the surface.
+ final float tilt = event.getAxisValue(MotionEvent.AXIS_TILT);
+
+ float tiltMult = (float)Math.sin(tilt);
+
+ // To be consistent with expected tilt.
+ final float tiltX = (float)-Math.sin(orientation) * tiltMult;
+ final float tiltY = (float)Math.cos(orientation) * tiltMult;
+
final float verticalFactor = event.getAxisValue(MotionEvent.AXIS_VSCROLL);
final float horizontalFactor = event.getAxisValue(MotionEvent.AXIS_HSCROLL);
boolean sourceMouseRelative = false;
if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.O) {
sourceMouseRelative = event.isFromSource(InputDevice.SOURCE_MOUSE_RELATIVE);
}
- return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative);
+ return handleMouseEvent(eventAction, buttonsMask, x, y, horizontalFactor, verticalFactor, false, sourceMouseRelative, pressure, tiltX, tiltY);
}
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y) {
@@ -484,6 +498,10 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
}
static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative) {
+ return handleMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, 1, 0, 0);
+ }
+
+ static boolean handleMouseEvent(int eventAction, int buttonsMask, float x, float y, float deltaX, float deltaY, boolean doubleClick, boolean sourceMouseRelative, float pressure, float tiltX, float tiltY) {
// Fix the buttonsMask
switch (eventAction) {
case MotionEvent.ACTION_CANCEL:
@@ -511,7 +529,7 @@ public class GodotInputHandler implements InputManager.InputDeviceListener {
case MotionEvent.ACTION_HOVER_MOVE:
case MotionEvent.ACTION_MOVE:
case MotionEvent.ACTION_SCROLL: {
- GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative);
+ GodotLib.dispatchMouseEvent(eventAction, buttonsMask, x, y, deltaX, deltaY, doubleClick, sourceMouseRelative, pressure, tiltX, tiltY);
return true;
}
}
diff --git a/platform/android/java_godot_lib_jni.cpp b/platform/android/java_godot_lib_jni.cpp
index 74605e3377..50075ed3f5 100644
--- a/platform/android/java_godot_lib_jni.cpp
+++ b/platform/android/java_godot_lib_jni.cpp
@@ -274,12 +274,12 @@ JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env,
}
// Called on the UI thread
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative) {
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative, jfloat p_pressure, jfloat p_tilt_x, jfloat p_tilt_y) {
if (step.get() <= 0) {
return;
}
- input_handler->process_mouse_event(p_event_type, p_button_mask, Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y), p_double_click, p_source_mouse_relative);
+ input_handler->process_mouse_event(p_event_type, p_button_mask, Point2(p_x, p_y), Vector2(p_delta_x, p_delta_y), p_double_click, p_source_mouse_relative, p_pressure, Vector2(p_tilt_x, p_tilt_y));
}
// Called on the UI thread
diff --git a/platform/android/java_godot_lib_jni.h b/platform/android/java_godot_lib_jni.h
index ee6a19034c..1ddda6c1c8 100644
--- a/platform/android/java_godot_lib_jni.h
+++ b/platform/android/java_godot_lib_jni.h
@@ -45,7 +45,7 @@ JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_newcontext(JNIEnv *en
JNIEXPORT jboolean JNICALL Java_org_godotengine_godot_GodotLib_step(JNIEnv *env, jclass clazz);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_ttsCallback(JNIEnv *env, jclass clazz, jint event, jint id, jint pos);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_back(JNIEnv *env, jclass clazz);
-JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative);
+JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchMouseEvent(JNIEnv *env, jclass clazz, jint p_event_type, jint p_button_mask, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y, jboolean p_double_click, jboolean p_source_mouse_relative, jfloat p_pressure, jfloat p_tilt_x, jfloat p_tilt_y);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_dispatchTouchEvent(JNIEnv *env, jclass clazz, jint ev, jint pointer, jint pointer_count, jfloatArray positions, jboolean p_double_tap);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_magnify(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_factor);
JNIEXPORT void JNICALL Java_org_godotengine_godot_GodotLib_pan(JNIEnv *env, jclass clazz, jfloat p_x, jfloat p_y, jfloat p_delta_x, jfloat p_delta_y);
diff --git a/platform/android/platform_gl.h b/platform/android/platform_gl.h
new file mode 100644
index 0000000000..af6edb103d
--- /dev/null
+++ b/platform/android/platform_gl.h
@@ -0,0 +1,43 @@
+/**************************************************************************/
+/* platform_gl.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 PLATFORM_GL_H
+#define PLATFORM_GL_H
+
+#ifndef GLES_API_ENABLED
+#define GLES_API_ENABLED // Allow using GLES.
+#endif
+
+#include <EGL/egl.h>
+#include <EGL/eglext.h>
+#include <GLES3/gl3.h>
+#include <GLES3/gl3ext.h>
+
+#endif // PLATFORM_GL_H
diff --git a/platform/android/tts_android.cpp b/platform/android/tts_android.cpp
index aef59c2584..93517d8045 100644
--- a/platform/android/tts_android.cpp
+++ b/platform/android/tts_android.cpp
@@ -54,7 +54,7 @@ void TTS_Android::setup(jobject p_tts) {
bool tts_enabled = GLOBAL_GET("audio/general/text_to_speech");
if (tts_enabled) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
tts = env->NewGlobalRef(p_tts);
@@ -103,7 +103,7 @@ bool TTS_Android::is_speaking() {
if (_is_speaking) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
return env->CallBooleanMethod(tts, _is_speaking);
} else {
return false;
@@ -115,7 +115,7 @@ bool TTS_Android::is_paused() {
if (_is_paused) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, false);
+ ERR_FAIL_NULL_V(env, false);
return env->CallBooleanMethod(tts, _is_paused);
} else {
return false;
@@ -127,7 +127,7 @@ Array TTS_Android::get_voices() {
Array list;
if (_get_voices) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND_V(env == nullptr, list);
+ ERR_FAIL_NULL_V(env, list);
jobject voices_object = env->CallObjectMethod(tts, _get_voices);
jobjectArray *arr = reinterpret_cast<jobjectArray *>(&voices_object);
@@ -165,7 +165,7 @@ void TTS_Android::speak(const String &p_text, const String &p_voice, int p_volum
if (_speak) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
jstring jStrT = env->NewStringUTF(p_text.utf8().get_data());
jstring jStrV = env->NewStringUTF(p_voice.utf8().get_data());
@@ -178,7 +178,7 @@ void TTS_Android::pause() {
if (_pause_speaking) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
env->CallVoidMethod(tts, _pause_speaking);
}
}
@@ -188,7 +188,7 @@ void TTS_Android::resume() {
if (_resume_speaking) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
env->CallVoidMethod(tts, _resume_speaking);
}
}
@@ -203,7 +203,7 @@ void TTS_Android::stop() {
if (_stop_speaking) {
JNIEnv *env = get_jni_env();
- ERR_FAIL_COND(env == nullptr);
+ ERR_FAIL_NULL(env);
env->CallVoidMethod(tts, _stop_speaking);
}
}
diff --git a/platform/ios/display_server_ios.mm b/platform/ios/display_server_ios.mm
index 7d91274a0c..33eb16279f 100644
--- a/platform/ios/display_server_ios.mm
+++ b/platform/ios/display_server_ios.mm
@@ -103,7 +103,7 @@ DisplayServerIOS::DisplayServerIOS(const String &p_rendering_driver, WindowMode
ERR_FAIL_MSG("Failed to create iOS OpenGLES rendering layer.");
}
- RasterizerGLES3::make_current();
+ RasterizerGLES3::make_current(false);
}
#endif
diff --git a/platform/ios/os_ios.mm b/platform/ios/os_ios.mm
index 50102e02cc..68e6d4c934 100644
--- a/platform/ios/os_ios.mm
+++ b/platform/ios/os_ios.mm
@@ -257,7 +257,7 @@ Error OS_IOS::open_dynamic_library(const String p_path, void *&p_library_handle,
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
- ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
+ ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
if (r_resolved_path != nullptr) {
*r_resolved_path = path;
diff --git a/platform/ios/platform_config.h b/platform/ios/platform_config.h
index fc0e165d6b..01b0a12b5d 100644
--- a/platform/ios/platform_config.h
+++ b/platform/ios/platform_config.h
@@ -30,8 +30,6 @@
#include <alloca.h>
-#define OPENGL_INCLUDE_H <ES3/gl.h>
-
#define PTHREAD_RENAME_SELF
#define _weakify(var) __weak typeof(var) GDWeak_##var = var;
diff --git a/platform/ios/platform_gl.h b/platform/ios/platform_gl.h
new file mode 100644
index 0000000000..974ea9d2c2
--- /dev/null
+++ b/platform/ios/platform_gl.h
@@ -0,0 +1,40 @@
+/**************************************************************************/
+/* platform_gl.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 PLATFORM_GL_H
+#define PLATFORM_GL_H
+
+#ifndef GLES_API_ENABLED
+#define GLES_API_ENABLED // Allow using GLES.
+#endif
+
+#include <ES3/gl.h>
+
+#endif // PLATFORM_GL_H
diff --git a/platform/linuxbsd/godot_linuxbsd.cpp b/platform/linuxbsd/godot_linuxbsd.cpp
index d059d60b72..efad9c8594 100644
--- a/platform/linuxbsd/godot_linuxbsd.cpp
+++ b/platform/linuxbsd/godot_linuxbsd.cpp
@@ -56,7 +56,7 @@ int main(int argc, char *argv[]) {
TEST_MAIN_OVERRIDE
char *cwd = (char *)malloc(PATH_MAX);
- ERR_FAIL_COND_V(!cwd, ERR_OUT_OF_MEMORY);
+ ERR_FAIL_NULL_V(cwd, ERR_OUT_OF_MEMORY);
char *ret = getcwd(cwd, PATH_MAX);
Error err = Main::setup(argv[0], argc - 1, &argv[1]);
diff --git a/platform/linuxbsd/platform_config.h b/platform/linuxbsd/platform_config.h
index 82c9c54879..c372ef28f6 100644
--- a/platform/linuxbsd/platform_config.h
+++ b/platform/linuxbsd/platform_config.h
@@ -43,5 +43,3 @@
#define PTHREAD_BSD_SET_NAME
#endif
#endif
-
-#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h"
diff --git a/platform/linuxbsd/platform_gl.h b/platform/linuxbsd/platform_gl.h
new file mode 100644
index 0000000000..1c19c4518a
--- /dev/null
+++ b/platform/linuxbsd/platform_gl.h
@@ -0,0 +1,41 @@
+/**************************************************************************/
+/* platform_gl.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 PLATFORM_GL_H
+#define PLATFORM_GL_H
+
+#ifndef GL_API_ENABLED
+#define GL_API_ENABLED // Allow using desktop GL.
+#endif
+
+#include "thirdparty/glad/glad/egl.h"
+#include "thirdparty/glad/glad/gl.h"
+
+#endif // PLATFORM_GL_H
diff --git a/platform/linuxbsd/tts_linux.cpp b/platform/linuxbsd/tts_linux.cpp
index 8bc83f5b9c..96745ab8ae 100644
--- a/platform/linuxbsd/tts_linux.cpp
+++ b/platform/linuxbsd/tts_linux.cpp
@@ -186,7 +186,7 @@ bool TTS_Linux::is_paused() const {
Array TTS_Linux::get_voices() const {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND_V(!synth, Array());
+ ERR_FAIL_NULL_V(synth, Array());
const_cast<TTS_Linux *>(this)->_load_voices();
Array list;
@@ -204,7 +204,7 @@ Array TTS_Linux::get_voices() const {
void TTS_Linux::speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
if (p_interrupt) {
stop();
}
@@ -233,7 +233,7 @@ void TTS_Linux::speak(const String &p_text, const String &p_voice, int p_volume,
void TTS_Linux::pause() {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
if (spd_pause(synth) == 0) {
paused = true;
}
@@ -242,7 +242,7 @@ void TTS_Linux::pause() {
void TTS_Linux::resume() {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
spd_resume(synth);
paused = false;
}
@@ -250,7 +250,7 @@ void TTS_Linux::resume() {
void TTS_Linux::stop() {
_THREAD_SAFE_METHOD_
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
for (DisplayServer::TTSUtterance &message : queue) {
DisplayServer::get_singleton()->tts_post_utterance_event(DisplayServer::TTS_UTTERANCE_CANCELED, message.id);
}
diff --git a/platform/linuxbsd/x11/display_server_x11.cpp b/platform/linuxbsd/x11/display_server_x11.cpp
index f38a9dd278..897a6438d2 100644
--- a/platform/linuxbsd/x11/display_server_x11.cpp
+++ b/platform/linuxbsd/x11/display_server_x11.cpp
@@ -307,37 +307,37 @@ void DisplayServerX11::_flush_mouse_motion() {
#ifdef SPEECHD_ENABLED
bool DisplayServerX11::tts_is_speaking() const {
- ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->is_speaking();
}
bool DisplayServerX11::tts_is_paused() const {
- ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->is_paused();
}
TypedArray<Dictionary> DisplayServerX11::tts_get_voices() const {
- ERR_FAIL_COND_V_MSG(!tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->get_voices();
}
void DisplayServerX11::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
}
void DisplayServerX11::tts_pause() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->pause();
}
void DisplayServerX11::tts_resume() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->resume();
}
void DisplayServerX11::tts_stop() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->stop();
}
@@ -5100,7 +5100,7 @@ DisplayServerX11::WindowID DisplayServerX11::_create_window(WindowMode p_mode, V
XVisualInfo vInfoTemplate = {};
vInfoTemplate.screen = DefaultScreen(x11_display);
XVisualInfo *vi_list = XGetVisualInfo(x11_display, visualMask, &vInfoTemplate, &numberOfVisuals);
- ERR_FAIL_COND_V(!vi_list, INVALID_WINDOW_ID);
+ ERR_FAIL_NULL_V(vi_list, INVALID_WINDOW_ID);
visualInfo = vi_list[0];
if (OS::get_singleton()->is_layered_allowed()) {
@@ -5821,7 +5821,7 @@ DisplayServerX11::DisplayServerX11(const String &p_rendering_driver, WindowMode
driver_found = true;
if (true) {
- RasterizerGLES3::make_current();
+ RasterizerGLES3::make_current(true);
} else {
memdelete(gl_manager);
gl_manager = nullptr;
diff --git a/platform/linuxbsd/x11/gl_manager_x11.cpp b/platform/linuxbsd/x11/gl_manager_x11.cpp
index f24bac5e19..25c4272607 100644
--- a/platform/linuxbsd/x11/gl_manager_x11.cpp
+++ b/platform/linuxbsd/x11/gl_manager_x11.cpp
@@ -103,7 +103,7 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
GLXCREATECONTEXTATTRIBSARBPROC glXCreateContextAttribsARB = (GLXCREATECONTEXTATTRIBSARBPROC)glXGetProcAddress((const GLubyte *)"glXCreateContextAttribsARB");
- ERR_FAIL_COND_V(!glXCreateContextAttribsARB, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(glXCreateContextAttribsARB, ERR_UNCONFIGURED);
static int visual_attribs[] = {
GLX_RENDER_TYPE, GLX_RGBA_BIT,
@@ -134,7 +134,7 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
if (OS::get_singleton()->is_layered_allowed()) {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs_layered, &fbcount);
- ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(fbc, ERR_UNCONFIGURED);
for (int i = 0; i < fbcount; i++) {
vi = (XVisualInfo *)glXGetVisualFromFBConfig(x11_display, fbc[i]);
@@ -156,10 +156,10 @@ Error GLManager_X11::_create_context(GLDisplay &gl_display) {
}
XFree(fbc);
- ERR_FAIL_COND_V(!fbconfig, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(fbconfig, ERR_UNCONFIGURED);
} else {
GLXFBConfig *fbc = glXChooseFBConfig(x11_display, DefaultScreen(x11_display), visual_attribs, &fbcount);
- ERR_FAIL_COND_V(!fbc, ERR_UNCONFIGURED);
+ ERR_FAIL_NULL_V(fbc, ERR_UNCONFIGURED);
vi = glXGetVisualFromFBConfig(x11_display, fbc[0]);
@@ -368,6 +368,7 @@ void GLManager_X11::set_use_vsync(bool p_use) {
GLXDrawable drawable = glXGetCurrentDrawable();
glXSwapIntervalEXT(disp.x11_display, drawable, val);
} else {
+ WARN_PRINT("Could not set V-Sync mode. V-Sync is not supported.");
return;
}
use_vsync = p_use;
diff --git a/platform/macos/SCsub b/platform/macos/SCsub
index 7ffb80f70b..30202e5de7 100644
--- a/platform/macos/SCsub
+++ b/platform/macos/SCsub
@@ -24,6 +24,7 @@ files = [
"tts_macos.mm",
"joypad_macos.cpp",
"vulkan_context_macos.mm",
+ "gl_manager_macos_angle.mm",
"gl_manager_macos_legacy.mm",
]
diff --git a/platform/macos/detect.py b/platform/macos/detect.py
index 21e824b2d3..c97cd19211 100644
--- a/platform/macos/detect.py
+++ b/platform/macos/detect.py
@@ -1,6 +1,6 @@
import os
import sys
-from methods import detect_darwin_sdk_path
+from methods import detect_darwin_sdk_path, get_compiler_version, is_vanilla_clang
from platform_methods import detect_arch
from typing import TYPE_CHECKING
@@ -32,6 +32,7 @@ def get_opts():
BoolVariable("use_asan", "Use LLVM/GCC compiler address sanitizer (ASAN)", False),
BoolVariable("use_tsan", "Use LLVM/GCC compiler thread sanitizer (TSAN)", False),
BoolVariable("use_coverage", "Use instrumentation codes in the binary (e.g. for code coverage)", False),
+ ("angle_libs", "Path to the ANGLE static libraries", ""),
]
@@ -119,6 +120,22 @@ def configure(env: "Environment"):
env.Append(CCFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.13"])
env.Append(LINKFLAGS=["-arch", "x86_64", "-mmacosx-version-min=10.13"])
+ cc_version = get_compiler_version(env) or {
+ "major": None,
+ "minor": None,
+ "patch": None,
+ "metadata1": None,
+ "metadata2": None,
+ "date": None,
+ }
+ cc_version_major = int(cc_version["major"] or -1)
+ cc_version_minor = int(cc_version["minor"] or -1)
+ vanilla = is_vanilla_clang(env)
+
+ # Workaround for Xcode 15 linker bug.
+ if not vanilla and cc_version_major == 15 and cc_version_minor == 0:
+ env.Prepend(LINKFLAGS=["-ld_classic"])
+
env.Append(CCFLAGS=["-fobjc-arc"])
if not "osxcross" in env: # regular native build
@@ -239,7 +256,13 @@ def configure(env: "Environment"):
if env["opengl3"]:
env.Append(CPPDEFINES=["GLES3_ENABLED"])
- env.Append(LINKFLAGS=["-framework", "OpenGL"])
+ if env["angle_libs"] != "":
+ env.AppendUnique(CPPDEFINES=["EGL_STATIC"])
+ env.Append(LINKFLAGS=["-L" + env["angle_libs"]])
+ env.Append(LINKFLAGS=["-lANGLE.macos." + env["arch"]])
+ env.Append(LINKFLAGS=["-lEGL.macos." + env["arch"]])
+ env.Append(LINKFLAGS=["-lGLES.macos." + env["arch"]])
+ env.Prepend(CPPPATH=["#thirdparty/angle/include"])
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 69f6008043..c03b4765f8 100644
--- a/platform/macos/display_server_macos.h
+++ b/platform/macos/display_server_macos.h
@@ -35,6 +35,7 @@
#include "servers/display_server.h"
#if defined(GLES3_ENABLED)
+#include "gl_manager_macos_angle.h"
#include "gl_manager_macos_legacy.h"
#endif // GLES3_ENABLED
@@ -127,7 +128,8 @@ public:
private:
#if defined(GLES3_ENABLED)
- GLManager_MacOS *gl_manager = nullptr;
+ GLManagerLegacy_MacOS *gl_manager_legacy = nullptr;
+ GLManagerANGLE_MacOS *gl_manager_angle = nullptr;
#endif
#if defined(VULKAN_ENABLED)
VulkanContextMacOS *context_vulkan = nullptr;
@@ -244,7 +246,6 @@ public:
void mouse_enter_window(WindowID p_window);
void mouse_exit_window(WindowID p_window);
- void window_update(WindowID p_window);
void window_destroy(WindowID p_window);
void window_resize(WindowID p_window, int p_width, int p_height);
void window_set_custom_window_buttons(WindowData &p_wd, bool p_enabled);
diff --git a/platform/macos/display_server_macos.mm b/platform/macos/display_server_macos.mm
index e79d6acc3f..2989f8d1c0 100644
--- a/platform/macos/display_server_macos.mm
+++ b/platform/macos/display_server_macos.mm
@@ -139,7 +139,7 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
// initWithContentRect uses bottom-left corner of the window’s frame as origin.
wd.window_object = [[GodotWindow alloc]
- initWithContentRect:NSMakeRect(100, 100, p_rect.size.width / scale, p_rect.size.height / scale)
+ initWithContentRect:NSMakeRect(100, 100, MAX(1, p_rect.size.width / scale), MAX(1, p_rect.size.height / scale))
styleMask:NSWindowStyleMaskTitled | NSWindowStyleMaskClosable | NSWindowStyleMaskMiniaturizable | NSWindowStyleMaskResizable
backing:NSBackingStoreBuffered
defer:NO];
@@ -185,9 +185,13 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
}
#endif
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- Error err = gl_manager->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height);
- ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context");
+ if (gl_manager_legacy) {
+ Error err = gl_manager_legacy->window_create(window_id_counter, wd.window_view, p_rect.size.width, p_rect.size.height);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context.");
+ }
+ if (gl_manager_angle) {
+ Error err = gl_manager_angle->window_create(window_id_counter, nullptr, (__bridge void *)[wd.window_view layer], p_rect.size.width, p_rect.size.height);
+ ERR_FAIL_COND_V_MSG(err != OK, INVALID_WINDOW_ID, "Can't create an OpenGL context.");
}
window_set_vsync_mode(p_vsync_mode, window_id_counter);
#endif
@@ -219,8 +223,11 @@ DisplayServerMacOS::WindowID DisplayServerMacOS::_create_window(WindowMode p_mod
}
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_resize(id, wd.size.width, wd.size.height);
+ if (gl_manager_legacy) {
+ gl_manager_legacy->window_resize(id, wd.size.width, wd.size.height);
+ }
+ if (gl_manager_angle) {
+ gl_manager_angle->window_resize(id, wd.size.width, wd.size.height);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -279,8 +286,8 @@ void DisplayServerMacOS::_set_window_per_pixel_transparency_enabled(bool p_enabl
[layer setOpaque:NO];
}
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_set_per_pixel_transparency_enabled(p_window, true);
+ if (gl_manager_legacy) {
+ gl_manager_legacy->window_set_per_pixel_transparency_enabled(p_window, true);
}
#endif
wd.layered_window = true;
@@ -299,8 +306,8 @@ void DisplayServerMacOS::_set_window_per_pixel_transparency_enabled(bool p_enabl
[layer setOpaque:YES];
}
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_set_per_pixel_transparency_enabled(p_window, false);
+ if (gl_manager_legacy) {
+ gl_manager_legacy->window_set_per_pixel_transparency_enabled(p_window, false);
}
#endif
wd.layered_window = false;
@@ -730,18 +737,10 @@ bool DisplayServerMacOS::get_is_resizing() const {
return is_resizing;
}
-void DisplayServerMacOS::window_update(WindowID p_window) {
-#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_update(p_window);
- }
-#endif
-}
-
void DisplayServerMacOS::window_destroy(WindowID p_window) {
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_destroy(p_window);
+ if (gl_manager_legacy) {
+ gl_manager_legacy->window_destroy(p_window);
}
#endif
#ifdef VULKAN_ENABLED
@@ -754,8 +753,11 @@ void DisplayServerMacOS::window_destroy(WindowID p_window) {
void DisplayServerMacOS::window_resize(WindowID p_window, int p_width, int p_height) {
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_resize(p_window, p_width, p_height);
+ if (gl_manager_legacy) {
+ gl_manager_legacy->window_resize(p_window, p_width, p_height);
+ }
+ if (gl_manager_angle) {
+ gl_manager_angle->window_resize(p_window, p_width, p_height);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -1451,7 +1453,7 @@ void DisplayServerMacOS::global_menu_set_item_checkable(const String &p_menu_roo
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_CHECK_BOX : CHECKABLE_TYPE_NONE;
}
}
@@ -1470,7 +1472,7 @@ void DisplayServerMacOS::global_menu_set_item_radio_checkable(const String &p_me
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->checkable_type = (p_checkable) ? CHECKABLE_TYPE_RADIO_BUTTON : CHECKABLE_TYPE_NONE;
}
}
@@ -1489,7 +1491,7 @@ void DisplayServerMacOS::global_menu_set_item_callback(const String &p_menu_root
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->callback = p_callback;
}
}
@@ -1508,7 +1510,7 @@ void DisplayServerMacOS::global_menu_set_item_key_callback(const String &p_menu_
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->key_callback = p_key_callback;
}
}
@@ -1527,7 +1529,7 @@ void DisplayServerMacOS::global_menu_set_item_tag(const String &p_menu_root, int
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->meta = p_tag;
}
}
@@ -1642,7 +1644,7 @@ void DisplayServerMacOS::global_menu_set_item_state(const String &p_menu_root, i
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->state = p_state;
}
}
@@ -1661,7 +1663,7 @@ void DisplayServerMacOS::global_menu_set_item_max_states(const String &p_menu_ro
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
obj->max_states = p_max_states;
}
}
@@ -1680,7 +1682,7 @@ void DisplayServerMacOS::global_menu_set_item_icon(const String &p_menu_root, in
NSMenuItem *menu_item = [menu itemAtIndex:p_idx];
if (menu_item) {
GodotMenuItem *obj = [menu_item representedObject];
- ERR_FAIL_COND(!obj);
+ ERR_FAIL_NULL(obj);
if (p_icon.is_valid()) {
obj->img = p_icon->get_image();
obj->img = obj->img->duplicate();
@@ -2912,7 +2914,7 @@ void DisplayServerMacOS::window_set_size(const Size2i p_size, WindowID p_window)
top_left.x = old_frame.origin.x;
top_left.y = NSMaxY(old_frame);
- NSRect new_frame = NSMakeRect(0, 0, size.x, size.y);
+ NSRect new_frame = NSMakeRect(0, 0, MAX(1, size.x), MAX(1, size.y));
new_frame = [wd.window_object frameRectForContentRect:new_frame];
new_frame.origin.x = top_left.x;
@@ -3370,8 +3372,11 @@ int64_t DisplayServerMacOS::window_get_native_handle(HandleType p_handle_type, W
}
#ifdef GLES3_ENABLED
case OPENGL_CONTEXT: {
- if (gl_manager) {
- return (int64_t)gl_manager->get_context(p_window);
+ if (gl_manager_legacy) {
+ return (int64_t)gl_manager_legacy->get_context(p_window);
+ }
+ if (gl_manager_angle) {
+ return (int64_t)gl_manager_angle->get_context(p_window);
}
return 0;
}
@@ -3398,8 +3403,11 @@ ObjectID DisplayServerMacOS::window_get_attached_instance_id(WindowID p_window)
void DisplayServerMacOS::gl_window_make_current(DisplayServer::WindowID p_window_id) {
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_make_current(p_window_id);
+ if (gl_manager_legacy) {
+ gl_manager_legacy->window_make_current(p_window_id);
+ }
+ if (gl_manager_angle) {
+ gl_manager_angle->window_make_current(p_window_id);
}
#endif
}
@@ -3407,8 +3415,11 @@ void DisplayServerMacOS::gl_window_make_current(DisplayServer::WindowID p_window
void DisplayServerMacOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_mode, WindowID p_window) {
_THREAD_SAFE_METHOD_
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
+ if (gl_manager_angle) {
+ gl_manager_angle->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
+ }
+ if (gl_manager_legacy) {
+ gl_manager_legacy->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -3421,8 +3432,11 @@ void DisplayServerMacOS::window_set_vsync_mode(DisplayServer::VSyncMode p_vsync_
DisplayServer::VSyncMode DisplayServerMacOS::window_get_vsync_mode(WindowID p_window) const {
_THREAD_SAFE_METHOD_
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- return (gl_manager->is_using_vsync() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED);
+ if (gl_manager_angle) {
+ return (gl_manager_angle->is_using_vsync() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED);
+ }
+ if (gl_manager_legacy) {
+ return (gl_manager_legacy->is_using_vsync() ? DisplayServer::VSyncMode::VSYNC_ENABLED : DisplayServer::VSyncMode::VSYNC_DISABLED);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -3805,8 +3819,11 @@ void DisplayServerMacOS::make_rendering_thread() {
void DisplayServerMacOS::swap_buffers() {
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->swap_buffers();
+ if (gl_manager_angle) {
+ gl_manager_angle->swap_buffers();
+ }
+ if (gl_manager_legacy) {
+ gl_manager_legacy->swap_buffers();
}
#endif
}
@@ -3826,10 +3843,10 @@ void DisplayServerMacOS::set_native_icon(const String &p_filename) {
@try {
NSData *icon_data = [[NSData alloc] initWithBytes:&data.write[0] length:len];
- ERR_FAIL_COND_MSG(!icon_data, "Error reading icon data.");
+ ERR_FAIL_NULL_MSG(icon_data, "Error reading icon data.");
NSImage *icon = [[NSImage alloc] initWithData:icon_data];
- ERR_FAIL_COND_MSG(!icon, "Error loading icon.");
+ ERR_FAIL_NULL_MSG(icon, "Error loading icon.");
[NSApp setApplicationIconImage:icon];
} @catch (NSException *exception) {
@@ -3917,6 +3934,7 @@ Vector<String> DisplayServerMacOS::get_rendering_drivers_func() {
#endif
#if defined(GLES3_ENABLED)
drivers.push_back("opengl3");
+ drivers.push_back("opengl3_angle");
#endif
return drivers;
@@ -4155,13 +4173,22 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
#if defined(GLES3_ENABLED)
if (rendering_driver == "opengl3") {
- GLManager_MacOS::ContextType opengl_api_type = GLManager_MacOS::GLES_3_0_COMPATIBLE;
- gl_manager = memnew(GLManager_MacOS(opengl_api_type));
- if (gl_manager->initialize() != OK) {
- memdelete(gl_manager);
- gl_manager = nullptr;
+ gl_manager_legacy = memnew(GLManagerLegacy_MacOS);
+ if (gl_manager_legacy->initialize() != OK) {
+ memdelete(gl_manager_legacy);
+ gl_manager_legacy = nullptr;
r_error = ERR_UNAVAILABLE;
- ERR_FAIL_MSG("Could not initialize OpenGL");
+ ERR_FAIL_MSG("Could not initialize OpenGL.");
+ return;
+ }
+ }
+ if (rendering_driver == "opengl3_angle") {
+ gl_manager_angle = memnew(GLManagerANGLE_MacOS);
+ if (gl_manager_angle->initialize() != OK) {
+ memdelete(gl_manager_angle);
+ gl_manager_angle = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ ERR_FAIL_MSG("Could not initialize OpenGL.");
}
}
#endif
@@ -4199,7 +4226,10 @@ DisplayServerMacOS::DisplayServerMacOS(const String &p_rendering_driver, WindowM
#if defined(GLES3_ENABLED)
if (rendering_driver == "opengl3") {
- RasterizerGLES3::make_current();
+ RasterizerGLES3::make_current(true);
+ }
+ if (rendering_driver == "opengl3_angle") {
+ RasterizerGLES3::make_current(false);
}
#endif
#if defined(VULKAN_ENABLED)
@@ -4230,9 +4260,13 @@ DisplayServerMacOS::~DisplayServerMacOS() {
// Destroy drivers.
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- memdelete(gl_manager);
- gl_manager = nullptr;
+ if (gl_manager_legacy) {
+ memdelete(gl_manager_legacy);
+ gl_manager_legacy = nullptr;
+ }
+ if (gl_manager_angle) {
+ memdelete(gl_manager_angle);
+ gl_manager_angle = nullptr;
}
#endif
#if defined(VULKAN_ENABLED)
diff --git a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
index 7ba1379fd0..99187fe60e 100644
--- a/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
+++ b/platform/macos/doc_classes/EditorExportPlatformMacOS.xml
@@ -22,6 +22,9 @@
<member name="application/copyright_localized" type="Dictionary" setter="" getter="">
Copyright notice for the bundle visible to the user (localized).
</member>
+ <member name="application/export_angle" type="int" setter="" getter="">
+ If set to [code]1[/code], ANGLE libraries are exported with the exported application. If set to [code]0[/code], ANGLE libraries are exported only if [member ProjectSettings.rendering/gl_compatibility/driver] is set to [code]"opengl3_angle"[/code].
+ </member>
<member name="application/icon" type="String" setter="" getter="">
Application icon file. If left empty, it will fallback to [member ProjectSettings.application/config/macos_native_icon], and then to [member ProjectSettings.application/config/icon].
</member>
diff --git a/platform/macos/export/export_plugin.cpp b/platform/macos/export/export_plugin.cpp
index 559c2c4e62..639a7699ee 100644
--- a/platform/macos/export/export_plugin.cpp
+++ b/platform/macos/export/export_plugin.cpp
@@ -384,6 +384,7 @@ void EditorExportPlatformMacOS::get_export_options(List<ExportOption> *r_options
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::DICTIONARY, "application/copyright_localized", PROPERTY_HINT_LOCALIZABLE_STRING), Dictionary()));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/min_macos_version"), "10.12"));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_angle", PROPERTY_HINT_ENUM, "Auto,Yes,No"), 0, true));
r_options->push_back(ExportOption(PropertyInfo(Variant::BOOL, "display/high_res"), true));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "xcode/platform_build"), "14C18"));
@@ -1618,6 +1619,14 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
// Now process our template.
bool found_binary = false;
+ int export_angle = p_preset->get("application/export_angle");
+ bool include_angle_libs = false;
+ if (export_angle == 0) {
+ include_angle_libs = String(GLOBAL_GET("rendering/gl_compatibility/driver.macos")) == "opengl3_angle";
+ } else if (export_angle == 1) {
+ include_angle_libs = true;
+ }
+
while (ret == UNZ_OK && err == OK) {
// Get filename.
unz_file_info info;
@@ -1665,6 +1674,20 @@ Error EditorExportPlatformMacOS::export_project(const Ref<EditorExportPreset> &p
continue; // next
}
+ if (file == "Contents/Frameworks/libEGL.dylib") {
+ if (!include_angle_libs) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; // skip
+ }
+ }
+
+ if (file == "Contents/Frameworks/libGLESv2.dylib") {
+ if (!include_angle_libs) {
+ ret = unzGoToNextFile(src_pkg_zip);
+ continue; // skip
+ }
+ }
+
if (file == "Contents/Info.plist") {
_fix_plist(p_preset, data, pkg_name);
}
diff --git a/platform/macos/gl_manager_macos_angle.h b/platform/macos/gl_manager_macos_angle.h
new file mode 100644
index 0000000000..919b8ec9c8
--- /dev/null
+++ b/platform/macos/gl_manager_macos_angle.h
@@ -0,0 +1,63 @@
+/**************************************************************************/
+/* gl_manager_macos_angle.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 GL_MANAGER_MACOS_ANGLE_H
+#define GL_MANAGER_MACOS_ANGLE_H
+
+#if defined(MACOS_ENABLED) && defined(GLES3_ENABLED)
+
+#include "core/error/error_list.h"
+#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "drivers/egl/egl_manager.h"
+#include "servers/display_server.h"
+
+#include <AppKit/AppKit.h>
+#include <ApplicationServices/ApplicationServices.h>
+#include <CoreVideo/CoreVideo.h>
+
+class GLManagerANGLE_MacOS : public EGLManager {
+private:
+ virtual const char *_get_platform_extension_name() const override;
+ virtual EGLenum _get_platform_extension_enum() const override;
+ virtual EGLenum _get_platform_api_enum() const override;
+ virtual Vector<EGLAttrib> _get_platform_display_attributes() const override;
+ virtual Vector<EGLint> _get_platform_context_attribs() const override;
+
+public:
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {}
+
+ GLManagerANGLE_MacOS() {}
+ ~GLManagerANGLE_MacOS() {}
+};
+
+#endif // MACOS_ENABLED && GLES3_ENABLED
+
+#endif // GL_MANAGER_MACOS_ANGLE_H
diff --git a/platform/macos/gl_manager_macos_angle.mm b/platform/macos/gl_manager_macos_angle.mm
new file mode 100644
index 0000000000..ec0ca3e1f3
--- /dev/null
+++ b/platform/macos/gl_manager_macos_angle.mm
@@ -0,0 +1,70 @@
+/**************************************************************************/
+/* gl_manager_macos_angle.mm */
+/**************************************************************************/
+/* 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 "gl_manager_macos_angle.h"
+
+#if defined(MACOS_ENABLED) && defined(GLES3_ENABLED)
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <EGL/eglext_angle.h>
+
+const char *GLManagerANGLE_MacOS::_get_platform_extension_name() const {
+ return "EGL_ANGLE_platform_angle";
+}
+
+EGLenum GLManagerANGLE_MacOS::_get_platform_extension_enum() const {
+ return EGL_PLATFORM_ANGLE_ANGLE;
+}
+
+Vector<EGLAttrib> GLManagerANGLE_MacOS::_get_platform_display_attributes() const {
+ Vector<EGLAttrib> ret;
+ ret.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
+ ret.push_back(EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE);
+ ret.push_back(EGL_NONE);
+
+ return ret;
+}
+
+EGLenum GLManagerANGLE_MacOS::_get_platform_api_enum() const {
+ return EGL_OPENGL_ES_API;
+}
+
+Vector<EGLint> GLManagerANGLE_MacOS::_get_platform_context_attribs() const {
+ Vector<EGLint> ret;
+ ret.push_back(EGL_CONTEXT_CLIENT_VERSION);
+ ret.push_back(3);
+ ret.push_back(EGL_NONE);
+
+ return ret;
+}
+
+#endif // MACOS_ENABLED && GLES3_ENABLED
diff --git a/platform/macos/gl_manager_macos_legacy.h b/platform/macos/gl_manager_macos_legacy.h
index 94d966f4ed..bafe825efb 100644
--- a/platform/macos/gl_manager_macos_legacy.h
+++ b/platform/macos/gl_manager_macos_legacy.h
@@ -45,17 +45,12 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations" // OpenGL is deprecated in macOS 10.14
-class GLManager_MacOS {
-public:
- enum ContextType {
- GLES_3_0_COMPATIBLE,
- };
+typedef CGLError (*CGLEnablePtr)(CGLContextObj ctx, CGLContextEnable pname);
+typedef CGLError (*CGLSetParameterPtr)(CGLContextObj ctx, CGLContextParameter pname, const GLint *params);
+typedef CGLContextObj (*CGLGetCurrentContextPtr)(void);
-private:
+class GLManagerLegacy_MacOS {
struct GLWindow {
- int width = 0;
- int height = 0;
-
id window_view = nullptr;
NSOpenGLContext *context = nullptr;
};
@@ -68,23 +63,21 @@ private:
Error create_context(GLWindow &win);
bool use_vsync = false;
- ContextType context_type;
+ CGLEnablePtr CGLEnable = nullptr;
+ CGLSetParameterPtr CGLSetParameter = nullptr;
+ CGLGetCurrentContextPtr CGLGetCurrentContext = nullptr;
public:
Error window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height);
void window_destroy(DisplayServer::WindowID p_window_id);
void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
- int window_get_width(DisplayServer::WindowID p_window_id = 0);
- int window_get_height(DisplayServer::WindowID p_window_id = 0);
-
void release_current();
void make_current();
void swap_buffers();
void window_make_current(DisplayServer::WindowID p_window_id);
- void window_update(DisplayServer::WindowID p_window_id);
void window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled);
Error initialize();
@@ -94,8 +87,8 @@ public:
NSOpenGLContext *get_context(DisplayServer::WindowID p_window_id);
- GLManager_MacOS(ContextType p_context_type);
- ~GLManager_MacOS();
+ GLManagerLegacy_MacOS();
+ ~GLManagerLegacy_MacOS();
};
#pragma clang diagnostic push
diff --git a/platform/macos/gl_manager_macos_legacy.mm b/platform/macos/gl_manager_macos_legacy.mm
index 550e2d5c59..3e5a96bffd 100644
--- a/platform/macos/gl_manager_macos_legacy.mm
+++ b/platform/macos/gl_manager_macos_legacy.mm
@@ -38,7 +38,7 @@
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wdeprecated-declarations" // OpenGL is deprecated in macOS 10.14
-Error GLManager_MacOS::create_context(GLWindow &win) {
+Error GLManagerLegacy_MacOS::create_context(GLWindow &win) {
NSOpenGLPixelFormatAttribute attributes[] = {
NSOpenGLPFADoubleBuffer,
NSOpenGLPFAClosestPolicy,
@@ -64,10 +64,8 @@ Error GLManager_MacOS::create_context(GLWindow &win) {
return OK;
}
-Error GLManager_MacOS::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) {
+Error GLManagerLegacy_MacOS::window_create(DisplayServer::WindowID p_window_id, id p_view, int p_width, int p_height) {
GLWindow win;
- win.width = p_width;
- win.height = p_height;
win.window_view = p_view;
if (create_context(win) != OK) {
@@ -80,16 +78,13 @@ Error GLManager_MacOS::window_create(DisplayServer::WindowID p_window_id, id p_v
return OK;
}
-void GLManager_MacOS::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {
+void GLManagerLegacy_MacOS::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {
if (!windows.has(p_window_id)) {
return;
}
GLWindow &win = windows[p_window_id];
- win.width = p_width;
- win.height = p_height;
-
GLint dim[2];
dim[0] = p_width;
dim[1] = p_height;
@@ -104,25 +99,7 @@ void GLManager_MacOS::window_resize(DisplayServer::WindowID p_window_id, int p_w
[win.context update];
}
-int GLManager_MacOS::window_get_width(DisplayServer::WindowID p_window_id) {
- if (!windows.has(p_window_id)) {
- return 0;
- }
-
- GLWindow &win = windows[p_window_id];
- return win.width;
-}
-
-int GLManager_MacOS::window_get_height(DisplayServer::WindowID p_window_id) {
- if (!windows.has(p_window_id)) {
- return 0;
- }
-
- GLWindow &win = windows[p_window_id];
- return win.height;
-}
-
-void GLManager_MacOS::window_destroy(DisplayServer::WindowID p_window_id) {
+void GLManagerLegacy_MacOS::window_destroy(DisplayServer::WindowID p_window_id) {
if (!windows.has(p_window_id)) {
return;
}
@@ -134,7 +111,7 @@ void GLManager_MacOS::window_destroy(DisplayServer::WindowID p_window_id) {
windows.erase(p_window_id);
}
-void GLManager_MacOS::release_current() {
+void GLManagerLegacy_MacOS::release_current() {
if (current_window == DisplayServer::INVALID_WINDOW_ID) {
return;
}
@@ -142,7 +119,7 @@ void GLManager_MacOS::release_current() {
[NSOpenGLContext clearCurrentContext];
}
-void GLManager_MacOS::window_make_current(DisplayServer::WindowID p_window_id) {
+void GLManagerLegacy_MacOS::window_make_current(DisplayServer::WindowID p_window_id) {
if (current_window == p_window_id) {
return;
}
@@ -156,7 +133,7 @@ void GLManager_MacOS::window_make_current(DisplayServer::WindowID p_window_id) {
current_window = p_window_id;
}
-void GLManager_MacOS::make_current() {
+void GLManagerLegacy_MacOS::make_current() {
if (current_window == DisplayServer::INVALID_WINDOW_ID) {
return;
}
@@ -168,21 +145,12 @@ void GLManager_MacOS::make_current() {
[win.context makeCurrentContext];
}
-void GLManager_MacOS::swap_buffers() {
+void GLManagerLegacy_MacOS::swap_buffers() {
GLWindow &win = windows[current_window];
[win.context flushBuffer];
}
-void GLManager_MacOS::window_update(DisplayServer::WindowID p_window_id) {
- if (!windows.has(p_window_id)) {
- return;
- }
-
- GLWindow &win = windows[p_window_id];
- [win.context update];
-}
-
-void GLManager_MacOS::window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled) {
+void GLManagerLegacy_MacOS::window_set_per_pixel_transparency_enabled(DisplayServer::WindowID p_window_id, bool p_enabled) {
if (!windows.has(p_window_id)) {
return;
}
@@ -198,26 +166,28 @@ void GLManager_MacOS::window_set_per_pixel_transparency_enabled(DisplayServer::W
[win.context update];
}
-Error GLManager_MacOS::initialize() {
+Error GLManagerLegacy_MacOS::initialize() {
return OK;
}
-void GLManager_MacOS::set_use_vsync(bool p_use) {
+void GLManagerLegacy_MacOS::set_use_vsync(bool p_use) {
use_vsync = p_use;
CGLContextObj ctx = CGLGetCurrentContext();
if (ctx) {
GLint swapInterval = p_use ? 1 : 0;
- CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval);
+ if (CGLSetParameter(ctx, kCGLCPSwapInterval, &swapInterval) != kCGLNoError) {
+ WARN_PRINT("Could not set V-Sync mode.");
+ }
use_vsync = p_use;
}
}
-bool GLManager_MacOS::is_using_vsync() const {
+bool GLManagerLegacy_MacOS::is_using_vsync() const {
return use_vsync;
}
-NSOpenGLContext *GLManager_MacOS::get_context(DisplayServer::WindowID p_window_id) {
+NSOpenGLContext *GLManagerLegacy_MacOS::get_context(DisplayServer::WindowID p_window_id) {
if (!windows.has(p_window_id)) {
return nullptr;
}
@@ -226,11 +196,16 @@ NSOpenGLContext *GLManager_MacOS::get_context(DisplayServer::WindowID p_window_i
return win.context;
}
-GLManager_MacOS::GLManager_MacOS(ContextType p_context_type) {
- context_type = p_context_type;
+GLManagerLegacy_MacOS::GLManagerLegacy_MacOS() {
+ CFBundleRef framework = CFBundleGetBundleWithIdentifier(CFSTR("com.apple.opengl"));
+ CFBundleLoadExecutable(framework);
+
+ CGLEnable = (CGLEnablePtr)CFBundleGetFunctionPointerForName(framework, CFSTR("CGLEnable"));
+ CGLSetParameter = (CGLSetParameterPtr)CFBundleGetFunctionPointerForName(framework, CFSTR("CGLSetParameter"));
+ CGLGetCurrentContext = (CGLGetCurrentContextPtr)CFBundleGetFunctionPointerForName(framework, CFSTR("CGLGetCurrentContext"));
}
-GLManager_MacOS::~GLManager_MacOS() {
+GLManagerLegacy_MacOS::~GLManagerLegacy_MacOS() {
release_current();
}
diff --git a/platform/macos/godot_content_view.mm b/platform/macos/godot_content_view.mm
index 8b6e1cdb79..22a9aa14c0 100644
--- a/platform/macos/godot_content_view.mm
+++ b/platform/macos/godot_content_view.mm
@@ -139,12 +139,6 @@
return [[CAMetalLayer class] layer];
}
-- (void)updateLayer {
- DisplayServerMacOS *ds = (DisplayServerMacOS *)DisplayServer::get_singleton();
- ds->window_update(window_id);
- [super updateLayer];
-}
-
- (BOOL)wantsUpdateLayer {
return YES;
}
diff --git a/platform/macos/os_macos.mm b/platform/macos/os_macos.mm
index c17ea95f4f..1b8ca0134d 100644
--- a/platform/macos/os_macos.mm
+++ b/platform/macos/os_macos.mm
@@ -231,7 +231,7 @@ Error OS_MacOS::open_dynamic_library(const String p_path, void *&p_library_handl
}
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
- ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
+ ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
if (r_resolved_path != nullptr) {
*r_resolved_path = path;
diff --git a/platform/macos/platform_config.h b/platform/macos/platform_config.h
index 65a898dcc1..1a571b689a 100644
--- a/platform/macos/platform_config.h
+++ b/platform/macos/platform_config.h
@@ -30,5 +30,4 @@
#include <alloca.h>
-#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h"
#define PTHREAD_RENAME_SELF
diff --git a/platform/macos/platform_gl.h b/platform/macos/platform_gl.h
new file mode 100644
index 0000000000..3bad9d5a5f
--- /dev/null
+++ b/platform/macos/platform_gl.h
@@ -0,0 +1,52 @@
+/**************************************************************************/
+/* platform_gl.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 PLATFORM_GL_H
+#define PLATFORM_GL_H
+
+#ifndef GL_API_ENABLED
+#define GL_API_ENABLED // Allow using desktop GL.
+#endif
+
+#ifndef GLES_API_ENABLED
+#define GLES_API_ENABLED // Allow using GLES (ANGLE).
+#endif
+
+#ifdef EGL_STATIC
+#define KHRONOS_STATIC 1
+#include "thirdparty/angle/include/EGL/egl.h"
+#include "thirdparty/angle/include/EGL/eglext.h"
+#undef KHRONOS_STATIC
+#else
+#include "thirdparty/glad/glad/egl.h"
+#endif
+#include "thirdparty/glad/glad/gl.h"
+
+#endif // PLATFORM_GL_H
diff --git a/platform/web/detect.py b/platform/web/detect.py
index 7b2e5646d6..3e2bb5cd30 100644
--- a/platform/web/detect.py
+++ b/platform/web/detect.py
@@ -118,11 +118,6 @@ def configure(env: "Environment"):
else:
env.Append(CCFLAGS=["-flto"])
env.Append(LINKFLAGS=["-flto"])
- # Workaround https://github.com/emscripten-core/emscripten/issues/19781.
- cc_version = get_compiler_version(env)
- cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"]))
- if cc_semver >= (3, 1, 42):
- env.Append(LINKFLAGS=["-Wl,-u,scalbnf"])
# Sanitizers
if env["use_ubsan"]:
@@ -204,9 +199,16 @@ def configure(env: "Environment"):
env.Append(LINKFLAGS=["-s", "PTHREAD_POOL_SIZE=8"])
env.Append(LINKFLAGS=["-s", "WASM_MEM_MAX=2048MB"])
+ # Get version info for checks below.
+ cc_version = get_compiler_version(env)
+ cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"]))
+
+ if env["lto"] != "none":
+ # Workaround https://github.com/emscripten-core/emscripten/issues/19781.
+ if cc_semver >= (3, 1, 42) and cc_semver < (3, 1, 46):
+ env.Append(LINKFLAGS=["-Wl,-u,scalbnf"])
+
if env["dlink_enabled"]:
- cc_version = get_compiler_version(env)
- cc_semver = (int(cc_version["major"]), int(cc_version["minor"]), int(cc_version["patch"]))
if cc_semver < (3, 1, 14):
print("GDExtension support requires emscripten >= 3.1.14, detected: %s.%s.%s" % cc_semver)
sys.exit(255)
diff --git a/platform/web/display_server_web.cpp b/platform/web/display_server_web.cpp
index 93b0496d74..aac1401f23 100644
--- a/platform/web/display_server_web.cpp
+++ b/platform/web/display_server_web.cpp
@@ -817,7 +817,7 @@ DisplayServerWeb::DisplayServerWeb(const String &p_rendering_driver, WindowMode
if (!emscripten_webgl_enable_extension(webgl_ctx, "OVR_multiview2")) {
print_verbose("Failed to enable WebXR extension.");
}
- RasterizerGLES3::make_current();
+ RasterizerGLES3::make_current(false);
} else {
OS::get_singleton()->alert(
diff --git a/platform/web/os_web.cpp b/platform/web/os_web.cpp
index 9ee8f90e89..f038f0248a 100644
--- a/platform/web/os_web.cpp
+++ b/platform/web/os_web.cpp
@@ -232,7 +232,7 @@ bool OS_Web::is_userfs_persistent() const {
Error OS_Web::open_dynamic_library(const String p_path, void *&p_library_handle, bool p_also_set_library_path, String *r_resolved_path) {
String path = p_path.get_file();
p_library_handle = dlopen(path.utf8().get_data(), RTLD_NOW);
- ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
+ ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, dlerror()));
if (r_resolved_path != nullptr) {
*r_resolved_path = path;
diff --git a/platform/web/platform_config.h b/platform/web/platform_config.h
index 78deaadcfd..c3189bccfb 100644
--- a/platform/web/platform_config.h
+++ b/platform/web/platform_config.h
@@ -29,5 +29,3 @@
/**************************************************************************/
#include <alloca.h>
-
-#define OPENGL_INCLUDE_H "platform/web/godot_webgl2.h"
diff --git a/platform/web/platform_gl.h b/platform/web/platform_gl.h
new file mode 100644
index 0000000000..be6e1462a7
--- /dev/null
+++ b/platform/web/platform_gl.h
@@ -0,0 +1,40 @@
+/**************************************************************************/
+/* platform_gl.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 PLATFORM_GL_H
+#define PLATFORM_GL_H
+
+#ifndef GLES_API_ENABLED
+#define GLES_API_ENABLED // Allow using GLES.
+#endif
+
+#include "platform/web/godot_webgl2.h"
+
+#endif // PLATFORM_GL_H
diff --git a/platform/windows/SCsub b/platform/windows/SCsub
index d7dd224199..1b6908d2bb 100644
--- a/platform/windows/SCsub
+++ b/platform/windows/SCsub
@@ -16,7 +16,9 @@ common_win = [
"tts_windows.cpp",
"windows_terminal_logger.cpp",
"vulkan_context_win.cpp",
- "gl_manager_windows.cpp",
+ "gl_manager_windows_native.cpp",
+ "gl_manager_windows_angle.cpp",
+ "wgl_detect_version.cpp",
]
common_win_wrap = [
diff --git a/platform/windows/detect.py b/platform/windows/detect.py
index 6e56f2a525..340b95e4ab 100644
--- a/platform/windows/detect.py
+++ b/platform/windows/detect.py
@@ -186,6 +186,7 @@ def get_opts():
BoolVariable("use_asan", "Use address sanitizer (ASAN)", False),
BoolVariable("debug_crt", "Compile with MSVC's debug CRT (/MDd)", False),
BoolVariable("incremental_link", "Use MSVC incremental linking. May increase or decrease build times.", False),
+ ("angle_libs", "Path to the ANGLE static libraries", ""),
]
@@ -431,7 +432,16 @@ def configure_msvc(env, vcvars_msvc_config):
if env["opengl3"]:
env.AppendUnique(CPPDEFINES=["GLES3_ENABLED"])
- LIBS += ["opengl32"]
+ if env["angle_libs"] != "":
+ env.AppendUnique(CPPDEFINES=["EGL_STATIC"])
+ env.Append(LIBPATH=[env["angle_libs"]])
+ LIBS += [
+ "libANGLE.windows." + env["arch"],
+ "libEGL.windows." + env["arch"],
+ "libGLES.windows." + env["arch"],
+ ]
+ LIBS += ["dxgi", "d3d9", "d3d11"]
+ env.Prepend(CPPPATH=["#thirdparty/angle/include"])
env.Append(LINKFLAGS=[p + env["LIBSUFFIX"] for p in LIBS])
@@ -614,7 +624,18 @@ def configure_mingw(env):
if env["opengl3"]:
env.Append(CPPDEFINES=["GLES3_ENABLED"])
- env.Append(LIBS=["opengl32"])
+ if env["angle_libs"] != "":
+ env.AppendUnique(CPPDEFINES=["EGL_STATIC"])
+ env.Append(LIBPATH=[env["angle_libs"]])
+ env.Append(
+ LIBS=[
+ "EGL.windows." + env["arch"],
+ "GLES.windows." + env["arch"],
+ "ANGLE.windows." + env["arch"],
+ ]
+ )
+ env.Append(LIBS=["dxgi", "d3d9", "d3d11"])
+ env.Prepend(CPPPATH=["#thirdparty/angle/include"])
env.Append(CPPDEFINES=["MINGW_ENABLED", ("MINGW_HAS_SECURE_API", 1)])
diff --git a/platform/windows/display_server_windows.cpp b/platform/windows/display_server_windows.cpp
index 5863a75324..113f777964 100644
--- a/platform/windows/display_server_windows.cpp
+++ b/platform/windows/display_server_windows.cpp
@@ -31,6 +31,7 @@
#include "display_server_windows.h"
#include "os_windows.h"
+#include "wgl_detect_version.h"
#include "core/config/project_settings.h"
#include "core/io/marshalls.h"
@@ -184,37 +185,37 @@ void DisplayServerWindows::_register_raw_input_devices(WindowID p_target_window)
}
bool DisplayServerWindows::tts_is_speaking() const {
- ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->is_speaking();
}
bool DisplayServerWindows::tts_is_paused() const {
- ERR_FAIL_COND_V_MSG(!tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, false, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->is_paused();
}
TypedArray<Dictionary> DisplayServerWindows::tts_get_voices() const {
- ERR_FAIL_COND_V_MSG(!tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_V_MSG(tts, TypedArray<Dictionary>(), "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
return tts->get_voices();
}
void DisplayServerWindows::tts_speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->speak(p_text, p_voice, p_volume, p_pitch, p_rate, p_utterance_id, p_interrupt);
}
void DisplayServerWindows::tts_pause() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->pause();
}
void DisplayServerWindows::tts_resume() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->resume();
}
void DisplayServerWindows::tts_stop() {
- ERR_FAIL_COND_MSG(!tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
+ ERR_FAIL_NULL_MSG(tts, "Enable the \"audio/general/text_to_speech\" project setting to use text-to-speech.");
tts->stop();
}
@@ -413,7 +414,7 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
Char16String utf16 = text.utf16();
HGLOBAL mem = GlobalAlloc(GMEM_MOVEABLE, (utf16.length() + 1) * sizeof(WCHAR));
- ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
+ ERR_FAIL_NULL_MSG(mem, "Unable to allocate memory for clipboard contents.");
LPWSTR lptstrCopy = (LPWSTR)GlobalLock(mem);
memcpy(lptstrCopy, utf16.get_data(), (utf16.length() + 1) * sizeof(WCHAR));
@@ -424,7 +425,7 @@ void DisplayServerWindows::clipboard_set(const String &p_text) {
// Set the CF_TEXT version (not needed?).
CharString utf8 = text.utf8();
mem = GlobalAlloc(GMEM_MOVEABLE, utf8.length() + 1);
- ERR_FAIL_COND_MSG(mem == nullptr, "Unable to allocate memory for clipboard contents.");
+ ERR_FAIL_NULL_MSG(mem, "Unable to allocate memory for clipboard contents.");
LPTSTR ptr = (LPTSTR)GlobalLock(mem);
memcpy(ptr, utf8.get_data(), utf8.length());
@@ -1070,8 +1071,11 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
}
#endif
#ifdef GLES3_ENABLED
- if (gl_manager) {
- gl_manager->window_destroy(p_window);
+ if (gl_manager_angle) {
+ gl_manager_angle->window_destroy(p_window);
+ }
+ if (gl_manager_native) {
+ gl_manager_native->window_destroy(p_window);
}
#endif
@@ -1089,8 +1093,11 @@ void DisplayServerWindows::delete_sub_window(WindowID p_window) {
void DisplayServerWindows::gl_window_make_current(DisplayServer::WindowID p_window_id) {
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_make_current(p_window_id);
+ if (gl_manager_angle) {
+ gl_manager_angle->window_make_current(p_window_id);
+ }
+ if (gl_manager_native) {
+ gl_manager_native->window_make_current(p_window_id);
}
#endif
}
@@ -1106,14 +1113,18 @@ int64_t DisplayServerWindows::window_get_native_handle(HandleType p_handle_type,
}
#if defined(GLES3_ENABLED)
case WINDOW_VIEW: {
- if (gl_manager) {
- return (int64_t)gl_manager->get_hdc(p_window);
+ if (gl_manager_native) {
+ return (int64_t)gl_manager_native->get_hdc(p_window);
+ } else {
+ return (int64_t)GetDC(windows[p_window].hWnd);
}
- return 0;
}
case OPENGL_CONTEXT: {
- if (gl_manager) {
- return (int64_t)gl_manager->get_hglrc(p_window);
+ if (gl_manager_native) {
+ return (int64_t)gl_manager_native->get_hglrc(p_window);
+ }
+ if (gl_manager_angle) {
+ return (int64_t)gl_manager_angle->get_context(p_window);
}
return 0;
}
@@ -1447,8 +1458,11 @@ void DisplayServerWindows::window_set_size(const Size2i p_size, WindowID p_windo
}
#endif
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->window_resize(p_window, w, h);
+ if (gl_manager_native) {
+ gl_manager_native->window_resize(p_window, w, h);
+ }
+ if (gl_manager_angle) {
+ gl_manager_angle->window_resize(p_window, w, h);
}
#endif
@@ -1511,7 +1525,7 @@ void DisplayServerWindows::_get_window_style(bool p_main_window, bool p_fullscre
if (p_fullscreen || p_borderless) {
r_style |= WS_POPUP; // p_borderless was WS_EX_TOOLWINDOW in the past.
- if (p_fullscreen && p_multiwindow_fs) {
+ if ((p_fullscreen && p_multiwindow_fs) || p_maximized) {
r_style |= WS_BORDER; // Allows child windows to be displayed on top of full screen.
}
} else {
@@ -2318,8 +2332,11 @@ void DisplayServerWindows::make_rendering_thread() {
void DisplayServerWindows::swap_buffers() {
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->swap_buffers();
+ if (gl_manager_angle) {
+ gl_manager_angle->swap_buffers();
+ }
+ if (gl_manager_native) {
+ gl_manager_native->swap_buffers();
}
#endif
}
@@ -2465,7 +2482,7 @@ void DisplayServerWindows::set_icon(const Ref<Image> &p_icon) {
}
HICON hicon = CreateIconFromResource(icon_bmp, icon_len, TRUE, 0x00030000);
- ERR_FAIL_COND(!hicon);
+ ERR_FAIL_NULL(hicon);
icon = img;
@@ -2490,8 +2507,11 @@ void DisplayServerWindows::window_set_vsync_mode(DisplayServer::VSyncMode p_vsyn
#endif
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- gl_manager->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED);
+ if (gl_manager_native) {
+ gl_manager_native->set_use_vsync(p_window, p_vsync_mode != DisplayServer::VSYNC_DISABLED);
+ }
+ if (gl_manager_angle) {
+ gl_manager_angle->set_use_vsync(p_vsync_mode != DisplayServer::VSYNC_DISABLED);
}
#endif
}
@@ -2505,8 +2525,11 @@ DisplayServer::VSyncMode DisplayServerWindows::window_get_vsync_mode(WindowID p_
#endif
#if defined(GLES3_ENABLED)
- if (gl_manager) {
- return gl_manager->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
+ if (gl_manager_native) {
+ return gl_manager_native->is_using_vsync(p_window) ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
+ }
+ if (gl_manager_angle) {
+ return gl_manager_angle->is_using_vsync() ? DisplayServer::VSYNC_ENABLED : DisplayServer::VSYNC_DISABLED;
}
#endif
@@ -2829,6 +2852,30 @@ LRESULT DisplayServerWindows::WndProc(HWND hWnd, UINT uMsg, WPARAM wParam, LPARA
// Process window messages.
switch (uMsg) {
+ case WM_NCPAINT: {
+ if (RenderingServer::get_singleton() && (windows[window_id].borderless || (windows[window_id].fullscreen && windows[window_id].multiwindow_fs))) {
+ Color color = RenderingServer::get_singleton()->get_default_clear_color();
+ HDC hdc = GetWindowDC(hWnd);
+ if (hdc) {
+ HPEN pen = CreatePen(PS_SOLID, 1, RGB(color.r * 255.f, color.g * 255.f, color.b * 255.f));
+ if (pen) {
+ HGDIOBJ prev_pen = SelectObject(hdc, pen);
+ HGDIOBJ prev_brush = SelectObject(hdc, GetStockObject(NULL_BRUSH));
+
+ RECT rc;
+ GetWindowRect(hWnd, &rc);
+ OffsetRect(&rc, -rc.left, -rc.top);
+ Rectangle(hdc, rc.left, rc.top, rc.right, rc.bottom);
+
+ SelectObject(hdc, prev_pen);
+ SelectObject(hdc, prev_brush);
+ DeleteObject(pen);
+ }
+ ReleaseDC(hWnd, hdc);
+ }
+ return 0;
+ }
+ } break;
case WM_NCHITTEST: {
if (windows[window_id].mpass) {
return HTTRANSPARENT;
@@ -4224,10 +4271,20 @@ DisplayServer::WindowID DisplayServerWindows::_create_window(WindowMode p_mode,
#endif
#ifdef GLES3_ENABLED
- if (gl_manager) {
- if (gl_manager->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
- memdelete(gl_manager);
- gl_manager = nullptr;
+ if (gl_manager_native) {
+ if (gl_manager_native->window_create(id, wd.hWnd, hInstance, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
+ memdelete(gl_manager_native);
+ gl_manager_native = nullptr;
+ windows.erase(id);
+ ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
+ }
+ window_set_vsync_mode(p_vsync_mode, id);
+ }
+
+ if (gl_manager_angle) {
+ if (gl_manager_angle->window_create(id, nullptr, wd.hWnd, WindowRect.right - WindowRect.left, WindowRect.bottom - WindowRect.top) != OK) {
+ memdelete(gl_manager_angle);
+ gl_manager_angle = nullptr;
windows.erase(id);
ERR_FAIL_V_MSG(INVALID_WINDOW_ID, "Failed to create an OpenGL window.");
}
@@ -4523,18 +4580,36 @@ DisplayServerWindows::DisplayServerWindows(const String &p_rendering_driver, Win
#if defined(GLES3_ENABLED)
if (rendering_driver == "opengl3") {
- GLManager_Windows::ContextType opengl_api_type = GLManager_Windows::GLES_3_0_COMPATIBLE;
+ int gl_version = detect_wgl_version();
+ if (gl_version < 30003) {
+ WARN_PRINT("Your video card drivers seem not to support the required OpenGL 3.3 version, switching to ANGLE.");
+ rendering_driver = "opengl3_angle";
+ }
+ }
- gl_manager = memnew(GLManager_Windows(opengl_api_type));
+ if (rendering_driver == "opengl3") {
+ gl_manager_native = memnew(GLManagerNative_Windows);
- if (gl_manager->initialize() != OK) {
- memdelete(gl_manager);
- gl_manager = nullptr;
+ if (gl_manager_native->initialize() != OK) {
+ memdelete(gl_manager_native);
+ gl_manager_native = nullptr;
r_error = ERR_UNAVAILABLE;
return;
}
- RasterizerGLES3::make_current();
+ RasterizerGLES3::make_current(true);
+ }
+ if (rendering_driver == "opengl3_angle") {
+ gl_manager_angle = memnew(GLManagerANGLE_Windows);
+
+ if (gl_manager_angle->initialize() != OK) {
+ memdelete(gl_manager_angle);
+ gl_manager_angle = nullptr;
+ r_error = ERR_UNAVAILABLE;
+ return;
+ }
+
+ RasterizerGLES3::make_current(false);
}
#endif
@@ -4608,6 +4683,7 @@ Vector<String> DisplayServerWindows::get_rendering_drivers_func() {
#endif
#ifdef GLES3_ENABLED
drivers.push_back("opengl3");
+ drivers.push_back("opengl3_angle");
#endif
return drivers;
@@ -4693,9 +4769,13 @@ DisplayServerWindows::~DisplayServerWindows() {
SystemParametersInfoA(SPI_SETMOUSETRAILS, restore_mouse_trails, 0, 0);
}
#ifdef GLES3_ENABLED
- if (gl_manager) {
- memdelete(gl_manager);
- gl_manager = nullptr;
+ if (gl_manager_angle) {
+ memdelete(gl_manager_angle);
+ gl_manager_angle = nullptr;
+ }
+ if (gl_manager_native) {
+ memdelete(gl_manager_native);
+ gl_manager_native = nullptr;
}
#endif
if (tts) {
diff --git a/platform/windows/display_server_windows.h b/platform/windows/display_server_windows.h
index 59c4442604..28f2f7e6ff 100644
--- a/platform/windows/display_server_windows.h
+++ b/platform/windows/display_server_windows.h
@@ -59,8 +59,9 @@
#endif
#if defined(GLES3_ENABLED)
-#include "gl_manager_windows.h"
-#endif
+#include "gl_manager_windows_angle.h"
+#include "gl_manager_windows_native.h"
+#endif // GLES3_ENABLED
#include <io.h>
#include <stdio.h>
@@ -335,7 +336,8 @@ class DisplayServerWindows : public DisplayServer {
Point2i center;
#if defined(GLES3_ENABLED)
- GLManager_Windows *gl_manager = nullptr;
+ GLManagerANGLE_Windows *gl_manager_angle = nullptr;
+ GLManagerNative_Windows *gl_manager_native = nullptr;
#endif
#if defined(VULKAN_ENABLED)
diff --git a/platform/windows/doc_classes/EditorExportPlatformWindows.xml b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
index fc068efc75..2a286de100 100644
--- a/platform/windows/doc_classes/EditorExportPlatformWindows.xml
+++ b/platform/windows/doc_classes/EditorExportPlatformWindows.xml
@@ -18,6 +18,9 @@
<member name="application/copyright" type="String" setter="" getter="">
Copyright notice for the bundle visible to the user. Optional. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
+ <member name="application/export_angle" type="int" setter="" getter="">
+ If set to [code]1[/code], ANGLE libraries are exported with the exported application. If set to [code]0[/code], ANGLE libraries are exported only if [member ProjectSettings.rendering/gl_compatibility/driver] is set to [code]"opengl3_angle"[/code].
+ </member>
<member name="application/file_description" type="String" setter="" getter="">
File description to be presented to users. Required. See [url=https://learn.microsoft.com/en-us/windows/win32/menurc/stringfileinfo-block]StringFileInfo[/url].
</member>
diff --git a/platform/windows/export/export_plugin.cpp b/platform/windows/export/export_plugin.cpp
index d2d4d78113..4185c36d77 100644
--- a/platform/windows/export/export_plugin.cpp
+++ b/platform/windows/export/export_plugin.cpp
@@ -179,6 +179,35 @@ Error EditorExportPlatformWindows::modify_template(const Ref<EditorExportPreset>
}
Error EditorExportPlatformWindows::export_project(const Ref<EditorExportPreset> &p_preset, bool p_debug, const String &p_path, int p_flags) {
+ int export_angle = p_preset->get("application/export_angle");
+ bool include_angle_libs = false;
+ if (export_angle == 0) {
+ include_angle_libs = String(GLOBAL_GET("rendering/gl_compatibility/driver.windows")) == "opengl3_angle";
+ } else if (export_angle == 1) {
+ include_angle_libs = true;
+ }
+
+ if (include_angle_libs) {
+ String custom_debug = p_preset->get("custom_template/debug");
+ String custom_release = p_preset->get("custom_template/release");
+ String arch = p_preset->get("binary_format/architecture");
+
+ String template_path = p_debug ? custom_debug : custom_release;
+
+ template_path = template_path.strip_edges();
+
+ if (template_path.is_empty()) {
+ template_path = find_export_template(get_template_file_name(p_debug ? "debug" : "release", arch));
+ }
+ Ref<DirAccess> da = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
+ if (da->file_exists(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"))) {
+ da->copy(template_path.get_base_dir().path_join("libEGL." + arch + ".dll"), p_path.get_base_dir().path_join("libEGL.dll"), get_chmod_flags());
+ }
+ if (da->file_exists(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"))) {
+ da->copy(template_path.get_base_dir().path_join("libGLESv2." + arch + ".dll"), p_path.get_base_dir().path_join("libGLESv2.dll"), get_chmod_flags());
+ }
+ }
+
bool export_as_zip = p_path.ends_with("zip");
bool embedded = p_preset->get("binary_format/embed_pck");
@@ -311,7 +340,7 @@ bool EditorExportPlatformWindows::get_export_option_visibility(const EditorExpor
// Hide resources.
bool mod_res = p_preset->get("application/modify_resources");
- if (!mod_res && p_option != "application/modify_resources" && p_option.begins_with("application/")) {
+ if (!mod_res && p_option != "application/modify_resources" && p_option != "application/export_angle" && p_option.begins_with("application/")) {
return false;
}
@@ -350,6 +379,7 @@ void EditorExportPlatformWindows::get_export_options(List<ExportOption> *r_optio
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/file_description"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/copyright"), ""));
r_options->push_back(ExportOption(PropertyInfo(Variant::STRING, "application/trademarks"), ""));
+ r_options->push_back(ExportOption(PropertyInfo(Variant::INT, "application/export_angle", PROPERTY_HINT_ENUM, "Auto,Yes,No"), 0, true));
String run_script = "Expand-Archive -LiteralPath '{temp_dir}\\{archive_name}' -DestinationPath '{temp_dir}'\n"
"$action = New-ScheduledTaskAction -Execute '{temp_dir}\\{exe_name}' -Argument '{cmd_args}'\n"
diff --git a/platform/windows/gl_manager_windows_angle.cpp b/platform/windows/gl_manager_windows_angle.cpp
new file mode 100644
index 0000000000..3086edc7f2
--- /dev/null
+++ b/platform/windows/gl_manager_windows_angle.cpp
@@ -0,0 +1,70 @@
+/**************************************************************************/
+/* gl_manager_windows_angle.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 "gl_manager_windows_angle.h"
+
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+#include <stdio.h>
+#include <stdlib.h>
+
+#include <EGL/eglext_angle.h>
+
+const char *GLManagerANGLE_Windows::_get_platform_extension_name() const {
+ return "EGL_ANGLE_platform_angle";
+}
+
+EGLenum GLManagerANGLE_Windows::_get_platform_extension_enum() const {
+ return EGL_PLATFORM_ANGLE_ANGLE;
+}
+
+Vector<EGLAttrib> GLManagerANGLE_Windows::_get_platform_display_attributes() const {
+ Vector<EGLAttrib> ret;
+ ret.push_back(EGL_PLATFORM_ANGLE_TYPE_ANGLE);
+ ret.push_back(EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE);
+ ret.push_back(EGL_NONE);
+
+ return ret;
+}
+
+EGLenum GLManagerANGLE_Windows::_get_platform_api_enum() const {
+ return EGL_OPENGL_ES_API;
+}
+
+Vector<EGLint> GLManagerANGLE_Windows::_get_platform_context_attribs() const {
+ Vector<EGLint> ret;
+ ret.push_back(EGL_CONTEXT_CLIENT_VERSION);
+ ret.push_back(3);
+ ret.push_back(EGL_NONE);
+
+ return ret;
+}
+
+#endif // WINDOWS_ENABLED && GLES3_ENABLED
diff --git a/platform/windows/gl_manager_windows_angle.h b/platform/windows/gl_manager_windows_angle.h
new file mode 100644
index 0000000000..d8dc651cfd
--- /dev/null
+++ b/platform/windows/gl_manager_windows_angle.h
@@ -0,0 +1,61 @@
+/**************************************************************************/
+/* gl_manager_windows_angle.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 GL_MANAGER_WINDOWS_ANGLE_H
+#define GL_MANAGER_WINDOWS_ANGLE_H
+
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+#include "core/error/error_list.h"
+#include "core/os/os.h"
+#include "core/templates/local_vector.h"
+#include "drivers/egl/egl_manager.h"
+#include "servers/display_server.h"
+
+#include <windows.h>
+
+class GLManagerANGLE_Windows : public EGLManager {
+private:
+ virtual const char *_get_platform_extension_name() const override;
+ virtual EGLenum _get_platform_extension_enum() const override;
+ virtual EGLenum _get_platform_api_enum() const override;
+ virtual Vector<EGLAttrib> _get_platform_display_attributes() const override;
+ virtual Vector<EGLint> _get_platform_context_attribs() const override;
+
+public:
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {}
+
+ GLManagerANGLE_Windows(){};
+ ~GLManagerANGLE_Windows(){};
+};
+
+#endif // WINDOWS_ENABLED && GLES3_ENABLED
+
+#endif // GL_MANAGER_WINDOWS_ANGLE_H
diff --git a/platform/windows/gl_manager_windows.cpp b/platform/windows/gl_manager_windows_native.cpp
index d3972c7bbc..2e41946eb2 100644
--- a/platform/windows/gl_manager_windows.cpp
+++ b/platform/windows/gl_manager_windows_native.cpp
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* gl_manager_windows.cpp */
+/* gl_manager_windows_native.cpp */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,7 +28,7 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#include "gl_manager_windows.h"
+#include "gl_manager_windows_native.h"
#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
@@ -52,11 +52,14 @@
#if defined(__GNUC__)
// Workaround GCC warning from -Wcast-function-type.
-#define wglGetProcAddress (void *)wglGetProcAddress
#define GetProcAddress (void *)GetProcAddress
#endif
+typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXT)(HDC);
+typedef BOOL(APIENTRY *PFNWGLDELETECONTEXT)(HGLRC);
+typedef BOOL(APIENTRY *PFNWGLMAKECURRENT)(HDC, HGLRC);
typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
+typedef void *(APIENTRY *PFNWGLGETPROCADDRESS)(LPCSTR);
static String format_error_message(DWORD id) {
LPWSTR messageBuffer = nullptr;
@@ -102,7 +105,7 @@ static bool nvapi_err_check(const char *msg, int status) {
// On windows we have to disable threaded optimization when using NVIDIA graphics cards
// to avoid stuttering, see https://github.com/microsoft/vscode-cpptools/issues/6592
// also see https://github.com/Ryujinx/Ryujinx/blob/master/Ryujinx.Common/GraphicsDriver/NVThreadedOptimization.cs
-void GLManager_Windows::_nvapi_disable_threaded_optimization() {
+void GLManagerNative_Windows::_nvapi_disable_threaded_optimization() {
HMODULE nvapi = 0;
#ifdef _WIN64
nvapi = LoadLibraryA("nvapi64.dll");
@@ -116,7 +119,7 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() {
void *(__cdecl * NvAPI_QueryInterface)(unsigned int interface_id) = 0;
- NvAPI_QueryInterface = (void *(__cdecl *)(unsigned int))GetProcAddress(nvapi, "nvapi_QueryInterface");
+ NvAPI_QueryInterface = (void *(__cdecl *)(unsigned int))(void *)GetProcAddress(nvapi, "nvapi_QueryInterface");
if (NvAPI_QueryInterface == NULL) {
print_verbose("Error getting NVAPI NvAPI_QueryInterface");
@@ -235,7 +238,7 @@ void GLManager_Windows::_nvapi_disable_threaded_optimization() {
NvAPI_DRS_DestroySession(session_handle);
}
-int GLManager_Windows::_find_or_create_display(GLWindow &win) {
+int GLManagerNative_Windows::_find_or_create_display(GLWindow &win) {
// find display NYI, only 1 supported so far
if (_displays.size()) {
return 0;
@@ -297,19 +300,36 @@ static Error _configure_pixel_format(HDC hDC) {
return OK;
}
-Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
+PFNWGLCREATECONTEXT gd_wglCreateContext;
+PFNWGLMAKECURRENT gd_wglMakeCurrent;
+PFNWGLDELETECONTEXT gd_wglDeleteContext;
+PFNWGLGETPROCADDRESS gd_wglGetProcAddress;
+
+Error GLManagerNative_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
Error err = _configure_pixel_format(win.hDC);
if (err != OK) {
return err;
}
- gl_display.hRC = wglCreateContext(win.hDC);
+ HMODULE module = LoadLibraryW(L"opengl32.dll");
+ if (!module) {
+ return ERR_CANT_CREATE;
+ }
+ gd_wglCreateContext = (PFNWGLCREATECONTEXT)GetProcAddress(module, "wglCreateContext");
+ gd_wglMakeCurrent = (PFNWGLMAKECURRENT)GetProcAddress(module, "wglMakeCurrent");
+ gd_wglDeleteContext = (PFNWGLDELETECONTEXT)GetProcAddress(module, "wglDeleteContext");
+ gd_wglGetProcAddress = (PFNWGLGETPROCADDRESS)GetProcAddress(module, "wglGetProcAddress");
+ if (!gd_wglCreateContext || !gd_wglMakeCurrent || !gd_wglDeleteContext || !gd_wglGetProcAddress) {
+ return ERR_CANT_CREATE;
+ }
+
+ gl_display.hRC = gd_wglCreateContext(win.hDC);
if (!gl_display.hRC) // Are We Able To Get A Rendering Context?
{
return ERR_CANT_CREATE; // Return FALSE
}
- if (!wglMakeCurrent(win.hDC, gl_display.hRC)) {
+ if (!gd_wglMakeCurrent(win.hDC, gl_display.hRC)) {
ERR_PRINT("Could not attach OpenGL context to newly created window: " + format_error_message(GetLastError()));
}
@@ -323,45 +343,45 @@ Error GLManager_Windows::_create_context(GLWindow &win, GLDisplay &gl_display) {
}; //zero indicates the end of the array
PFNWGLCREATECONTEXTATTRIBSARBPROC wglCreateContextAttribsARB = nullptr; //pointer to the method
- wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)wglGetProcAddress("wglCreateContextAttribsARB");
+ wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)gd_wglGetProcAddress("wglCreateContextAttribsARB");
if (wglCreateContextAttribsARB == nullptr) //OpenGL 3.0 is not supported
{
- wglDeleteContext(gl_display.hRC);
+ gd_wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
return ERR_CANT_CREATE;
}
HGLRC new_hRC = wglCreateContextAttribsARB(win.hDC, 0, attribs);
if (!new_hRC) {
- wglDeleteContext(gl_display.hRC);
+ gd_wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
return ERR_CANT_CREATE;
}
- if (!wglMakeCurrent(win.hDC, nullptr)) {
+ if (!gd_wglMakeCurrent(win.hDC, nullptr)) {
ERR_PRINT("Could not detach OpenGL context from newly created window: " + format_error_message(GetLastError()));
}
- wglDeleteContext(gl_display.hRC);
+ gd_wglDeleteContext(gl_display.hRC);
gl_display.hRC = new_hRC;
- if (!wglMakeCurrent(win.hDC, gl_display.hRC)) // Try To Activate The Rendering Context
+ if (!gd_wglMakeCurrent(win.hDC, gl_display.hRC)) // Try to activate the rendering context.
{
ERR_PRINT("Could not attach OpenGL context to newly created window with replaced OpenGL context: " + format_error_message(GetLastError()));
- wglDeleteContext(gl_display.hRC);
+ gd_wglDeleteContext(gl_display.hRC);
gl_display.hRC = 0;
return ERR_CANT_CREATE;
}
if (!wglSwapIntervalEXT) {
- wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)wglGetProcAddress("wglSwapIntervalEXT");
+ wglSwapIntervalEXT = (PFNWGLSWAPINTERVALEXTPROC)gd_wglGetProcAddress("wglSwapIntervalEXT");
}
return OK;
}
-Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
+Error GLManagerNative_Windows::window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height) {
HDC hDC = GetDC(p_hwnd);
if (!hDC) {
return ERR_CANT_CREATE;
@@ -374,8 +394,6 @@ Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND
}
GLWindow win;
- win.width = p_width;
- win.height = p_height;
win.hwnd = p_hwnd;
win.hDC = hDC;
@@ -395,24 +413,11 @@ Error GLManager_Windows::window_create(DisplayServer::WindowID p_window_id, HWND
return OK;
}
-void GLManager_Windows::_internal_set_current_window(GLWindow *p_win) {
+void GLManagerNative_Windows::_internal_set_current_window(GLWindow *p_win) {
_current_window = p_win;
}
-void GLManager_Windows::window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {
- get_window(p_window_id).width = p_width;
- get_window(p_window_id).height = p_height;
-}
-
-int GLManager_Windows::window_get_width(DisplayServer::WindowID p_window_id) {
- return get_window(p_window_id).width;
-}
-
-int GLManager_Windows::window_get_height(DisplayServer::WindowID p_window_id) {
- return get_window(p_window_id).height;
-}
-
-void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
+void GLManagerNative_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
GLWindow &win = get_window(p_window_id);
if (_current_window == &win) {
_current_window = nullptr;
@@ -420,17 +425,17 @@ void GLManager_Windows::window_destroy(DisplayServer::WindowID p_window_id) {
_windows.erase(p_window_id);
}
-void GLManager_Windows::release_current() {
+void GLManagerNative_Windows::release_current() {
if (!_current_window) {
return;
}
- if (!wglMakeCurrent(_current_window->hDC, nullptr)) {
+ if (!gd_wglMakeCurrent(_current_window->hDC, nullptr)) {
ERR_PRINT("Could not detach OpenGL context from window marked current: " + format_error_message(GetLastError()));
}
}
-void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
+void GLManagerNative_Windows::window_make_current(DisplayServer::WindowID p_window_id) {
if (p_window_id == -1) {
return;
}
@@ -444,33 +449,33 @@ void GLManager_Windows::window_make_current(DisplayServer::WindowID p_window_id)
}
const GLDisplay &disp = get_display(win.gldisplay_id);
- if (!wglMakeCurrent(win.hDC, disp.hRC)) {
+ if (!gd_wglMakeCurrent(win.hDC, disp.hRC)) {
ERR_PRINT("Could not switch OpenGL context to other window: " + format_error_message(GetLastError()));
}
_internal_set_current_window(&win);
}
-void GLManager_Windows::make_current() {
+void GLManagerNative_Windows::make_current() {
if (!_current_window) {
return;
}
const GLDisplay &disp = get_current_display();
- if (!wglMakeCurrent(_current_window->hDC, disp.hRC)) {
+ if (!gd_wglMakeCurrent(_current_window->hDC, disp.hRC)) {
ERR_PRINT("Could not switch OpenGL context to window marked current: " + format_error_message(GetLastError()));
}
}
-void GLManager_Windows::swap_buffers() {
+void GLManagerNative_Windows::swap_buffers() {
SwapBuffers(_current_window->hDC);
}
-Error GLManager_Windows::initialize() {
+Error GLManagerNative_Windows::initialize() {
_nvapi_disable_threaded_optimization();
return OK;
}
-void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use) {
+void GLManagerNative_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool p_use) {
GLWindow &win = get_window(p_window_id);
GLWindow *current = _current_window;
@@ -480,7 +485,12 @@ void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool
if (wglSwapIntervalEXT) {
win.use_vsync = p_use;
- wglSwapIntervalEXT(p_use ? 1 : 0);
+
+ if (!wglSwapIntervalEXT(p_use ? 1 : 0)) {
+ WARN_PRINT("Could not set V-Sync mode.");
+ }
+ } else {
+ WARN_PRINT("Could not set V-Sync mode. V-Sync is not supported.");
}
if (current != _current_window) {
@@ -489,29 +499,27 @@ void GLManager_Windows::set_use_vsync(DisplayServer::WindowID p_window_id, bool
}
}
-bool GLManager_Windows::is_using_vsync(DisplayServer::WindowID p_window_id) const {
+bool GLManagerNative_Windows::is_using_vsync(DisplayServer::WindowID p_window_id) const {
return get_window(p_window_id).use_vsync;
}
-HDC GLManager_Windows::get_hdc(DisplayServer::WindowID p_window_id) {
+HDC GLManagerNative_Windows::get_hdc(DisplayServer::WindowID p_window_id) {
return get_window(p_window_id).hDC;
}
-HGLRC GLManager_Windows::get_hglrc(DisplayServer::WindowID p_window_id) {
+HGLRC GLManagerNative_Windows::get_hglrc(DisplayServer::WindowID p_window_id) {
const GLWindow &win = get_window(p_window_id);
const GLDisplay &disp = get_display(win.gldisplay_id);
return disp.hRC;
}
-GLManager_Windows::GLManager_Windows(ContextType p_context_type) {
- context_type = p_context_type;
-
+GLManagerNative_Windows::GLManagerNative_Windows() {
direct_render = false;
glx_minor = glx_major = 0;
_current_window = nullptr;
}
-GLManager_Windows::~GLManager_Windows() {
+GLManagerNative_Windows::~GLManagerNative_Windows() {
release_current();
}
diff --git a/platform/windows/gl_manager_windows.h b/platform/windows/gl_manager_windows_native.h
index 482b00a1ba..829c53b3d2 100644
--- a/platform/windows/gl_manager_windows.h
+++ b/platform/windows/gl_manager_windows_native.h
@@ -1,5 +1,5 @@
/**************************************************************************/
-/* gl_manager_windows.h */
+/* gl_manager_windows_native.h */
/**************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
@@ -28,8 +28,8 @@
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/**************************************************************************/
-#ifndef GL_MANAGER_WINDOWS_H
-#define GL_MANAGER_WINDOWS_H
+#ifndef GL_MANAGER_WINDOWS_NATIVE_H
+#define GL_MANAGER_WINDOWS_NATIVE_H
#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
@@ -43,17 +43,10 @@
typedef bool(APIENTRY *PFNWGLSWAPINTERVALEXTPROC)(int interval);
typedef int(APIENTRY *PFNWGLGETSWAPINTERVALEXTPROC)(void);
-class GLManager_Windows {
-public:
- enum ContextType {
- GLES_3_0_COMPATIBLE,
- };
-
+class GLManagerNative_Windows {
private:
// any data specific to the window
struct GLWindow {
- int width = 0;
- int height = 0;
bool use_vsync = false;
// windows specific
@@ -86,7 +79,6 @@ private:
bool direct_render;
int glx_minor, glx_major;
- ContextType context_type;
private:
void _nvapi_disable_threaded_optimization();
@@ -96,11 +88,7 @@ private:
public:
Error window_create(DisplayServer::WindowID p_window_id, HWND p_hwnd, HINSTANCE p_hinstance, int p_width, int p_height);
void window_destroy(DisplayServer::WindowID p_window_id);
- void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height);
-
- // get directly from the cached GLWindow
- int window_get_width(DisplayServer::WindowID p_window_id = 0);
- int window_get_height(DisplayServer::WindowID p_window_id = 0);
+ void window_resize(DisplayServer::WindowID p_window_id, int p_width, int p_height) {}
void release_current();
void make_current();
@@ -116,10 +104,10 @@ public:
HDC get_hdc(DisplayServer::WindowID p_window_id);
HGLRC get_hglrc(DisplayServer::WindowID p_window_id);
- GLManager_Windows(ContextType p_context_type);
- ~GLManager_Windows();
+ GLManagerNative_Windows();
+ ~GLManagerNative_Windows();
};
#endif // WINDOWS_ENABLED && GLES3_ENABLED
-#endif // GL_MANAGER_WINDOWS_H
+#endif // GL_MANAGER_WINDOWS_NATIVE_H
diff --git a/platform/windows/os_windows.cpp b/platform/windows/os_windows.cpp
index b661222dfe..1d3b80e21e 100644
--- a/platform/windows/os_windows.cpp
+++ b/platform/windows/os_windows.cpp
@@ -395,7 +395,7 @@ Error OS_Windows::open_dynamic_library(const String p_path, void *&p_library_han
}
}
#else
- ERR_FAIL_COND_V_MSG(!p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(GetLastError())));
+ ERR_FAIL_NULL_V_MSG(p_library_handle, ERR_CANT_OPEN, vformat("Can't open dynamic library: %s. Error: %s.", p_path, format_error_message(GetLastError())));
#endif
if (cookie) {
@@ -1678,7 +1678,7 @@ Error OS_Windows::move_to_trash(const String &p_path) {
String OS_Windows::get_system_ca_certificates() {
HCERTSTORE cert_store = CertOpenSystemStoreA(0, "ROOT");
- ERR_FAIL_COND_V_MSG(!cert_store, "", "Failed to read the root certificate store.");
+ ERR_FAIL_NULL_V_MSG(cert_store, "", "Failed to read the root certificate store.");
FILETIME curr_time;
GetSystemTimeAsFileTime(&curr_time);
diff --git a/platform/windows/platform_config.h b/platform/windows/platform_config.h
index ae4e51e3fb..964e341ce4 100644
--- a/platform/windows/platform_config.h
+++ b/platform/windows/platform_config.h
@@ -29,5 +29,3 @@
/**************************************************************************/
#include <malloc.h>
-
-#define OPENGL_INCLUDE_H "thirdparty/glad/glad/gl.h"
diff --git a/platform/windows/platform_gl.h b/platform/windows/platform_gl.h
new file mode 100644
index 0000000000..e4af8b0ccd
--- /dev/null
+++ b/platform/windows/platform_gl.h
@@ -0,0 +1,53 @@
+/**************************************************************************/
+/* platform_gl.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 PLATFORM_GL_H
+#define PLATFORM_GL_H
+
+#ifndef GL_API_ENABLED
+#define GL_API_ENABLED // Allow using desktop GL.
+#endif
+
+#ifndef GLES_API_ENABLED
+#define GLES_API_ENABLED // Allow using GLES (ANGLE).
+#endif
+
+#ifdef EGL_STATIC
+#define KHRONOS_STATIC 1
+#include "thirdparty/angle/include/EGL/egl.h"
+#include "thirdparty/angle/include/EGL/eglext.h"
+#undef KHRONOS_STATIC
+#else
+#include "thirdparty/glad/glad/egl.h"
+#endif
+
+#include "thirdparty/glad/glad/gl.h"
+
+#endif // PLATFORM_GL_H
diff --git a/platform/windows/tts_windows.cpp b/platform/windows/tts_windows.cpp
index 907096d890..11d63d85ee 100644
--- a/platform/windows/tts_windows.cpp
+++ b/platform/windows/tts_windows.cpp
@@ -114,7 +114,7 @@ void TTS_Windows::_update_tts() {
}
bool TTS_Windows::is_speaking() const {
- ERR_FAIL_COND_V(!synth, false);
+ ERR_FAIL_NULL_V(synth, false);
SPVOICESTATUS status;
synth->GetStatus(&status, nullptr);
@@ -122,7 +122,7 @@ bool TTS_Windows::is_speaking() const {
}
bool TTS_Windows::is_paused() const {
- ERR_FAIL_COND_V(!synth, false);
+ ERR_FAIL_NULL_V(synth, false);
return paused;
}
@@ -185,7 +185,7 @@ Array TTS_Windows::get_voices() const {
}
void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volume, float p_pitch, float p_rate, int p_utterance_id, bool p_interrupt) {
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
if (p_interrupt) {
stop();
}
@@ -212,7 +212,7 @@ void TTS_Windows::speak(const String &p_text, const String &p_voice, int p_volum
}
void TTS_Windows::pause() {
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
if (!paused) {
if (synth->Pause() == S_OK) {
paused = true;
@@ -221,13 +221,13 @@ void TTS_Windows::pause() {
}
void TTS_Windows::resume() {
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
synth->Resume();
paused = false;
}
void TTS_Windows::stop() {
- ERR_FAIL_COND(!synth);
+ ERR_FAIL_NULL(synth);
SPVOICESTATUS status;
synth->GetStatus(&status, nullptr);
diff --git a/platform/windows/wgl_detect_version.cpp b/platform/windows/wgl_detect_version.cpp
new file mode 100644
index 0000000000..264cd525c5
--- /dev/null
+++ b/platform/windows/wgl_detect_version.cpp
@@ -0,0 +1,189 @@
+/**************************************************************************/
+/* wgl_detect_version.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. */
+/**************************************************************************/
+
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+#include "wgl_detect_version.h"
+#include "os_windows.h"
+
+#include "core/string/print_string.h"
+#include "core/string/ustring.h"
+
+#include <windows.h>
+
+#include <dwmapi.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#define WGL_CONTEXT_MAJOR_VERSION_ARB 0x2091
+#define WGL_CONTEXT_MINOR_VERSION_ARB 0x2092
+#define WGL_CONTEXT_FLAGS_ARB 0x2094
+#define WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB 0x00000002
+#define WGL_CONTEXT_PROFILE_MASK_ARB 0x9126
+#define WGL_CONTEXT_CORE_PROFILE_BIT_ARB 0x00000001
+#define WGL_VENDOR 0x1F00
+#define WGL_RENDERER 0x1F01
+#define WGL_VERSION 0x1F02
+
+#if defined(__GNUC__)
+// Workaround GCC warning from -Wcast-function-type.
+#define GetProcAddress (void *)GetProcAddress
+#endif
+
+typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXT)(HDC);
+typedef BOOL(APIENTRY *PFNWGLDELETECONTEXT)(HGLRC);
+typedef BOOL(APIENTRY *PFNWGLMAKECURRENT)(HDC, HGLRC);
+typedef HGLRC(APIENTRY *PFNWGLCREATECONTEXTATTRIBSARBPROC)(HDC, HGLRC, const int *);
+typedef void *(APIENTRY *PFNWGLGETPROCADDRESS)(LPCSTR);
+typedef const char *(APIENTRY *PFNWGLGETSTRINGPROC)(unsigned int);
+
+int detect_wgl_version() {
+ int major = 0;
+ int minor = 0;
+
+ PFNWGLCREATECONTEXT gd_wglCreateContext;
+ PFNWGLMAKECURRENT gd_wglMakeCurrent;
+ PFNWGLDELETECONTEXT gd_wglDeleteContext;
+ PFNWGLGETPROCADDRESS gd_wglGetProcAddress;
+
+ HMODULE module = LoadLibraryW(L"opengl32.dll");
+ if (!module) {
+ return 0;
+ }
+ gd_wglCreateContext = (PFNWGLCREATECONTEXT)GetProcAddress(module, "wglCreateContext");
+ gd_wglMakeCurrent = (PFNWGLMAKECURRENT)GetProcAddress(module, "wglMakeCurrent");
+ gd_wglDeleteContext = (PFNWGLDELETECONTEXT)GetProcAddress(module, "wglDeleteContext");
+ gd_wglGetProcAddress = (PFNWGLGETPROCADDRESS)GetProcAddress(module, "wglGetProcAddress");
+ if (!gd_wglCreateContext || !gd_wglMakeCurrent || !gd_wglDeleteContext || !gd_wglGetProcAddress) {
+ return 0;
+ }
+
+ LPCWSTR class_name = L"EngineWGLDetect";
+ HINSTANCE hInstance = static_cast<OS_Windows *>(OS::get_singleton())->get_hinstance();
+ WNDCLASSW wc = {};
+
+ wc.lpfnWndProc = DefWindowProcW;
+ wc.hInstance = hInstance;
+ wc.lpszClassName = class_name;
+
+ RegisterClassW(&wc);
+
+ HWND hWnd = CreateWindowExW(WS_EX_APPWINDOW, class_name, L"", WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, nullptr, nullptr, hInstance, nullptr);
+ if (hWnd) {
+ HDC hDC = GetDC(hWnd);
+ if (hDC) {
+ static PIXELFORMATDESCRIPTOR pfd = {
+ sizeof(PIXELFORMATDESCRIPTOR), // Size Of This Pixel Format Descriptor
+ 1,
+ PFD_DRAW_TO_WINDOW | // Format Must Support Window
+ PFD_SUPPORT_OPENGL | // Format Must Support OpenGL
+ PFD_DOUBLEBUFFER,
+ (BYTE)PFD_TYPE_RGBA,
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 32 : 24),
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Color Bits Ignored
+ (BYTE)(OS::get_singleton()->is_layered_allowed() ? 8 : 0), // Alpha Buffer
+ (BYTE)0, // Shift Bit Ignored
+ (BYTE)0, // No Accumulation Buffer
+ (BYTE)0, (BYTE)0, (BYTE)0, (BYTE)0, // Accumulation Bits Ignored
+ (BYTE)24, // 24Bit Z-Buffer (Depth Buffer)
+ (BYTE)0, // No Stencil Buffer
+ (BYTE)0, // No Auxiliary Buffer
+ (BYTE)PFD_MAIN_PLANE, // Main Drawing Layer
+ (BYTE)0, // Reserved
+ 0, 0, 0 // Layer Masks Ignored
+ };
+
+ int pixel_format = ChoosePixelFormat(hDC, &pfd);
+ SetPixelFormat(hDC, pixel_format, &pfd);
+
+ HGLRC hRC = gd_wglCreateContext(hDC);
+ if (hRC) {
+ if (gd_wglMakeCurrent(hDC, hRC)) {
+ int attribs[] = {
+ WGL_CONTEXT_MAJOR_VERSION_ARB, 3,
+ WGL_CONTEXT_MINOR_VERSION_ARB, 3,
+ WGL_CONTEXT_PROFILE_MASK_ARB, WGL_CONTEXT_CORE_PROFILE_BIT_ARB,
+ WGL_CONTEXT_FLAGS_ARB, WGL_CONTEXT_FORWARD_COMPATIBLE_BIT_ARB,
+ 0
+ };
+
+ PFNWGLCREATECONTEXTATTRIBSARBPROC gd_wglCreateContextAttribsARB = nullptr;
+ gd_wglCreateContextAttribsARB = (PFNWGLCREATECONTEXTATTRIBSARBPROC)gd_wglGetProcAddress("wglCreateContextAttribsARB");
+ if (gd_wglCreateContextAttribsARB) {
+ HGLRC new_hRC = gd_wglCreateContextAttribsARB(hDC, 0, attribs);
+ if (new_hRC) {
+ if (gd_wglMakeCurrent(hDC, new_hRC)) {
+ PFNWGLGETSTRINGPROC gd_wglGetString = (PFNWGLGETSTRINGPROC)GetProcAddress(module, "glGetString");
+ if (gd_wglGetString) {
+ const char *prefixes[] = {
+ "OpenGL ES-CM ",
+ "OpenGL ES-CL ",
+ "OpenGL ES ",
+ "OpenGL SC ",
+ nullptr
+ };
+ const char *version = (const char *)gd_wglGetString(WGL_VERSION);
+ if (version) {
+ const String device_vendor = String::utf8((const char *)gd_wglGetString(WGL_VENDOR)).strip_edges();
+ const String device_name = String::utf8((const char *)gd_wglGetString(WGL_RENDERER)).strip_edges();
+ for (int i = 0; prefixes[i]; i++) {
+ size_t length = strlen(prefixes[i]);
+ if (strncmp(version, prefixes[i], length) == 0) {
+ version += length;
+ break;
+ }
+ }
+#ifdef _MSC_VER
+ sscanf_s(version, "%d.%d", &major, &minor);
+#else
+ sscanf(version, "%d.%d", &major, &minor);
+#endif
+ print_verbose(vformat("Native OpenGL API detected: %d.%d: %s - %s", major, minor, device_vendor, device_name));
+ }
+ }
+ }
+ gd_wglMakeCurrent(nullptr, nullptr);
+ gd_wglDeleteContext(new_hRC);
+ }
+ }
+ }
+ gd_wglMakeCurrent(nullptr, nullptr);
+ gd_wglDeleteContext(hRC);
+ }
+ ReleaseDC(hWnd, hDC);
+ }
+ DestroyWindow(hWnd);
+ }
+ UnregisterClassW(class_name, hInstance);
+
+ return major * 10000 + minor;
+}
+
+#endif // WINDOWS_ENABLED && GLES3_ENABLED
diff --git a/platform/windows/wgl_detect_version.h b/platform/windows/wgl_detect_version.h
new file mode 100644
index 0000000000..0be2923ba3
--- /dev/null
+++ b/platform/windows/wgl_detect_version.h
@@ -0,0 +1,40 @@
+/**************************************************************************/
+/* wgl_detect_version.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 WGL_DETECT_VERSION_H
+#define WGL_DETECT_VERSION_H
+
+#if defined(WINDOWS_ENABLED) && defined(GLES3_ENABLED)
+
+int detect_wgl_version();
+
+#endif // WINDOWS_ENABLED && GLES3_ENABLED
+
+#endif // WGL_DETECT_VERSION_H
diff --git a/scene/2d/animated_sprite_2d.cpp b/scene/2d/animated_sprite_2d.cpp
index 7de6219b10..bf3783966b 100644
--- a/scene/2d/animated_sprite_2d.cpp
+++ b/scene/2d/animated_sprite_2d.cpp
@@ -447,7 +447,7 @@ void AnimatedSprite2D::play(const StringName &p_name, float p_custom_scale, bool
name = animation;
}
- ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", name));
+ ERR_FAIL_NULL_MSG(frames, vformat("There is no animation with name '%s'.", name));
ERR_FAIL_COND_MSG(!frames->get_animation_names().has(name), vformat("There is no animation with name '%s'.", name));
if (frames->get_frame_count(name) == 0) {
diff --git a/scene/2d/audio_stream_player_2d.cpp b/scene/2d/audio_stream_player_2d.cpp
index dac31058bd..0a80467b6b 100644
--- a/scene/2d/audio_stream_player_2d.cpp
+++ b/scene/2d/audio_stream_player_2d.cpp
@@ -119,7 +119,7 @@ StringName AudioStreamPlayer2D::_get_actual_bus() {
ERR_FAIL_COND_V(world_2d.is_null(), SceneStringNames::get_singleton()->Master);
PhysicsDirectSpaceState2D *space_state = PhysicsServer2D::get_singleton()->space_get_direct_state(world_2d->get_space());
- ERR_FAIL_COND_V(space_state == nullptr, SceneStringNames::get_singleton()->Master);
+ ERR_FAIL_NULL_V(space_state, SceneStringNames::get_singleton()->Master);
PhysicsDirectSpaceState2D::ShapeResult sr[MAX_INTERSECT_AREAS];
PhysicsDirectSpaceState2D::PointParameters point_params;
@@ -354,10 +354,6 @@ void AudioStreamPlayer2D::_validate_property(PropertyInfo &p_property) const {
}
}
-void AudioStreamPlayer2D::_bus_layout_changed() {
- notify_property_list_changed();
-}
-
void AudioStreamPlayer2D::set_max_distance(float p_pixels) {
ERR_FAIL_COND(p_pixels <= 0.0);
max_distance = p_pixels;
@@ -426,6 +422,14 @@ float AudioStreamPlayer2D::get_panning_strength() const {
return panning_strength;
}
+void AudioStreamPlayer2D::_on_bus_layout_changed() {
+ notify_property_list_changed();
+}
+
+void AudioStreamPlayer2D::_on_bus_renamed(int p_bus_index, const StringName &p_old_name, const StringName &p_new_name) {
+ notify_property_list_changed();
+}
+
void AudioStreamPlayer2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer2D::set_stream);
ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer2D::get_stream);
@@ -490,7 +494,8 @@ void AudioStreamPlayer2D::_bind_methods() {
}
AudioStreamPlayer2D::AudioStreamPlayer2D() {
- AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer2D::_bus_layout_changed));
+ AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer2D::_on_bus_layout_changed));
+ AudioServer::get_singleton()->connect("bus_renamed", callable_mp(this, &AudioStreamPlayer2D::_on_bus_renamed));
cached_global_panning_strength = GLOBAL_GET("audio/general/2d_panning_strength");
set_hide_clip_children(true);
}
diff --git a/scene/2d/audio_stream_player_2d.h b/scene/2d/audio_stream_player_2d.h
index a4677bef36..0766f2f77d 100644
--- a/scene/2d/audio_stream_player_2d.h
+++ b/scene/2d/audio_stream_player_2d.h
@@ -75,7 +75,9 @@ private:
StringName _get_actual_bus();
void _update_panning();
- void _bus_layout_changed();
+
+ void _on_bus_layout_changed();
+ void _on_bus_renamed(int p_bus_index, const StringName &p_old_name, const StringName &p_new_name);
static void _listener_changed_cb(void *self) { reinterpret_cast<AudioStreamPlayer2D *>(self)->force_update_panning = true; }
diff --git a/scene/2d/gpu_particles_2d.cpp b/scene/2d/gpu_particles_2d.cpp
index 70c72dab07..67b14692a2 100644
--- a/scene/2d/gpu_particles_2d.cpp
+++ b/scene/2d/gpu_particles_2d.cpp
@@ -49,11 +49,11 @@ void GPUParticles2D::set_emitting(bool p_emitting) {
// Last cycle ended.
active = true;
time = 0;
- signal_cancled = false;
+ signal_canceled = false;
emission_time = lifetime;
active_time = lifetime * (2 - explosiveness_ratio);
} else {
- signal_cancled = true;
+ signal_canceled = true;
}
set_process_internal(true);
} else if (!p_emitting) {
@@ -429,7 +429,7 @@ void GPUParticles2D::restart() {
emitting = true;
active = true;
- signal_cancled = false;
+ signal_canceled = false;
time = 0;
emission_time = lifetime;
active_time = lifetime * (2 - explosiveness_ratio);
@@ -701,7 +701,7 @@ void GPUParticles2D::_notification(int p_what) {
}
}
if (time > active_time) {
- if (active && !signal_cancled) {
+ if (active && !signal_canceled) {
emit_signal(SceneStringNames::get_singleton()->finished);
}
active = false;
diff --git a/scene/2d/gpu_particles_2d.h b/scene/2d/gpu_particles_2d.h
index 97690b07fa..3a342e2c22 100644
--- a/scene/2d/gpu_particles_2d.h
+++ b/scene/2d/gpu_particles_2d.h
@@ -49,7 +49,7 @@ private:
bool emitting = false;
bool active = false;
- bool signal_cancled = false;
+ bool signal_canceled = false;
bool one_shot = false;
int amount = 0;
double lifetime = 0.0;
diff --git a/scene/2d/joint_2d.cpp b/scene/2d/joint_2d.cpp
index ce427d47aa..62b44655c1 100644
--- a/scene/2d/joint_2d.cpp
+++ b/scene/2d/joint_2d.cpp
@@ -235,6 +235,8 @@ void Joint2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint2D::set_exclude_nodes_from_collision);
ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint2D::get_exclude_nodes_from_collision);
+ ClassDB::bind_method(D_METHOD("get_rid"), &Joint2D::get_rid);
+
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody2D"), "set_node_a", "get_node_a");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody2D"), "set_node_b", "get_node_b");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "bias", PROPERTY_HINT_RANGE, "0,0.9,0.001"), "set_bias", "get_bias");
@@ -281,7 +283,7 @@ void PinJoint2D::set_softness(real_t p_softness) {
softness = p_softness;
queue_redraw();
if (is_configured()) {
- PhysicsServer2D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness);
+ PhysicsServer2D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer2D::PIN_JOINT_SOFTNESS, p_softness);
}
}
@@ -410,7 +412,7 @@ void DampedSpringJoint2D::set_rest_length(real_t p_rest_length) {
rest_length = p_rest_length;
queue_redraw();
if (is_configured()) {
- PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, p_rest_length ? p_rest_length : length);
+ PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_REST_LENGTH, p_rest_length ? p_rest_length : length);
}
}
@@ -422,7 +424,7 @@ void DampedSpringJoint2D::set_stiffness(real_t p_stiffness) {
stiffness = p_stiffness;
queue_redraw();
if (is_configured()) {
- PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_STIFFNESS, p_stiffness);
+ PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_STIFFNESS, p_stiffness);
}
}
@@ -434,7 +436,7 @@ void DampedSpringJoint2D::set_damping(real_t p_damping) {
damping = p_damping;
queue_redraw();
if (is_configured()) {
- PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_joint(), PhysicsServer2D::DAMPED_SPRING_DAMPING, p_damping);
+ PhysicsServer2D::get_singleton()->damped_spring_joint_set_param(get_rid(), PhysicsServer2D::DAMPED_SPRING_DAMPING, p_damping);
}
}
diff --git a/scene/2d/joint_2d.h b/scene/2d/joint_2d.h
index b23fd8028d..581a3b6757 100644
--- a/scene/2d/joint_2d.h
+++ b/scene/2d/joint_2d.h
@@ -76,7 +76,7 @@ public:
void set_exclude_nodes_from_collision(bool p_enable);
bool get_exclude_nodes_from_collision() const;
- RID get_joint() const { return joint; }
+ RID get_rid() const { return joint; }
Joint2D();
~Joint2D();
};
diff --git a/scene/2d/line_2d.cpp b/scene/2d/line_2d.cpp
index 3a9473d76c..be58875e0e 100644
--- a/scene/2d/line_2d.cpp
+++ b/scene/2d/line_2d.cpp
@@ -42,12 +42,12 @@ Rect2 Line2D::_edit_get_rect() const {
return Rect2(0, 0, 0, 0);
}
Vector2 d = Vector2(_width, _width);
- Rect2 aabb = Rect2(_points[0] - d, 2 * d);
+ Rect2 bounding_rect = Rect2(_points[0] - d, 2 * d);
for (int i = 1; i < _points.size(); i++) {
- aabb.expand_to(_points[i] - d);
- aabb.expand_to(_points[i] + d);
+ bounding_rect.expand_to(_points[i] - d);
+ bounding_rect.expand_to(_points[i] + d);
}
- return aabb;
+ return bounding_rect;
}
bool Line2D::_edit_use_rect() const {
@@ -59,7 +59,14 @@ bool Line2D::_edit_is_selected_on_click(const Point2 &p_point, double p_toleranc
const Vector2 *points = _points.ptr();
for (int i = 0; i < _points.size() - 1; i++) {
Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, &points[i]);
- if (p.distance_to(p_point) <= d) {
+ if (p_point.distance_to(p) <= d) {
+ return true;
+ }
+ }
+ if (_closed && _points.size() > 2) {
+ const Vector2 closing_segment[2] = { points[0], points[_points.size() - 1] };
+ Vector2 p = Geometry2D::get_closest_point_to_segment(p_point, closing_segment);
+ if (p_point.distance_to(p) <= d) {
return true;
}
}
@@ -73,6 +80,15 @@ void Line2D::set_points(const Vector<Vector2> &p_points) {
queue_redraw();
}
+void Line2D::set_closed(bool p_closed) {
+ _closed = p_closed;
+ queue_redraw();
+}
+
+bool Line2D::is_closed() const {
+ return _closed;
+}
+
void Line2D::set_width(float p_width) {
if (p_width < 0.0) {
p_width = 0.0;
@@ -86,14 +102,12 @@ float Line2D::get_width() const {
}
void Line2D::set_curve(const Ref<Curve> &p_curve) {
- // Cleanup previous connection if any
if (_curve.is_valid()) {
_curve->disconnect_changed(callable_mp(this, &Line2D::_curve_changed));
}
_curve = p_curve;
- // Connect to the curve so the line will update when it is changed
if (_curve.is_valid()) {
_curve->connect_changed(callable_mp(this, &Line2D::_curve_changed));
}
@@ -156,14 +170,12 @@ Color Line2D::get_default_color() const {
}
void Line2D::set_gradient(const Ref<Gradient> &p_gradient) {
- // Cleanup previous connection if any
if (_gradient.is_valid()) {
_gradient->disconnect_changed(callable_mp(this, &Line2D::_gradient_changed));
}
_gradient = p_gradient;
- // Connect to the gradient so the line will update when the Gradient is changed
if (_gradient.is_valid()) {
_gradient->connect_changed(callable_mp(this, &Line2D::_gradient_changed));
}
@@ -264,20 +276,10 @@ void Line2D::_draw() {
return;
}
- // TODO Is this really needed?
- // Copy points for faster access
- Vector<Vector2> points;
- points.resize(len);
- {
- const Vector2 *points_read = _points.ptr();
- for (int i = 0; i < len; ++i) {
- points.write[i] = points_read[i];
- }
- }
-
// TODO Maybe have it as member rather than copying parameters and allocating memory?
LineBuilder lb;
- lb.points = points;
+ lb.points = _points;
+ lb.closed = _closed;
lb.default_color = _default_color;
lb.gradient = *_gradient;
lb.texture_mode = _texture_mode;
@@ -306,13 +308,10 @@ void Line2D::_draw() {
lb.uvs, Vector<int>(), Vector<float>(),
texture_rid);
- // DEBUG
- // Draw wireframe
- // if(lb.indices.size() % 3 == 0) {
- // Color col(0,0,0);
- // for(int i = 0; i < lb.indices.size(); i += 3) {
- // int vi = lb.indices[i];
- // int lbvsize = lb.vertices.size();
+ // DEBUG: Draw wireframe
+ // if (lb.indices.size() % 3 == 0) {
+ // Color col(0, 0, 0);
+ // for (int i = 0; i < lb.indices.size(); i += 3) {
// Vector2 a = lb.vertices[lb.indices[i]];
// Vector2 b = lb.vertices[lb.indices[i+1]];
// Vector2 c = lb.vertices[lb.indices[i+2]];
@@ -320,9 +319,9 @@ void Line2D::_draw() {
// draw_line(b, c, col);
// draw_line(c, a, col);
// }
- // for(int i = 0; i < lb.vertices.size(); ++i) {
+ // for (int i = 0; i < lb.vertices.size(); ++i) {
// Vector2 p = lb.vertices[i];
- // draw_rect(Rect2(p.x-1, p.y-1, 2, 2), Color(0,0,0,0.5));
+ // draw_rect(Rect2(p.x - 1, p.y - 1, 2, 2), Color(0, 0, 0, 0.5));
// }
// }
}
@@ -350,6 +349,9 @@ void Line2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("clear_points"), &Line2D::clear_points);
+ ClassDB::bind_method(D_METHOD("set_closed", "closed"), &Line2D::set_closed);
+ ClassDB::bind_method(D_METHOD("is_closed"), &Line2D::is_closed);
+
ClassDB::bind_method(D_METHOD("set_width", "width"), &Line2D::set_width);
ClassDB::bind_method(D_METHOD("get_width"), &Line2D::get_width);
@@ -387,6 +389,7 @@ void Line2D::_bind_methods() {
ClassDB::bind_method(D_METHOD("get_antialiased"), &Line2D::get_antialiased);
ADD_PROPERTY(PropertyInfo(Variant::PACKED_VECTOR2_ARRAY, "points"), "set_points", "get_points");
+ ADD_PROPERTY(PropertyInfo(Variant::BOOL, "closed"), "set_closed", "is_closed");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "width", PROPERTY_HINT_NONE, "suffix:px"), "set_width", "get_width");
ADD_PROPERTY(PropertyInfo(Variant::OBJECT, "width_curve", PROPERTY_HINT_RESOURCE_TYPE, "Curve"), "set_curve", "get_curve");
ADD_PROPERTY(PropertyInfo(Variant::COLOR, "default_color"), "set_default_color", "get_default_color");
diff --git a/scene/2d/line_2d.h b/scene/2d/line_2d.h
index aa873ca642..1d750ca456 100644
--- a/scene/2d/line_2d.h
+++ b/scene/2d/line_2d.h
@@ -76,6 +76,9 @@ public:
void add_point(Vector2 pos, int atpos = -1);
void remove_point(int i);
+ void set_closed(bool p_closed);
+ bool is_closed() const;
+
void set_width(float width);
float get_width() const;
@@ -127,6 +130,7 @@ private:
LineJointMode _joint_mode = LINE_JOINT_SHARP;
LineCapMode _begin_cap_mode = LINE_CAP_NONE;
LineCapMode _end_cap_mode = LINE_CAP_NONE;
+ bool _closed = false;
float _width = 10.0;
Ref<Curve> _curve;
Color _default_color = Color(1, 1, 1);
diff --git a/scene/2d/line_builder.cpp b/scene/2d/line_builder.cpp
index 0970325502..e898dc7fab 100644
--- a/scene/2d/line_builder.cpp
+++ b/scene/2d/line_builder.cpp
@@ -30,75 +30,25 @@
#include "line_builder.h"
-//----------------------------------------------------------------------------
-// Util
-//----------------------------------------------------------------------------
-
-enum SegmentIntersectionResult {
- SEGMENT_PARALLEL = 0,
- SEGMENT_NO_INTERSECT = 1,
- SEGMENT_INTERSECT = 2
-};
-
-static SegmentIntersectionResult segment_intersection(
- Vector2 a, Vector2 b, Vector2 c, Vector2 d,
- Vector2 *out_intersection) {
- // http://paulbourke.net/geometry/pointlineplane/ <-- Good stuff
- Vector2 cd = d - c;
- Vector2 ab = b - a;
- float div = cd.y * ab.x - cd.x * ab.y;
-
- if (Math::abs(div) > 0.001f) {
- float ua = (cd.x * (a.y - c.y) - cd.y * (a.x - c.x)) / div;
- float ub = (ab.x * (a.y - c.y) - ab.y * (a.x - c.x)) / div;
- *out_intersection = a + ua * ab;
- if (ua >= 0.f && ua <= 1.f &&
- ub >= 0.f && ub <= 1.f) {
- return SEGMENT_INTERSECT;
- }
- return SEGMENT_NO_INTERSECT;
- }
-
- return SEGMENT_PARALLEL;
-}
-
-static float calculate_total_distance(const Vector<Vector2> &points) {
- float d = 0.f;
- for (int i = 1; i < points.size(); ++i) {
- d += points[i].distance_to(points[i - 1]);
- }
- return d;
-}
-
-static inline Vector2 rotate90(const Vector2 &v) {
- // Note: the 2D referential is X-right, Y-down
- return Vector2(v.y, -v.x);
-}
+#include "core/math/geometry_2d.h"
+// Utility method.
static inline Vector2 interpolate(const Rect2 &r, const Vector2 &v) {
return Vector2(
Math::lerp(r.position.x, r.position.x + r.get_size().x, v.x),
Math::lerp(r.position.y, r.position.y + r.get_size().y, v.y));
}
-//----------------------------------------------------------------------------
-// LineBuilder
-//----------------------------------------------------------------------------
-
LineBuilder::LineBuilder() {
}
-void LineBuilder::clear_output() {
- vertices.clear();
- colors.clear();
- indices.clear();
- uvs.clear();
-}
-
void LineBuilder::build() {
- // Need at least 2 points to draw a line
+ // Need at least 2 points to draw a line, so clear the output and return.
if (points.size() < 2) {
- clear_output();
+ vertices.clear();
+ colors.clear();
+ indices.clear();
+ uvs.clear();
return;
}
@@ -107,14 +57,21 @@ void LineBuilder::build() {
const float hw = width / 2.f;
const float hw_sq = hw * hw;
const float sharp_limit_sq = sharp_limit * sharp_limit;
- const int len = points.size();
+ const int point_count = points.size();
+ const bool wrap_around = closed && point_count > 2;
+
+ _interpolate_color = gradient != nullptr;
+ const bool retrieve_curve = curve != nullptr;
+ const bool distance_required = _interpolate_color || retrieve_curve ||
+ texture_mode == Line2D::LINE_TEXTURE_TILE ||
+ texture_mode == Line2D::LINE_TEXTURE_STRETCH;
// Initial values
Vector2 pos0 = points[0];
Vector2 pos1 = points[1];
Vector2 f0 = (pos1 - pos0).normalized();
- Vector2 u0 = rotate90(f0);
+ Vector2 u0 = f0.orthogonal();
Vector2 pos_up0 = pos0;
Vector2 pos_down0 = pos0;
@@ -124,32 +81,37 @@ void LineBuilder::build() {
float current_distance0 = 0.f;
float current_distance1 = 0.f;
float total_distance = 0.f;
+
float width_factor = 1.f;
- _interpolate_color = gradient != nullptr;
- bool retrieve_curve = curve != nullptr;
- bool distance_required = _interpolate_color ||
- retrieve_curve ||
- texture_mode == Line2D::LINE_TEXTURE_TILE ||
- texture_mode == Line2D::LINE_TEXTURE_STRETCH;
+ float modified_hw = hw;
+ if (retrieve_curve) {
+ width_factor = curve->sample_baked(0.f);
+ modified_hw = hw * width_factor;
+ }
+
if (distance_required) {
- total_distance = calculate_total_distance(points);
- //Adjust totalDistance.
- // The line's outer length will be a little higher due to begin and end caps
- if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) {
- if (retrieve_curve) {
- total_distance += width * curve->sample_baked(0.f) * 0.5f;
- } else {
- total_distance += width * 0.5f;
- }
+ // Calculate the total distance.
+ for (int i = 1; i < point_count; ++i) {
+ total_distance += points[i].distance_to(points[i - 1]);
}
- if (end_cap_mode == Line2D::LINE_CAP_BOX || end_cap_mode == Line2D::LINE_CAP_ROUND) {
- if (retrieve_curve) {
- total_distance += width * curve->sample_baked(1.f) * 0.5f;
- } else {
- total_distance += width * 0.5f;
+ if (wrap_around) {
+ total_distance += points[point_count - 1].distance_to(pos0);
+ } else {
+ // Adjust the total distance.
+ // The line's outer length may be a little higher due to the end caps.
+ if (begin_cap_mode == Line2D::LINE_CAP_BOX || begin_cap_mode == Line2D::LINE_CAP_ROUND) {
+ total_distance += modified_hw;
+ }
+ if (end_cap_mode == Line2D::LINE_CAP_BOX || end_cap_mode == Line2D::LINE_CAP_ROUND) {
+ if (retrieve_curve) {
+ total_distance += hw * curve->sample_baked(1.f);
+ } else {
+ total_distance += hw;
+ }
}
}
}
+
if (_interpolate_color) {
color0 = gradient->get_color(0);
} else {
@@ -159,34 +121,31 @@ void LineBuilder::build() {
float uvx0 = 0.f;
float uvx1 = 0.f;
- if (retrieve_curve) {
- width_factor = curve->sample_baked(0.f);
- }
-
- pos_up0 += u0 * hw * width_factor;
- pos_down0 -= u0 * hw * width_factor;
+ pos_up0 += u0 * modified_hw;
+ pos_down0 -= u0 * modified_hw;
// Begin cap
- if (begin_cap_mode == Line2D::LINE_CAP_BOX) {
- // Push back first vertices a little bit
- pos_up0 -= f0 * hw * width_factor;
- pos_down0 -= f0 * hw * width_factor;
-
- current_distance0 += hw * width_factor;
- current_distance1 = current_distance0;
- } else if (begin_cap_mode == Line2D::LINE_CAP_ROUND) {
- if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
- uvx0 = width_factor * 0.5f / tile_aspect;
- } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
- uvx0 = width * width_factor / total_distance;
+ if (!wrap_around) {
+ if (begin_cap_mode == Line2D::LINE_CAP_BOX) {
+ // Push back first vertices a little bit.
+ pos_up0 -= f0 * modified_hw;
+ pos_down0 -= f0 * modified_hw;
+
+ current_distance0 += modified_hw;
+ current_distance1 = current_distance0;
+ } else if (begin_cap_mode == Line2D::LINE_CAP_ROUND) {
+ if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
+ uvx0 = width_factor * 0.5f / tile_aspect;
+ } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
+ uvx0 = width * width_factor / total_distance;
+ }
+ new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, uvx0 * 2, 1.f));
+ current_distance0 += modified_hw;
+ current_distance1 = current_distance0;
}
- new_arc(pos0, pos_up0 - pos0, -Math_PI, color0, Rect2(0.f, 0.f, uvx0 * 2, 1.f));
- current_distance0 += hw * width_factor;
- current_distance1 = current_distance0;
+ strip_begin(pos_up0, pos_down0, color0, uvx0);
}
- strip_begin(pos_up0, pos_down0, color0, uvx0);
-
/*
* pos_up0 ------------- pos_up1 --------------------
* | |
@@ -200,19 +159,30 @@ void LineBuilder::build() {
// http://labs.hyperandroid.com/tag/opengl-lines
// (not the same implementation but visuals help a lot)
+ // If the polyline wraps around, then draw two more segments with joints:
+ // The last one, which should normally end with an end cap, and the one that matches the end and the beginning.
+ int segments_count = wrap_around ? point_count : (point_count - 2);
+ // The wraparound case starts with a "fake walk" from the end of the polyline
+ // to its beginning, so that its first joint is correct, without drawing anything.
+ int first_point = wrap_around ? -1 : 1;
+
+ // If the line wraps around, these variables will be used for the final segment.
+ Vector2 first_pos_up, first_pos_down;
+ bool is_first_joint_sharp = false;
+
// For each additional segment
- for (int i = 1; i < len - 1; ++i) {
- pos1 = points[i];
- Vector2 pos2 = points[i + 1];
+ for (int i = first_point; i <= segments_count; ++i) {
+ pos1 = points[(i == -1) ? point_count - 1 : i % point_count]; // First point.
+ Vector2 pos2 = points[(i + 1) % point_count]; // Second point.
Vector2 f1 = (pos2 - pos1).normalized();
- Vector2 u1 = rotate90(f1);
+ Vector2 u1 = f1.orthogonal();
- // Determine joint orientation
- const float dp = u0.dot(f1);
+ // Determine joint orientation.
+ float dp = u0.dot(f1);
const Orientation orientation = (dp > 0.f ? UP : DOWN);
- if (distance_required) {
+ if (distance_required && i >= 1) {
current_distance1 += pos0.distance_to(pos1);
}
if (_interpolate_color) {
@@ -220,15 +190,14 @@ void LineBuilder::build() {
}
if (retrieve_curve) {
width_factor = curve->sample_baked(current_distance1 / total_distance);
+ modified_hw = hw * width_factor;
}
- Vector2 inner_normal0, inner_normal1;
- if (orientation == UP) {
- inner_normal0 = u0 * hw * width_factor;
- inner_normal1 = u1 * hw * width_factor;
- } else {
- inner_normal0 = -u0 * hw * width_factor;
- inner_normal1 = -u1 * hw * width_factor;
+ Vector2 inner_normal0 = u0 * modified_hw;
+ Vector2 inner_normal1 = u1 * modified_hw;
+ if (orientation == DOWN) {
+ inner_normal0 = -inner_normal0;
+ inner_normal1 = -inner_normal1;
}
/*
@@ -245,18 +214,18 @@ void LineBuilder::build() {
* /
*/
- // Find inner intersection at the joint
+ // Find inner intersection at the joint.
Vector2 corner_pos_in, corner_pos_out;
- SegmentIntersectionResult intersection_result = segment_intersection(
+ bool is_intersecting = Geometry2D::segment_intersects_segment(
pos0 + inner_normal0, pos1 + inner_normal0,
pos1 + inner_normal1, pos2 + inner_normal1,
&corner_pos_in);
- if (intersection_result == SEGMENT_INTERSECT) {
- // Inner parts of the segments intersect
+ if (is_intersecting) {
+ // Inner parts of the segments intersect.
corner_pos_out = 2.f * pos1 - corner_pos_in;
} else {
- // No intersection, segments are either parallel or too sharp
+ // No intersection, segments are too sharp or they overlap.
corner_pos_in = pos1 + inner_normal0;
corner_pos_out = pos1 - inner_normal0;
}
@@ -273,8 +242,8 @@ void LineBuilder::build() {
Line2D::LineJointMode current_joint_mode = joint_mode;
Vector2 pos_up1, pos_down1;
- if (intersection_result == SEGMENT_INTERSECT) {
- // Fallback on bevel if sharp angle is too high (because it would produce very long miters)
+ if (is_intersecting) {
+ // Fallback on bevel if sharp angle is too high (because it would produce very long miters).
float width_factor_sq = width_factor * width_factor;
if (current_joint_mode == Line2D::LINE_JOINT_SHARP && corner_pos_out.distance_squared_to(pos1) / (hw_sq * width_factor_sq) > sharp_limit_sq) {
current_joint_mode = Line2D::LINE_JOINT_BEVEL;
@@ -288,57 +257,78 @@ void LineBuilder::build() {
// Bevel or round
if (orientation == UP) {
pos_up1 = corner_pos_up;
- pos_down1 = pos1 - u0 * hw * width_factor;
+ pos_down1 = pos1 - u0 * modified_hw;
} else {
- pos_up1 = pos1 + u0 * hw * width_factor;
+ pos_up1 = pos1 + u0 * modified_hw;
pos_down1 = corner_pos_down;
}
}
} else {
// No intersection: fallback
if (current_joint_mode == Line2D::LINE_JOINT_SHARP) {
- // There is no fallback implementation for LINE_JOINT_SHARP so switch to the LINE_JOINT_BEVEL
+ // There is no fallback implementation for LINE_JOINT_SHARP so switch to the LINE_JOINT_BEVEL.
current_joint_mode = Line2D::LINE_JOINT_BEVEL;
}
pos_up1 = corner_pos_up;
pos_down1 = corner_pos_down;
}
- // Add current line body quad
- // Triangles are clockwise
+ // Triangles are clockwise.
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
uvx1 = current_distance1 / (width * tile_aspect);
} else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
uvx1 = current_distance1 / total_distance;
}
- strip_add_quad(pos_up1, pos_down1, color1, uvx1);
-
- // Swap vars for use in the next line
+ // Swap vars for use in the next line.
color0 = color1;
u0 = u1;
f0 = f1;
pos0 = pos1;
- if (intersection_result == SEGMENT_INTERSECT) {
+ if (is_intersecting) {
if (current_joint_mode == Line2D::LINE_JOINT_SHARP) {
pos_up0 = pos_up1;
pos_down0 = pos_down1;
} else {
if (orientation == UP) {
pos_up0 = corner_pos_up;
- pos_down0 = pos1 - u1 * hw * width_factor;
+ pos_down0 = pos1 - u1 * modified_hw;
} else {
- pos_up0 = pos1 + u1 * hw * width_factor;
+ pos_up0 = pos1 + u1 * modified_hw;
pos_down0 = corner_pos_down;
}
}
} else {
- pos_up0 = pos1 + u1 * hw * width_factor;
- pos_down0 = pos1 - u1 * hw * width_factor;
+ pos_up0 = pos1 + u1 * modified_hw;
+ pos_down0 = pos1 - u1 * modified_hw;
+ }
+
+ // End the "fake pass" in the closed line case before the drawing subroutine.
+ if (i == -1) {
+ continue;
+ }
+
+ // For wrap-around polylines, store some kind of start positions of the first joint for the final connection.
+ if (wrap_around && i == 0) {
+ Vector2 first_pos_center = (pos_up1 + pos_down1) / 2;
+ float lerp_factor = 1.0 / width_factor;
+ first_pos_up = first_pos_center.lerp(pos_up1, lerp_factor);
+ first_pos_down = first_pos_center.lerp(pos_down1, lerp_factor);
+ is_first_joint_sharp = current_joint_mode == Line2D::LINE_JOINT_SHARP;
+ }
+
+ // Add current line body quad.
+ if (wrap_around && retrieve_curve && !is_first_joint_sharp && i == segments_count) {
+ // If the width curve is not seamless, we might need to fetch the line's start points to use them for the final connection.
+ Vector2 first_pos_center = (first_pos_up + first_pos_down) / 2;
+ strip_add_quad(first_pos_center.lerp(first_pos_up, width_factor), first_pos_center.lerp(first_pos_down, width_factor), color1, uvx1);
+ return;
+ } else {
+ strip_add_quad(pos_up1, pos_down1, color1, uvx1);
}
- // From this point, bu0 and bd0 concern the next segment
- // Add joint geometry
+ // From this point, bu0 and bd0 concern the next segment.
+ // Add joint geometry.
if (current_joint_mode != Line2D::LINE_JOINT_SHARP) {
/* ________________ cbegin
* / \
@@ -358,64 +348,68 @@ void LineBuilder::build() {
cend = pos_up0;
}
- if (current_joint_mode == Line2D::LINE_JOINT_BEVEL) {
+ if (current_joint_mode == Line2D::LINE_JOINT_BEVEL && !(wrap_around && i == segments_count)) {
strip_add_tri(cend, orientation);
- } else if (current_joint_mode == Line2D::LINE_JOINT_ROUND) {
+ } else if (current_joint_mode == Line2D::LINE_JOINT_ROUND && !(wrap_around && i == segments_count)) {
Vector2 vbegin = cbegin - pos1;
Vector2 vend = cend - pos1;
strip_add_arc(pos1, vbegin.angle_to(vend), orientation);
}
- if (intersection_result != SEGMENT_INTERSECT) {
+ if (!is_intersecting) {
// In this case the joint is too corrupted to be re-used,
// start again the strip with fallback points
strip_begin(pos_up0, pos_down0, color1, uvx1);
}
}
}
- // Last (or only) segment
- pos1 = points[points.size() - 1];
- if (distance_required) {
- current_distance1 += pos0.distance_to(pos1);
- }
- if (_interpolate_color) {
- color1 = gradient->get_color(gradient->get_point_count() - 1);
- }
- if (retrieve_curve) {
- width_factor = curve->sample_baked(1.f);
- }
+ // Draw the last (or only) segment, with its end cap logic.
+ if (!wrap_around) {
+ pos1 = points[point_count - 1];
- Vector2 pos_up1 = pos1 + u0 * hw * width_factor;
- Vector2 pos_down1 = pos1 - u0 * hw * width_factor;
+ if (distance_required) {
+ current_distance1 += pos0.distance_to(pos1);
+ }
+ if (_interpolate_color) {
+ color1 = gradient->get_color(gradient->get_point_count() - 1);
+ }
+ if (retrieve_curve) {
+ width_factor = curve->sample_baked(1.f);
+ modified_hw = hw * width_factor;
+ }
- // End cap (box)
- if (end_cap_mode == Line2D::LINE_CAP_BOX) {
- pos_up1 += f0 * hw * width_factor;
- pos_down1 += f0 * hw * width_factor;
+ Vector2 pos_up1 = pos1 + u0 * modified_hw;
+ Vector2 pos_down1 = pos1 - u0 * modified_hw;
- current_distance1 += hw * width_factor;
- }
+ // Add extra distance for a box end cap.
+ if (end_cap_mode == Line2D::LINE_CAP_BOX) {
+ pos_up1 += f0 * modified_hw;
+ pos_down1 += f0 * modified_hw;
- if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
- uvx1 = current_distance1 / (width * tile_aspect);
- } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
- uvx1 = current_distance1 / total_distance;
- }
-
- strip_add_quad(pos_up1, pos_down1, color1, uvx1);
+ current_distance1 += modified_hw;
+ }
- // End cap (round)
- if (end_cap_mode == Line2D::LINE_CAP_ROUND) {
- // Note: color is not used in case we don't interpolate...
- Color color = _interpolate_color ? gradient->get_color(gradient->get_point_count() - 1) : Color(0, 0, 0);
- float dist = 0;
if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
- dist = width_factor / tile_aspect;
+ uvx1 = current_distance1 / (width * tile_aspect);
} else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
- dist = width * width_factor / total_distance;
+ uvx1 = current_distance1 / total_distance;
+ }
+
+ strip_add_quad(pos_up1, pos_down1, color1, uvx1);
+
+ // Custom drawing for a round end cap.
+ if (end_cap_mode == Line2D::LINE_CAP_ROUND) {
+ // Note: color is not used in case we don't interpolate.
+ Color color = _interpolate_color ? gradient->get_color(gradient->get_point_count() - 1) : Color(0, 0, 0);
+ float dist = 0;
+ if (texture_mode == Line2D::LINE_TEXTURE_TILE) {
+ dist = width_factor / tile_aspect;
+ } else if (texture_mode == Line2D::LINE_TEXTURE_STRETCH) {
+ dist = width * width_factor / total_distance;
+ }
+ new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f * dist, 0.f, dist, 1.f));
}
- new_arc(pos1, pos_up1 - pos1, Math_PI, color, Rect2(uvx1 - 0.5f * dist, 0.f, dist, 1.f));
}
}
diff --git a/scene/2d/line_builder.h b/scene/2d/line_builder.h
index 044ff93b42..3706352d5c 100644
--- a/scene/2d/line_builder.h
+++ b/scene/2d/line_builder.h
@@ -41,6 +41,7 @@ public:
Line2D::LineJointMode joint_mode = Line2D::LINE_JOINT_SHARP;
Line2D::LineCapMode begin_cap_mode = Line2D::LINE_CAP_NONE;
Line2D::LineCapMode end_cap_mode = Line2D::LINE_CAP_NONE;
+ bool closed = false;
float width = 10.0;
Curve *curve = nullptr;
Color default_color = Color(0.4, 0.5, 1);
@@ -61,7 +62,6 @@ public:
LineBuilder();
void build();
- void clear_output();
private:
enum Orientation {
diff --git a/scene/2d/navigation_agent_2d.cpp b/scene/2d/navigation_agent_2d.cpp
index 6aeaf300d1..1b3b0bcef0 100644
--- a/scene/2d/navigation_agent_2d.cpp
+++ b/scene/2d/navigation_agent_2d.cpp
@@ -560,7 +560,7 @@ Vector2 NavigationAgent2D::get_next_path_position() {
const Vector<Vector2> &navigation_path = navigation_result->get_path();
if (navigation_path.size() == 0) {
- ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector2(), "The agent has no parent.");
+ ERR_FAIL_NULL_V_MSG(agent_parent, Vector2(), "The agent has no parent.");
return agent_parent->get_global_position();
} else {
return navigation_path[navigation_path_index];
@@ -568,7 +568,7 @@ Vector2 NavigationAgent2D::get_next_path_position() {
}
real_t NavigationAgent2D::distance_to_target() const {
- ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent.");
+ ERR_FAIL_NULL_V_MSG(agent_parent, 0.0, "The agent has no parent.");
return agent_parent->get_global_position().distance_to(target_position);
}
diff --git a/scene/2d/physical_bone_2d.cpp b/scene/2d/physical_bone_2d.cpp
index efffa56f17..64cf56fa85 100644
--- a/scene/2d/physical_bone_2d.cpp
+++ b/scene/2d/physical_bone_2d.cpp
@@ -71,7 +71,7 @@ void PhysicalBone2D::_position_at_bone2d() {
// Reset to Bone2D position
if (parent_skeleton) {
Bone2D *bone_to_use = parent_skeleton->get_bone(bone2d_index);
- ERR_FAIL_COND_MSG(bone_to_use == nullptr, "It's not possible to position the bone with ID: " + itos(bone2d_index));
+ ERR_FAIL_NULL_MSG(bone_to_use, "It's not possible to position the bone with ID: " + itos(bone2d_index) + ".");
set_global_transform(bone_to_use->get_global_transform());
}
}
diff --git a/scene/2d/tile_map.cpp b/scene/2d/tile_map.cpp
index 6938358994..0c1aab6198 100644
--- a/scene/2d/tile_map.cpp
+++ b/scene/2d/tile_map.cpp
@@ -548,7 +548,7 @@ void TileMapLayer::_rendering_occluders_update_cell(CellData &r_cell_data) {
RID occluder_id = rs->canvas_light_occluder_create();
rs->canvas_light_occluder_set_enabled(occluder_id, node_visible);
rs->canvas_light_occluder_set_transform(occluder_id, tile_map_node->get_global_transform() * xform);
- rs->canvas_light_occluder_set_polygon(occluder_id, tile_data->get_occluder(i)->get_rid());
+ rs->canvas_light_occluder_set_polygon(occluder_id, tile_map_node->get_transformed_polygon(Ref<Resource>(tile_data->get_occluder(i)), r_cell_data.cell.alternative_tile)->get_rid());
rs->canvas_light_occluder_attach_to_canvas(occluder_id, tile_map_node->get_canvas());
rs->canvas_light_occluder_set_light_mask(occluder_id, tile_set->get_occlusion_layer_light_mask(i));
r_cell_data.occluders.push_back(occluder_id);
@@ -783,6 +783,7 @@ void TileMapLayer::_physics_update_cell(CellData &r_cell_data) {
for (int shape_index = 0; shape_index < shapes_count; shape_index++) {
// Add decomposed convex shapes.
Ref<ConvexPolygonShape2D> shape = tile_data->get_collision_polygon_shape(tile_set_physics_layer, polygon_index, shape_index);
+ shape = tile_map_node->get_transformed_polygon(Ref<Resource>(shape), c.alternative_tile);
ps->body_add_shape(body, shape->get_rid());
ps->body_set_shape_as_one_way_collision(body, body_shape_index, one_way_collision, one_way_collision_margin);
@@ -985,6 +986,7 @@ void TileMapLayer::_navigation_update_cell(CellData &r_cell_data) {
for (unsigned int navigation_layer_index = 0; navigation_layer_index < r_cell_data.navigation_regions.size(); navigation_layer_index++) {
Ref<NavigationPolygon> navigation_polygon;
navigation_polygon = tile_data->get_navigation_polygon(navigation_layer_index);
+ navigation_polygon = tile_map_node->get_transformed_polygon(Ref<Resource>(navigation_polygon), c.alternative_tile);
RID &region = r_cell_data.navigation_regions[navigation_layer_index];
@@ -1074,6 +1076,7 @@ void TileMapLayer::_navigation_draw_cell_debug(const RID &p_canvas_item, const V
for (int layer_index = 0; layer_index < tile_set->get_navigation_layers_count(); layer_index++) {
Ref<NavigationPolygon> navigation_polygon = tile_data->get_navigation_polygon(layer_index);
if (navigation_polygon.is_valid()) {
+ navigation_polygon = tile_map_node->get_transformed_polygon(Ref<Resource>(navigation_polygon), c.alternative_tile);
Vector<Vector2> navigation_polygon_vertices = navigation_polygon->get_vertices();
if (navigation_polygon_vertices.size() < 3) {
continue;
@@ -2288,21 +2291,14 @@ TypedArray<Vector2i> TileMapLayer::get_used_cells_by_id(int p_source_id, const V
Rect2i TileMapLayer::get_used_rect() const {
// Return the rect of the currently used area.
if (used_rect_cache_dirty) {
- bool first = true;
used_rect_cache = Rect2i();
if (tile_map.size() > 0) {
- if (first) {
- used_rect_cache = Rect2i(tile_map.begin()->key.x, tile_map.begin()->key.y, 0, 0);
- first = false;
- }
+ used_rect_cache = Rect2i(tile_map.begin()->key.x, tile_map.begin()->key.y, 0, 0);
for (const KeyValue<Vector2i, CellData> &E : tile_map) {
- used_rect_cache.expand_to(Vector2i(E.key.x, E.key.y));
+ used_rect_cache.expand_to(E.key);
}
- }
-
- if (!first) { // first is true if every layer is empty.
used_rect_cache.size += Vector2i(1, 1); // The cache expands to top-left coordinate, so we add one full tile.
}
used_rect_cache_dirty = false;
@@ -3012,6 +3008,7 @@ void TileMap::_internal_update() {
}
// Update dirty quadrants on layers.
+ polygon_cache.clear();
for (Ref<TileMapLayer> &layer : layers) {
layer->internal_update();
}
@@ -3100,18 +3097,18 @@ void TileMap::draw_tile(RID p_canvas_item, const Vector2 &p_position, const Ref<
dest_rect.size.x += FP_ADJUST;
dest_rect.size.y += FP_ADJUST;
- bool transpose = tile_data->get_transpose();
+ bool transpose = tile_data->get_transpose() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
if (transpose) {
dest_rect.position = (p_position - Vector2(dest_rect.size.y, dest_rect.size.x) / 2 - tile_offset);
} else {
dest_rect.position = (p_position - dest_rect.size / 2 - tile_offset);
}
- if (tile_data->get_flip_h()) {
+ if (tile_data->get_flip_h() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_H)) {
dest_rect.size.x = -dest_rect.size.x;
}
- if (tile_data->get_flip_v()) {
+ if (tile_data->get_flip_v() ^ bool(p_alternative_tile & TileSetAtlasSource::TRANSFORM_FLIP_V)) {
dest_rect.size.y = -dest_rect.size.y;
}
@@ -3482,6 +3479,37 @@ Rect2 TileMap::_edit_get_rect() const {
}
#endif
+PackedVector2Array TileMap::_get_transformed_vertices(const PackedVector2Array &p_vertices, int p_alternative_id) {
+ const Vector2 *r = p_vertices.ptr();
+ int size = p_vertices.size();
+
+ PackedVector2Array new_points;
+ new_points.resize(size);
+ Vector2 *w = new_points.ptrw();
+
+ bool flip_h = (p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_H);
+ bool flip_v = (p_alternative_id & TileSetAtlasSource::TRANSFORM_FLIP_V);
+ bool transpose = (p_alternative_id & TileSetAtlasSource::TRANSFORM_TRANSPOSE);
+
+ for (int i = 0; i < size; i++) {
+ Vector2 v;
+ if (transpose) {
+ v = Vector2(r[i].y, r[i].x);
+ } else {
+ v = r[i];
+ }
+
+ if (flip_h) {
+ v.x *= -1;
+ }
+ if (flip_v) {
+ v.y *= -1;
+ }
+ w[i] = v;
+ }
+ return new_points;
+}
+
bool TileMap::_set(const StringName &p_name, const Variant &p_value) {
Vector<String> components = String(p_name).split("/", true, 2);
if (p_name == "format") {
@@ -4239,12 +4267,19 @@ TypedArray<Vector2i> TileMap::get_used_cells_by_id(int p_layer, int p_source_id,
Rect2i TileMap::get_used_rect() const {
// Return the visible rect of the tilemap.
- if (layers.is_empty()) {
- return Rect2i();
- }
- Rect2 rect = layers[0]->get_used_rect();
- for (unsigned int i = 1; i < layers.size(); i++) {
- rect = rect.merge(layers[i]->get_used_rect());
+ bool first = true;
+ Rect2i rect = Rect2i();
+ for (const Ref<TileMapLayer> &layer : layers) {
+ Rect2i layer_rect = layer->get_used_rect();
+ if (layer_rect == Rect2i()) {
+ continue;
+ }
+ if (first) {
+ rect = layer_rect;
+ first = false;
+ } else {
+ rect = rect.merge(layer_rect);
+ }
}
return rect;
}
@@ -4384,6 +4419,57 @@ void TileMap::draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_ce
#undef DRAW_SIDE_IF_NEEDED
}
+Ref<Resource> TileMap::get_transformed_polygon(Ref<Resource> p_polygon, int p_alternative_id) {
+ if (!bool(p_alternative_id & (TileSetAtlasSource::TRANSFORM_FLIP_H | TileSetAtlasSource::TRANSFORM_FLIP_V | TileSetAtlasSource::TRANSFORM_TRANSPOSE))) {
+ return p_polygon;
+ }
+
+ {
+ HashMap<Pair<Ref<Resource>, int>, Ref<Resource>, PairHash<Ref<Resource>, int>>::Iterator E = polygon_cache.find(Pair<Ref<Resource>, int>(p_polygon, p_alternative_id));
+ if (E) {
+ return E->value;
+ }
+ }
+
+ Ref<ConvexPolygonShape2D> col = p_polygon;
+ if (col.is_valid()) {
+ Ref<ConvexPolygonShape2D> ret;
+ ret.instantiate();
+ ret->set_points(_get_transformed_vertices(col->get_points(), p_alternative_id));
+ polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret;
+ return ret;
+ }
+
+ Ref<NavigationPolygon> nav = p_polygon;
+ if (nav.is_valid()) {
+ PackedVector2Array new_points = _get_transformed_vertices(nav->get_vertices(), p_alternative_id);
+ Ref<NavigationPolygon> ret;
+ ret.instantiate();
+ ret->set_vertices(new_points);
+
+ PackedInt32Array indices;
+ indices.resize(new_points.size());
+ int *w = indices.ptrw();
+ for (int i = 0; i < new_points.size(); i++) {
+ w[i] = i;
+ }
+ ret->add_polygon(indices);
+ polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret;
+ return ret;
+ }
+
+ Ref<OccluderPolygon2D> ocd = p_polygon;
+ if (ocd.is_valid()) {
+ Ref<OccluderPolygon2D> ret;
+ ret.instantiate();
+ ret->set_polygon(_get_transformed_vertices(ocd->get_polygon(), p_alternative_id));
+ polygon_cache[Pair<Ref<Resource>, int>(p_polygon, p_alternative_id)] = ret;
+ return ret;
+ }
+
+ return p_polygon;
+}
+
PackedStringArray TileMap::get_configuration_warnings() const {
PackedStringArray warnings = Node::get_configuration_warnings();
diff --git a/scene/2d/tile_map.h b/scene/2d/tile_map.h
index 7782d7de96..f804f808cb 100644
--- a/scene/2d/tile_map.h
+++ b/scene/2d/tile_map.h
@@ -455,6 +455,10 @@ private:
void _tile_set_changed();
+ // Polygons.
+ HashMap<Pair<Ref<Resource>, int>, Ref<Resource>, PairHash<Ref<Resource>, int>> polygon_cache;
+ PackedVector2Array _get_transformed_vertices(const PackedVector2Array &p_vertices, int p_alternative_id);
+
protected:
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -595,6 +599,7 @@ public:
// Helpers?
TypedArray<Vector2i> get_surrounding_cells(const Vector2i &coords);
void draw_cells_outline(Control *p_control, const RBSet<Vector2i> &p_cells, Color p_color, Transform2D p_transform = Transform2D());
+ Ref<Resource> get_transformed_polygon(Ref<Resource> p_polygon, int p_alternative_id);
// Virtual function to modify the TileData at runtime.
GDVIRTUAL2R(bool, _use_tile_data_runtime_update, int, Vector2i);
diff --git a/scene/3d/audio_stream_player_3d.cpp b/scene/3d/audio_stream_player_3d.cpp
index 8147521a01..9f99b5ecbd 100644
--- a/scene/3d/audio_stream_player_3d.cpp
+++ b/scene/3d/audio_stream_player_3d.cpp
@@ -674,10 +674,6 @@ void AudioStreamPlayer3D::_validate_property(PropertyInfo &p_property) const {
}
}
-void AudioStreamPlayer3D::_bus_layout_changed() {
- notify_property_list_changed();
-}
-
void AudioStreamPlayer3D::set_max_distance(float p_metres) {
ERR_FAIL_COND(p_metres < 0.0);
max_distance = p_metres;
@@ -814,6 +810,14 @@ float AudioStreamPlayer3D::get_panning_strength() const {
return panning_strength;
}
+void AudioStreamPlayer3D::_on_bus_layout_changed() {
+ notify_property_list_changed();
+}
+
+void AudioStreamPlayer3D::_on_bus_renamed(int p_bus_index, const StringName &p_old_name, const StringName &p_new_name) {
+ notify_property_list_changed();
+}
+
void AudioStreamPlayer3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_stream", "stream"), &AudioStreamPlayer3D::set_stream);
ClassDB::bind_method(D_METHOD("get_stream"), &AudioStreamPlayer3D::get_stream);
@@ -923,7 +927,8 @@ void AudioStreamPlayer3D::_bind_methods() {
AudioStreamPlayer3D::AudioStreamPlayer3D() {
velocity_tracker.instantiate();
- AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_bus_layout_changed));
+ AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer3D::_on_bus_layout_changed));
+ AudioServer::get_singleton()->connect("bus_renamed", callable_mp(this, &AudioStreamPlayer3D::_on_bus_renamed));
set_disable_scale(true);
cached_global_panning_strength = GLOBAL_GET("audio/general/3d_panning_strength");
}
diff --git a/scene/3d/audio_stream_player_3d.h b/scene/3d/audio_stream_player_3d.h
index bba8f10761..f20170e63b 100644
--- a/scene/3d/audio_stream_player_3d.h
+++ b/scene/3d/audio_stream_player_3d.h
@@ -97,7 +97,8 @@ private:
Area3D *_get_overriding_area();
Vector<AudioFrame> _update_panning();
- void _bus_layout_changed();
+ void _on_bus_layout_changed();
+ void _on_bus_renamed(int p_bus_index, const StringName &p_old_name, const StringName &p_new_name);
uint32_t area_mask = 1;
diff --git a/scene/3d/gpu_particles_3d.cpp b/scene/3d/gpu_particles_3d.cpp
index a7667267a6..12f13bee2f 100644
--- a/scene/3d/gpu_particles_3d.cpp
+++ b/scene/3d/gpu_particles_3d.cpp
@@ -48,11 +48,11 @@ void GPUParticles3D::set_emitting(bool p_emitting) {
// Last cycle ended.
active = true;
time = 0;
- signal_cancled = false;
+ signal_canceled = false;
emission_time = lifetime;
active_time = lifetime * (2 - explosiveness_ratio);
} else {
- signal_cancled = true;
+ signal_canceled = true;
}
set_process_internal(true);
} else if (!p_emitting) {
@@ -397,7 +397,7 @@ void GPUParticles3D::restart() {
emitting = true;
active = true;
- signal_cancled = false;
+ signal_canceled = false;
time = 0;
emission_time = lifetime * (1 - explosiveness_ratio);
active_time = lifetime * (2 - explosiveness_ratio);
@@ -465,7 +465,7 @@ void GPUParticles3D::_notification(int p_what) {
}
}
if (time > active_time) {
- if (active && !signal_cancled) {
+ if (active && !signal_canceled) {
emit_signal(SceneStringNames::get_singleton()->finished);
}
active = false;
diff --git a/scene/3d/gpu_particles_3d.h b/scene/3d/gpu_particles_3d.h
index 6e9083bda2..f3df4f1929 100644
--- a/scene/3d/gpu_particles_3d.h
+++ b/scene/3d/gpu_particles_3d.h
@@ -62,7 +62,7 @@ private:
bool emitting = false;
bool active = false;
- bool signal_cancled = false;
+ bool signal_canceled = false;
bool one_shot = false;
int amount = 0;
double lifetime = 0.0;
diff --git a/scene/3d/joint_3d.cpp b/scene/3d/joint_3d.cpp
index 61f89648ee..f1361ab1bb 100644
--- a/scene/3d/joint_3d.cpp
+++ b/scene/3d/joint_3d.cpp
@@ -221,6 +221,8 @@ void Joint3D::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_exclude_nodes_from_collision", "enable"), &Joint3D::set_exclude_nodes_from_collision);
ClassDB::bind_method(D_METHOD("get_exclude_nodes_from_collision"), &Joint3D::get_exclude_nodes_from_collision);
+ ClassDB::bind_method(D_METHOD("get_rid"), &Joint3D::get_rid);
+
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_a", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_a", "get_node_a");
ADD_PROPERTY(PropertyInfo(Variant::NODE_PATH, "node_b", PROPERTY_HINT_NODE_PATH_VALID_TYPES, "PhysicsBody3D"), "set_node_b", "get_node_b");
ADD_PROPERTY(PropertyInfo(Variant::INT, "solver_priority", PROPERTY_HINT_RANGE, "1,8,1"), "set_solver_priority", "get_solver_priority");
@@ -257,7 +259,7 @@ void PinJoint3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, 3);
params[p_param] = p_value;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->pin_joint_set_param(get_joint(), PhysicsServer3D::PinJointParam(p_param), p_value);
+ PhysicsServer3D::get_singleton()->pin_joint_set_param(get_rid(), PhysicsServer3D::PinJointParam(p_param), p_value);
}
}
@@ -332,7 +334,7 @@ void HingeJoint3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params[p_param] = p_value;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->hinge_joint_set_param(get_joint(), PhysicsServer3D::HingeJointParam(p_param), p_value);
+ PhysicsServer3D::get_singleton()->hinge_joint_set_param(get_rid(), PhysicsServer3D::HingeJointParam(p_param), p_value);
}
update_gizmos();
@@ -347,7 +349,7 @@ void HingeJoint3D::set_flag(Flag p_flag, bool p_value) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags[p_flag] = p_value;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->hinge_joint_set_flag(get_joint(), PhysicsServer3D::HingeJointFlag(p_flag), p_value);
+ PhysicsServer3D::get_singleton()->hinge_joint_set_flag(get_rid(), PhysicsServer3D::HingeJointFlag(p_flag), p_value);
}
update_gizmos();
@@ -458,7 +460,7 @@ void SliderJoint3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params[p_param] = p_value;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->slider_joint_set_param(get_joint(), PhysicsServer3D::SliderJointParam(p_param), p_value);
+ PhysicsServer3D::get_singleton()->slider_joint_set_param(get_rid(), PhysicsServer3D::SliderJointParam(p_param), p_value);
}
update_gizmos();
}
@@ -540,7 +542,7 @@ void ConeTwistJoint3D::set_param(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params[p_param] = p_value;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(get_joint(), PhysicsServer3D::ConeTwistJointParam(p_param), p_value);
+ PhysicsServer3D::get_singleton()->cone_twist_joint_set_param(get_rid(), PhysicsServer3D::ConeTwistJointParam(p_param), p_value);
}
update_gizmos();
@@ -753,7 +755,7 @@ void Generic6DOFJoint3D::set_param_x(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_x[p_param] = p_value;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
update_gizmos();
@@ -768,7 +770,7 @@ void Generic6DOFJoint3D::set_param_y(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_y[p_param] = p_value;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
update_gizmos();
}
@@ -782,7 +784,7 @@ void Generic6DOFJoint3D::set_param_z(Param p_param, real_t p_value) {
ERR_FAIL_INDEX(p_param, PARAM_MAX);
params_z[p_param] = p_value;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_param(get_rid(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisParam(p_param), p_value);
}
update_gizmos();
}
@@ -796,7 +798,7 @@ void Generic6DOFJoint3D::set_flag_x(Flag p_flag, bool p_enabled) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags_x[p_flag] = p_enabled;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_rid(), Vector3::AXIS_X, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
update_gizmos();
}
@@ -810,7 +812,7 @@ void Generic6DOFJoint3D::set_flag_y(Flag p_flag, bool p_enabled) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags_y[p_flag] = p_enabled;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_rid(), Vector3::AXIS_Y, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
update_gizmos();
}
@@ -824,7 +826,7 @@ void Generic6DOFJoint3D::set_flag_z(Flag p_flag, bool p_enabled) {
ERR_FAIL_INDEX(p_flag, FLAG_MAX);
flags_z[p_flag] = p_enabled;
if (is_configured()) {
- PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_joint(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
+ PhysicsServer3D::get_singleton()->generic_6dof_joint_set_flag(get_rid(), Vector3::AXIS_Z, PhysicsServer3D::G6DOFJointAxisFlag(p_flag), p_enabled);
}
update_gizmos();
}
diff --git a/scene/3d/joint_3d.h b/scene/3d/joint_3d.h
index cadd617153..527aed4079 100644
--- a/scene/3d/joint_3d.h
+++ b/scene/3d/joint_3d.h
@@ -77,7 +77,7 @@ public:
void set_exclude_nodes_from_collision(bool p_enable);
bool get_exclude_nodes_from_collision() const;
- RID get_joint() const { return joint; }
+ RID get_rid() const { return joint; }
Joint3D();
~Joint3D();
};
diff --git a/scene/3d/lightmap_gi.cpp b/scene/3d/lightmap_gi.cpp
index a666dca658..5dd1e6954d 100644
--- a/scene/3d/lightmap_gi.cpp
+++ b/scene/3d/lightmap_gi.cpp
@@ -1082,7 +1082,9 @@ LightmapGI::BakeError LightmapGI::bake(Node *p_from_node, String p_image_data_pa
Lightmapper::BakeError bake_err = lightmapper->bake(Lightmapper::BakeQuality(bake_quality), use_denoiser, bounces, bias, max_texture_size, directional, Lightmapper::GenerateProbes(gen_probes), environment_image, environment_transform, _lightmap_bake_step_function, &bsud, exposure_normalization);
- if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) {
+ if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_TOO_SMALL) {
+ return BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL;
+ } else if (bake_err == Lightmapper::BAKE_ERROR_LIGHTMAP_CANT_PRE_BAKE_MESHES) {
return BAKE_ERROR_MESHES_INVALID;
}
@@ -1566,6 +1568,7 @@ void LightmapGI::_bind_methods() {
BIND_ENUM_CONSTANT(BAKE_ERROR_MESHES_INVALID);
BIND_ENUM_CONSTANT(BAKE_ERROR_CANT_CREATE_IMAGE);
BIND_ENUM_CONSTANT(BAKE_ERROR_USER_ABORTED);
+ BIND_ENUM_CONSTANT(BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL);
BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_DISABLED);
BIND_ENUM_CONSTANT(ENVIRONMENT_MODE_SCENE);
diff --git a/scene/3d/lightmap_gi.h b/scene/3d/lightmap_gi.h
index b9e33cf300..02123ef7ba 100644
--- a/scene/3d/lightmap_gi.h
+++ b/scene/3d/lightmap_gi.h
@@ -132,6 +132,7 @@ public:
BAKE_ERROR_MESHES_INVALID,
BAKE_ERROR_CANT_CREATE_IMAGE,
BAKE_ERROR_USER_ABORTED,
+ BAKE_ERROR_TEXTURE_SIZE_TOO_SMALL,
};
enum EnvironmentMode {
diff --git a/scene/3d/navigation_agent_3d.cpp b/scene/3d/navigation_agent_3d.cpp
index 93acf38fa8..3c119671ec 100644
--- a/scene/3d/navigation_agent_3d.cpp
+++ b/scene/3d/navigation_agent_3d.cpp
@@ -602,7 +602,7 @@ Vector3 NavigationAgent3D::get_next_path_position() {
const Vector<Vector3> &navigation_path = navigation_result->get_path();
if (navigation_path.size() == 0) {
- ERR_FAIL_COND_V_MSG(agent_parent == nullptr, Vector3(), "The agent has no parent.");
+ ERR_FAIL_NULL_V_MSG(agent_parent, Vector3(), "The agent has no parent.");
return agent_parent->get_global_position();
} else {
return navigation_path[navigation_path_index] - Vector3(0, path_height_offset, 0);
@@ -610,7 +610,7 @@ Vector3 NavigationAgent3D::get_next_path_position() {
}
real_t NavigationAgent3D::distance_to_target() const {
- ERR_FAIL_COND_V_MSG(agent_parent == nullptr, 0.0, "The agent has no parent.");
+ ERR_FAIL_NULL_V_MSG(agent_parent, 0.0, "The agent has no parent.");
return agent_parent->get_global_position().distance_to(target_position);
}
diff --git a/scene/3d/soft_body_3d.cpp b/scene/3d/soft_body_3d.cpp
index d1753fff6c..d24dd755dc 100644
--- a/scene/3d/soft_body_3d.cpp
+++ b/scene/3d/soft_body_3d.cpp
@@ -78,14 +78,13 @@ void SoftBodyRenderingServerHandler::commit_changes() {
RS::get_singleton()->mesh_surface_update_vertex_region(mesh, surface, 0, buffer);
}
-void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
- memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], p_vector3, sizeof(float) * 3);
+void SoftBodyRenderingServerHandler::set_vertex(int p_vertex_id, const Vector3 &p_vertex) {
+ memcpy(&write_buffer[p_vertex_id * stride + offset_vertices], &p_vertex, sizeof(Vector3));
}
-void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
+void SoftBodyRenderingServerHandler::set_normal(int p_vertex_id, const Vector3 &p_normal) {
// Store normal vector in A2B10G10R10 format.
- Vector3 n;
- memcpy(&n, p_vector3, sizeof(Vector3));
+ Vector3 n = p_normal;
n *= Vector3(0.5, 0.5, 0.5);
n += Vector3(0.5, 0.5, 0.5);
Vector2 res = n.octahedron_encode();
diff --git a/scene/3d/soft_body_3d.h b/scene/3d/soft_body_3d.h
index 0b75ae2cda..6648f956dc 100644
--- a/scene/3d/soft_body_3d.h
+++ b/scene/3d/soft_body_3d.h
@@ -59,8 +59,8 @@ private:
void commit_changes();
public:
- void set_vertex(int p_vertex_id, const void *p_vector3) override;
- void set_normal(int p_vertex_id, const void *p_vector3) override;
+ void set_vertex(int p_vertex_id, const Vector3 &p_vertex) override;
+ void set_normal(int p_vertex_id, const Vector3 &p_normal) override;
void set_aabb(const AABB &p_aabb) override;
};
diff --git a/scene/3d/sprite_3d.cpp b/scene/3d/sprite_3d.cpp
index 1345cfcdb8..8250263c35 100644
--- a/scene/3d/sprite_3d.cpp
+++ b/scene/3d/sprite_3d.cpp
@@ -1231,7 +1231,7 @@ void AnimatedSprite3D::play(const StringName &p_name, float p_custom_scale, bool
name = animation;
}
- ERR_FAIL_COND_MSG(frames == nullptr, vformat("There is no animation with name '%s'.", name));
+ ERR_FAIL_NULL_MSG(frames, vformat("There is no animation with name '%s'.", name));
ERR_FAIL_COND_MSG(!frames->get_animation_names().has(name), vformat("There is no animation with name '%s'.", name));
if (frames->get_frame_count(name) == 0) {
diff --git a/scene/animation/animation_blend_tree.cpp b/scene/animation/animation_blend_tree.cpp
index 8da1ef8e1d..b9cbd3cf94 100644
--- a/scene/animation/animation_blend_tree.cpp
+++ b/scene/animation/animation_blend_tree.cpp
@@ -149,7 +149,7 @@ double AnimationNodeAnimation::_process(double p_time, bool p_seek, bool p_is_ex
}
// Emit start & finish signal. Internally, the detections are the same for backward.
- // We should use call_deferred since the track keys are still being prosessed.
+ // We should use call_deferred since the track keys are still being processed.
if (state->tree && !p_test_only) {
// AnimationTree uses seek to 0 "internally" to process the first key of the animation, which is used as the start detection.
if (p_seek && !p_is_external_seeking && cur_time == 0) {
diff --git a/scene/animation/animation_node_state_machine.cpp b/scene/animation/animation_node_state_machine.cpp
index 0254419d22..eeacef4ef7 100644
--- a/scene/animation/animation_node_state_machine.cpp
+++ b/scene/animation/animation_node_state_machine.cpp
@@ -1100,7 +1100,7 @@ bool AnimationNodeStateMachinePlayback::_check_advance_condition(const Ref<Anima
if (transition->expression.is_valid()) {
AnimationTree *tree_base = state_machine->get_animation_tree();
- ERR_FAIL_COND_V(tree_base == nullptr, false);
+ ERR_FAIL_NULL_V(tree_base, false);
NodePath advance_expression_base_node_path = tree_base->get_advance_expression_base_node();
Node *expression_base = tree_base->get_node_or_null(advance_expression_base_node_path);
diff --git a/scene/audio/audio_stream_player.cpp b/scene/audio/audio_stream_player.cpp
index ae68bd719b..7f6dfd0ab8 100644
--- a/scene/audio/audio_stream_player.cpp
+++ b/scene/audio/audio_stream_player.cpp
@@ -236,6 +236,14 @@ bool AudioStreamPlayer::_is_active() const {
return false;
}
+void AudioStreamPlayer::_on_bus_layout_changed() {
+ notify_property_list_changed();
+}
+
+void AudioStreamPlayer::_on_bus_renamed(int p_bus_index, const StringName &p_old_name, const StringName &p_new_name) {
+ notify_property_list_changed();
+}
+
void AudioStreamPlayer::set_stream_paused(bool p_pause) {
// TODO this does not have perfect recall, fix that maybe? If there are zero playbacks registered with the AudioServer, this bool isn't persisted.
for (Ref<AudioStreamPlayback> &playback : stream_playbacks) {
@@ -303,10 +311,6 @@ void AudioStreamPlayer::_validate_property(PropertyInfo &p_property) const {
}
}
-void AudioStreamPlayer::_bus_layout_changed() {
- notify_property_list_changed();
-}
-
bool AudioStreamPlayer::has_stream_playback() {
return !stream_playbacks.is_empty();
}
@@ -372,7 +376,8 @@ void AudioStreamPlayer::_bind_methods() {
}
AudioStreamPlayer::AudioStreamPlayer() {
- AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer::_bus_layout_changed));
+ AudioServer::get_singleton()->connect("bus_layout_changed", callable_mp(this, &AudioStreamPlayer::_on_bus_layout_changed));
+ AudioServer::get_singleton()->connect("bus_renamed", callable_mp(this, &AudioStreamPlayer::_on_bus_renamed));
}
AudioStreamPlayer::~AudioStreamPlayer() {
diff --git a/scene/audio/audio_stream_player.h b/scene/audio/audio_stream_player.h
index c0c25aa983..9dbdccdc69 100644
--- a/scene/audio/audio_stream_player.h
+++ b/scene/audio/audio_stream_player.h
@@ -60,15 +60,11 @@ private:
MixTarget mix_target = MIX_TARGET_STEREO;
- void _mix_internal(bool p_fadeout);
- void _mix_audio();
- static void _mix_audios(void *self) { reinterpret_cast<AudioStreamPlayer *>(self)->_mix_audio(); }
-
void _set_playing(bool p_enable);
bool _is_active() const;
- void _bus_layout_changed();
- void _mix_to_bus(const AudioFrame *p_frames, int p_amount);
+ void _on_bus_layout_changed();
+ void _on_bus_renamed(int p_bus_index, const StringName &p_old_name, const StringName &p_new_name);
Vector<AudioFrame> _get_volume_vector();
diff --git a/scene/gui/box_container.cpp b/scene/gui/box_container.cpp
index 97729b1ac5..2728126e64 100644
--- a/scene/gui/box_container.cpp
+++ b/scene/gui/box_container.cpp
@@ -30,8 +30,9 @@
#include "box_container.h"
-#include "label.h"
-#include "margin_container.h"
+#include "scene/gui/label.h"
+#include "scene/gui/margin_container.h"
+#include "scene/theme/theme_db.h"
struct _MinSizeCache {
int min_size = 0;
@@ -288,12 +289,6 @@ Size2 BoxContainer::get_minimum_size() const {
return minimum;
}
-void BoxContainer::_update_theme_item_cache() {
- Container::_update_theme_item_cache();
-
- theme_cache.separation = get_theme_constant(SNAME("separation"));
-}
-
void BoxContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
@@ -399,6 +394,8 @@ void BoxContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment", "get_alignment");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, BoxContainer, separation);
}
MarginContainer *VBoxContainer::add_margin_child(const String &p_label, Control *p_control, bool p_expand) {
diff --git a/scene/gui/box_container.h b/scene/gui/box_container.h
index 31fd13c22f..c8cfe11062 100644
--- a/scene/gui/box_container.h
+++ b/scene/gui/box_container.h
@@ -56,8 +56,6 @@ private:
protected:
bool is_fixed = false;
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/scene/gui/button.cpp b/scene/gui/button.cpp
index a94b12541e..23a581c5f6 100644
--- a/scene/gui/button.cpp
+++ b/scene/gui/button.cpp
@@ -31,6 +31,7 @@
#include "button.h"
#include "core/string/translation.h"
+#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
Size2 Button::get_minimum_size() const {
@@ -49,46 +50,6 @@ void Button::_set_internal_margin(Side p_side, float p_value) {
void Button::_queue_update_size_cache() {
}
-void Button::_update_theme_item_cache() {
- BaseButton::_update_theme_item_cache();
-
- theme_cache.normal = get_theme_stylebox(SNAME("normal"));
- theme_cache.normal_mirrored = get_theme_stylebox(SNAME("normal_mirrored"));
- theme_cache.pressed = get_theme_stylebox(SNAME("pressed"));
- theme_cache.pressed_mirrored = get_theme_stylebox(SNAME("pressed_mirrored"));
- theme_cache.hover = get_theme_stylebox(SNAME("hover"));
- theme_cache.hover_mirrored = get_theme_stylebox(SNAME("hover_mirrored"));
- theme_cache.hover_pressed = get_theme_stylebox(SNAME("hover_pressed"));
- theme_cache.hover_pressed_mirrored = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
- theme_cache.disabled = get_theme_stylebox(SNAME("disabled"));
- theme_cache.disabled_mirrored = get_theme_stylebox(SNAME("disabled_mirrored"));
- theme_cache.focus = get_theme_stylebox(SNAME("focus"));
-
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
- theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
- theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
- theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
- theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
-
- theme_cache.icon_normal_color = get_theme_color(SNAME("icon_normal_color"));
- theme_cache.icon_focus_color = get_theme_color(SNAME("icon_focus_color"));
- theme_cache.icon_pressed_color = get_theme_color(SNAME("icon_pressed_color"));
- theme_cache.icon_hover_color = get_theme_color(SNAME("icon_hover_color"));
- theme_cache.icon_hover_pressed_color = get_theme_color(SNAME("icon_hover_pressed_color"));
- theme_cache.icon_disabled_color = get_theme_color(SNAME("icon_disabled_color"));
-
- theme_cache.icon = get_theme_icon(SNAME("icon"));
-
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
-}
-
void Button::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
@@ -670,6 +631,42 @@ void Button::_bind_methods() {
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, normal);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, normal_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, pressed);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, pressed_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, hover);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, hover_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, hover_pressed);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, hover_pressed_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, disabled_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Button, focus);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_focus_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_hover_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_hover_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_disabled_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, Button, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, Button, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, outline_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, font_outline_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_normal_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_focus_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_hover_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_hover_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Button, icon_disabled_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Button, icon);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Button, icon_max_width);
}
Button::Button(const String &p_text) {
diff --git a/scene/gui/button.h b/scene/gui/button.h
index 4fefb9fb07..ad7412b54e 100644
--- a/scene/gui/button.h
+++ b/scene/gui/button.h
@@ -100,8 +100,8 @@ private:
protected:
void _set_internal_margin(Side p_side, float p_value);
- virtual void _update_theme_item_cache() override;
virtual void _queue_update_size_cache();
+
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/check_box.cpp b/scene/gui/check_box.cpp
index 008fe9181d..6c02ba1a86 100644
--- a/scene/gui/check_box.cpp
+++ b/scene/gui/check_box.cpp
@@ -30,6 +30,7 @@
#include "check_box.h"
+#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
Size2 CheckBox::get_icon_size() const {
@@ -73,23 +74,6 @@ Size2 CheckBox::get_minimum_size() const {
return minsize;
}
-void CheckBox::_update_theme_item_cache() {
- Button::_update_theme_item_cache();
-
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.check_v_offset = get_theme_constant(SNAME("check_v_offset"));
- theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
-
- theme_cache.checked = get_theme_icon(SNAME("checked"));
- theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
- theme_cache.radio_checked = get_theme_icon(SNAME("radio_checked"));
- theme_cache.radio_unchecked = get_theme_icon(SNAME("radio_unchecked"));
- theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
- theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
- theme_cache.radio_checked_disabled = get_theme_icon(SNAME("radio_checked_disabled"));
- theme_cache.radio_unchecked_disabled = get_theme_icon(SNAME("radio_unchecked_disabled"));
-}
-
void CheckBox::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
@@ -149,6 +133,21 @@ bool CheckBox::is_radio() {
return get_button_group().is_valid();
}
+void CheckBox::_bind_methods() {
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, CheckBox, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, CheckBox, check_v_offset);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, CheckBox, normal_style, "normal");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckBox, checked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckBox, unchecked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckBox, radio_checked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckBox, radio_unchecked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckBox, checked_disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckBox, unchecked_disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckBox, radio_checked_disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckBox, radio_unchecked_disabled);
+}
+
CheckBox::CheckBox(const String &p_text) :
Button(p_text) {
set_toggle_mode(true);
diff --git a/scene/gui/check_box.h b/scene/gui/check_box.h
index 69d753f469..8726181631 100644
--- a/scene/gui/check_box.h
+++ b/scene/gui/check_box.h
@@ -55,8 +55,8 @@ protected:
Size2 get_icon_size() const;
Size2 get_minimum_size() const override;
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
+ static void _bind_methods();
bool is_radio();
diff --git a/scene/gui/check_button.cpp b/scene/gui/check_button.cpp
index a1ab8eb129..d9fabc5459 100644
--- a/scene/gui/check_button.cpp
+++ b/scene/gui/check_button.cpp
@@ -30,7 +30,7 @@
#include "check_button.h"
-#include "core/string/print_string.h"
+#include "scene/theme/theme_db.h"
#include "servers/rendering_server.h"
Size2 CheckButton::get_icon_size() const {
@@ -78,23 +78,6 @@ Size2 CheckButton::get_minimum_size() const {
return minsize;
}
-void CheckButton::_update_theme_item_cache() {
- Button::_update_theme_item_cache();
-
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.check_v_offset = get_theme_constant(SNAME("check_v_offset"));
- theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
-
- theme_cache.checked = get_theme_icon(SNAME("checked"));
- theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
- theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
- theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
- theme_cache.checked_mirrored = get_theme_icon(SNAME("checked_mirrored"));
- theme_cache.unchecked_mirrored = get_theme_icon(SNAME("unchecked_mirrored"));
- theme_cache.checked_disabled_mirrored = get_theme_icon(SNAME("checked_disabled_mirrored"));
- theme_cache.unchecked_disabled_mirrored = get_theme_icon(SNAME("unchecked_disabled_mirrored"));
-}
-
void CheckButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED:
@@ -153,6 +136,21 @@ void CheckButton::_notification(int p_what) {
}
}
+void CheckButton::_bind_methods() {
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, CheckButton, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, CheckButton, check_v_offset);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, CheckButton, normal_style, "normal");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckButton, checked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckButton, unchecked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckButton, checked_disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckButton, unchecked_disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckButton, checked_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckButton, unchecked_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckButton, checked_disabled_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CheckButton, unchecked_disabled_mirrored);
+}
+
CheckButton::CheckButton(const String &p_text) :
Button(p_text) {
set_toggle_mode(true);
diff --git a/scene/gui/check_button.h b/scene/gui/check_button.h
index 5797686efb..84f77b2e83 100644
--- a/scene/gui/check_button.h
+++ b/scene/gui/check_button.h
@@ -55,8 +55,8 @@ protected:
Size2 get_icon_size() const;
virtual Size2 get_minimum_size() const override;
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
+ static void _bind_methods();
public:
CheckButton(const String &p_text = String());
diff --git a/scene/gui/code_edit.cpp b/scene/gui/code_edit.cpp
index 443a639ff2..d35d35d36d 100644
--- a/scene/gui/code_edit.cpp
+++ b/scene/gui/code_edit.cpp
@@ -34,6 +34,7 @@
#include "core/os/keyboard.h"
#include "core/string/string_builder.h"
#include "core/string/ustring.h"
+#include "scene/theme/theme_db.h"
void CodeEdit::_notification(int p_what) {
switch (p_what) {
@@ -228,55 +229,6 @@ void CodeEdit::_notification(int p_what) {
}
}
-void CodeEdit::_update_theme_item_cache() {
- TextEdit::_update_theme_item_cache();
-
- /* Gutters */
- theme_cache.code_folding_color = get_theme_color(SNAME("code_folding_color"));
- theme_cache.can_fold_icon = get_theme_icon(SNAME("can_fold"));
- theme_cache.folded_icon = get_theme_icon(SNAME("folded"));
- theme_cache.folded_eol_icon = get_theme_icon(SNAME("folded_eol_icon"));
-
- theme_cache.breakpoint_color = get_theme_color(SNAME("breakpoint_color"));
- theme_cache.breakpoint_icon = get_theme_icon(SNAME("breakpoint"));
-
- theme_cache.bookmark_color = get_theme_color(SNAME("bookmark_color"));
- theme_cache.bookmark_icon = get_theme_icon(SNAME("bookmark"));
-
- theme_cache.executing_line_color = get_theme_color(SNAME("executing_line_color"));
- theme_cache.executing_line_icon = get_theme_icon(SNAME("executing_line"));
-
- theme_cache.line_number_color = get_theme_color(SNAME("line_number_color"));
-
- /* Code Completion */
- theme_cache.code_completion_style = get_theme_stylebox(SNAME("completion"));
- theme_cache.code_completion_icon_separation = get_theme_constant(SNAME("h_separation"), SNAME("ItemList"));
-
- theme_cache.code_completion_max_width = get_theme_constant(SNAME("completion_max_width"));
- theme_cache.code_completion_max_lines = get_theme_constant(SNAME("completion_lines"));
- theme_cache.code_completion_scroll_width = get_theme_constant(SNAME("completion_scroll_width"));
- theme_cache.code_completion_scroll_color = get_theme_color(SNAME("completion_scroll_color"));
- theme_cache.code_completion_scroll_hovered_color = get_theme_color(SNAME("completion_scroll_hovered_color"));
- theme_cache.code_completion_background_color = get_theme_color(SNAME("completion_background_color"));
- theme_cache.code_completion_selected_color = get_theme_color(SNAME("completion_selected_color"));
- theme_cache.code_completion_existing_color = get_theme_color(SNAME("completion_existing_color"));
-
- /* Code hint */
- theme_cache.code_hint_style = get_theme_stylebox(SNAME("panel"), SNAME("TooltipPanel"));
- theme_cache.code_hint_color = get_theme_color(SNAME("font_color"), SNAME("TooltipLabel"));
-
- /* Line length guideline */
- theme_cache.line_length_guideline_color = get_theme_color(SNAME("line_length_guideline_color"));
-
- /* Other visuals */
- theme_cache.style_normal = get_theme_stylebox(SNAME("normal"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
-
- theme_cache.line_spacing = get_theme_constant(SNAME("line_spacing"));
-}
-
void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
Ref<InputEventMouseButton> mb = p_gui_input;
if (mb.is_valid()) {
@@ -481,7 +433,7 @@ void CodeEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
// Allow unicode handling if:
// No modifiers are pressed (except Shift and CapsLock)
- bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
+ bool allow_unicode_handling = !(k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
/* AUTO-COMPLETE */
if (code_completion_enabled && k->is_action("ui_text_completion_query", true)) {
@@ -1571,7 +1523,19 @@ void CodeEdit::_fold_gutter_draw_callback(int p_line, int p_gutter, Rect2 p_regi
p_region.position += Point2(horizontal_padding, vertical_padding);
p_region.size -= Point2(horizontal_padding, vertical_padding) * 2;
- if (can_fold_line(p_line)) {
+ bool can_fold = can_fold_line(p_line);
+
+ if (is_line_code_region_start(p_line)) {
+ Color region_icon_color = theme_cache.folded_code_region_color;
+ region_icon_color.a = MAX(region_icon_color.a, 0.4f);
+ if (can_fold) {
+ theme_cache.can_fold_code_region_icon->draw_rect(get_canvas_item(), p_region, false, region_icon_color);
+ } else {
+ theme_cache.folded_code_region_icon->draw_rect(get_canvas_item(), p_region, false, region_icon_color);
+ }
+ return;
+ }
+ if (can_fold) {
theme_cache.can_fold_icon->draw_rect(get_canvas_item(), p_region, false, theme_cache.code_folding_color);
return;
}
@@ -1602,6 +1566,27 @@ bool CodeEdit::can_fold_line(int p_line) const {
return false;
}
+ // Check for code region.
+ if (is_line_code_region_end(p_line)) {
+ return false;
+ }
+ if (is_line_code_region_start(p_line)) {
+ int region_level = 0;
+ // Check if there is a valid end region tag.
+ for (int next_line = p_line + 1; next_line < get_line_count(); next_line++) {
+ if (is_line_code_region_end(next_line)) {
+ region_level -= 1;
+ if (region_level == -1) {
+ return true;
+ }
+ }
+ if (is_line_code_region_start(next_line)) {
+ region_level += 1;
+ }
+ }
+ return false;
+ }
+
/* Check for full multiline line or block strings / comments. */
int in_comment = is_in_comment(p_line);
int in_string = (in_comment == -1) ? is_in_string(p_line) : -1;
@@ -1610,13 +1595,13 @@ bool CodeEdit::can_fold_line(int p_line) const {
return false;
}
- int delimter_end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y;
+ int delimiter_end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y;
/* No end line, therefore we have a multiline region over the rest of the file. */
- if (delimter_end_line == -1) {
+ if (delimiter_end_line == -1) {
return true;
}
/* End line is the same therefore we have a block. */
- if (delimter_end_line == p_line) {
+ if (delimiter_end_line == p_line) {
/* Check we are the start of the block. */
if (p_line - 1 >= 0) {
if ((in_string != -1 && is_in_string(p_line - 1) != -1) || (in_comment != -1 && is_in_comment(p_line - 1) != -1)) {
@@ -1626,7 +1611,7 @@ bool CodeEdit::can_fold_line(int p_line) const {
/* Check it continues for at least one line. */
return ((in_string != -1 && is_in_string(p_line + 1) != -1) || (in_comment != -1 && is_in_comment(p_line + 1) != -1));
}
- return ((in_string != -1 && is_in_string(delimter_end_line) != -1) || (in_comment != -1 && is_in_comment(delimter_end_line) != -1));
+ return ((in_string != -1 && is_in_string(delimiter_end_line) != -1) || (in_comment != -1 && is_in_comment(delimiter_end_line) != -1));
}
/* Otherwise check indent levels. */
@@ -1650,31 +1635,51 @@ void CodeEdit::fold_line(int p_line) {
const int line_count = get_line_count() - 1;
int end_line = line_count;
- int in_comment = is_in_comment(p_line);
- int in_string = (in_comment == -1) ? is_in_string(p_line) : -1;
- if (in_string != -1 || in_comment != -1) {
- end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y;
- /* End line is the same therefore we have a block of single line delimiters. */
- if (end_line == p_line) {
- for (int i = p_line + 1; i <= line_count; i++) {
- if ((in_string != -1 && is_in_string(i) == -1) || (in_comment != -1 && is_in_comment(i) == -1)) {
+ // Fold code region.
+ if (is_line_code_region_start(p_line)) {
+ int region_level = 0;
+ for (int endregion_line = p_line + 1; endregion_line < get_line_count(); endregion_line++) {
+ if (is_line_code_region_start(endregion_line)) {
+ region_level += 1;
+ }
+ if (is_line_code_region_end(endregion_line)) {
+ region_level -= 1;
+ if (region_level == -1) {
+ end_line = endregion_line;
break;
}
- end_line = i;
}
}
- } else {
- int start_indent = get_indent_level(p_line);
- for (int i = p_line + 1; i <= line_count; i++) {
- if (get_line(i).strip_edges().size() == 0) {
- continue;
- }
- if (get_indent_level(i) > start_indent) {
- end_line = i;
- continue;
+ set_line_background_color(p_line, theme_cache.folded_code_region_color);
+ }
+
+ int in_comment = is_in_comment(p_line);
+ int in_string = (in_comment == -1) ? is_in_string(p_line) : -1;
+ if (!is_line_code_region_start(p_line)) {
+ if (in_string != -1 || in_comment != -1) {
+ end_line = get_delimiter_end_position(p_line, get_line(p_line).size() - 1).y;
+ // End line is the same therefore we have a block of single line delimiters.
+ if (end_line == p_line) {
+ for (int i = p_line + 1; i <= line_count; i++) {
+ if ((in_string != -1 && is_in_string(i) == -1) || (in_comment != -1 && is_in_comment(i) == -1)) {
+ break;
+ }
+ end_line = i;
+ }
}
- if (is_in_string(i) == -1 && is_in_comment(i) == -1) {
- break;
+ } else {
+ int start_indent = get_indent_level(p_line);
+ for (int i = p_line + 1; i <= line_count; i++) {
+ if (get_line(i).strip_edges().size() == 0) {
+ continue;
+ }
+ if (get_indent_level(i) > start_indent) {
+ end_line = i;
+ continue;
+ }
+ if (is_in_string(i) == -1 && is_in_comment(i) == -1) {
+ break;
+ }
}
}
}
@@ -1725,6 +1730,9 @@ void CodeEdit::unfold_line(int p_line) {
break;
}
_set_line_as_hidden(i, false);
+ if (is_line_code_region_start(i - 1)) {
+ set_line_background_color(i - 1, Color(0.0, 0.0, 0.0, 0.0));
+ }
}
queue_redraw();
}
@@ -1764,6 +1772,95 @@ TypedArray<int> CodeEdit::get_folded_lines() const {
return folded_lines;
}
+/* Code region */
+void CodeEdit::create_code_region() {
+ // Abort if there is no selected text.
+ if (!has_selection()) {
+ return;
+ }
+ // Check that region tag find a comment delimiter and is valid.
+ if (code_region_start_string.is_empty()) {
+ WARN_PRINT_ONCE("Cannot create code region without any one line comment delimiters");
+ return;
+ }
+ begin_complex_operation();
+ // Merge selections if selection starts on the same line the previous one ends.
+ Vector<int> caret_edit_order = get_caret_index_edit_order();
+ Vector<int> carets_to_remove;
+ for (int i = 1; i < caret_edit_order.size(); i++) {
+ int current_caret = caret_edit_order[i - 1];
+ int next_caret = caret_edit_order[i];
+ if (get_selection_from_line(current_caret) == get_selection_to_line(next_caret)) {
+ select(get_selection_from_line(next_caret), get_selection_from_column(next_caret), get_selection_to_line(current_caret), get_selection_to_column(current_caret), next_caret);
+ carets_to_remove.append(current_caret);
+ }
+ }
+ // Sort and remove backwards to preserve indices.
+ carets_to_remove.sort();
+ for (int i = carets_to_remove.size() - 1; i >= 0; i--) {
+ remove_caret(carets_to_remove[i]);
+ }
+
+ // Adding start and end region tags.
+ int first_region_start = -1;
+ for (int caret_idx : get_caret_index_edit_order()) {
+ if (!has_selection(caret_idx)) {
+ continue;
+ }
+ int from_line = get_selection_from_line(caret_idx);
+ if (first_region_start == -1 || from_line < first_region_start) {
+ first_region_start = from_line;
+ }
+ int to_line = get_selection_to_line(caret_idx);
+ set_line(to_line, get_line(to_line) + "\n" + code_region_end_string);
+ insert_line_at(from_line, code_region_start_string + " " + RTR("New Code Region"));
+ fold_line(from_line);
+ }
+
+ // Select name of the first region to allow quick edit.
+ remove_secondary_carets();
+ set_caret_line(first_region_start);
+ int tag_length = code_region_start_string.length() + RTR("New Code Region").length() + 1;
+ set_caret_column(tag_length);
+ select(first_region_start, code_region_start_string.length() + 1, first_region_start, tag_length);
+
+ end_complex_operation();
+ queue_redraw();
+}
+
+String CodeEdit::get_code_region_start_tag() const {
+ return code_region_start_tag;
+}
+
+String CodeEdit::get_code_region_end_tag() const {
+ return code_region_end_tag;
+}
+
+void CodeEdit::set_code_region_tags(const String &p_start, const String &p_end) {
+ ERR_FAIL_COND_MSG(p_start == p_end, "Starting and ending region tags cannot be identical.");
+ ERR_FAIL_COND_MSG(p_start.is_empty(), "Starting region tag cannot be empty.");
+ ERR_FAIL_COND_MSG(p_end.is_empty(), "Ending region tag cannot be empty.");
+ code_region_start_tag = p_start;
+ code_region_end_tag = p_end;
+ _update_code_region_tags();
+}
+
+bool CodeEdit::is_line_code_region_start(int p_line) const {
+ ERR_FAIL_INDEX_V(p_line, get_line_count(), false);
+ if (code_region_start_string.is_empty()) {
+ return false;
+ }
+ return get_line(p_line).strip_edges().begins_with(code_region_start_string);
+}
+
+bool CodeEdit::is_line_code_region_end(int p_line) const {
+ ERR_FAIL_INDEX_V(p_line, get_line_count(), false);
+ if (code_region_start_string.is_empty()) {
+ return false;
+ }
+ return get_line(p_line).strip_edges().begins_with(code_region_end_string);
+}
+
/* Delimiters */
// Strings
void CodeEdit::add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only) {
@@ -2302,6 +2399,19 @@ void CodeEdit::set_symbol_lookup_word_as_valid(bool p_valid) {
}
}
+/* Visual */
+Color CodeEdit::_get_brace_mismatch_color() const {
+ return theme_cache.brace_mismatch_color;
+}
+
+Color CodeEdit::_get_code_folding_color() const {
+ return theme_cache.code_folding_color;
+}
+
+Ref<Texture2D> CodeEdit::_get_folded_eol_icon() const {
+ return theme_cache.folded_eol_icon;
+}
+
void CodeEdit::_bind_methods() {
/* Indent management */
ClassDB::bind_method(D_METHOD("set_indent_size", "size"), &CodeEdit::set_indent_size);
@@ -2392,6 +2502,14 @@ void CodeEdit::_bind_methods() {
ClassDB::bind_method(D_METHOD("is_line_folded", "line"), &CodeEdit::is_line_folded);
ClassDB::bind_method(D_METHOD("get_folded_lines"), &CodeEdit::get_folded_lines);
+ /* Code region */
+ ClassDB::bind_method(D_METHOD("create_code_region"), &CodeEdit::create_code_region);
+ ClassDB::bind_method(D_METHOD("get_code_region_start_tag"), &CodeEdit::get_code_region_start_tag);
+ ClassDB::bind_method(D_METHOD("get_code_region_end_tag"), &CodeEdit::get_code_region_end_tag);
+ ClassDB::bind_method(D_METHOD("set_code_region_tags", "start", "end"), &CodeEdit::set_code_region_tags, DEFVAL("region"), DEFVAL("endregion"));
+ ClassDB::bind_method(D_METHOD("is_line_code_region_start", "line"), &CodeEdit::is_line_code_region_start);
+ ClassDB::bind_method(D_METHOD("is_line_code_region_end", "line"), &CodeEdit::is_line_code_region_end);
+
/* Delimiters */
// Strings
ClassDB::bind_method(D_METHOD("add_string_delimiter", "start_key", "end_key", "line_only"), &CodeEdit::add_string_delimiter, DEFVAL(false));
@@ -2527,6 +2645,57 @@ void CodeEdit::_bind_methods() {
/* Symbol lookup */
ADD_SIGNAL(MethodInfo("symbol_lookup", PropertyInfo(Variant::STRING, "symbol"), PropertyInfo(Variant::INT, "line"), PropertyInfo(Variant::INT, "column")));
ADD_SIGNAL(MethodInfo("symbol_validate", PropertyInfo(Variant::STRING, "symbol")));
+
+ /* Theme items */
+ /* Gutters */
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, code_folding_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, folded_code_region_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, can_fold_icon, "can_fold");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, folded_icon, "folded");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, can_fold_code_region_icon, "can_fold_code_region");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, folded_code_region_icon, "folded_code_region");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, CodeEdit, folded_eol_icon);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, breakpoint_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, breakpoint_icon, "breakpoint");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, bookmark_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, bookmark_icon, "bookmark");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, executing_line_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, CodeEdit, executing_line_icon, "executing_line");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, line_number_color);
+
+ /* Code Completion */
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, CodeEdit, code_completion_style, "completion");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_CONSTANT, CodeEdit, code_completion_icon_separation, "h_separation", "ItemList");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, CodeEdit, code_completion_max_width, "completion_max_width");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, CodeEdit, code_completion_max_lines, "completion_lines");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, CodeEdit, code_completion_scroll_width, "completion_scroll_width");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_COLOR, CodeEdit, code_completion_scroll_color, "completion_scroll_color");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_COLOR, CodeEdit, code_completion_scroll_hovered_color, "completion_scroll_hovered_color");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_COLOR, CodeEdit, code_completion_background_color, "completion_background_color");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_COLOR, CodeEdit, code_completion_selected_color, "completion_selected_color");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_COLOR, CodeEdit, code_completion_existing_color, "completion_existing_color");
+
+ /* Code hint */
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, CodeEdit, code_hint_style, "panel", "TooltipPanel");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, CodeEdit, code_hint_color, "font_color", "TooltipLabel");
+
+ /* Line length guideline */
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, line_length_guideline_color);
+
+ /* Other visuals */
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, CodeEdit, style_normal, "normal");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, CodeEdit, brace_mismatch_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, CodeEdit, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, CodeEdit, font_size);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, CodeEdit, line_spacing);
}
/* Auto brace completion */
@@ -2630,6 +2799,27 @@ void CodeEdit::_update_gutter_indexes() {
}
}
+/* Code Region */
+void CodeEdit::_update_code_region_tags() {
+ code_region_start_string = "";
+ code_region_end_string = "";
+
+ if (code_region_start_tag.is_empty() || code_region_end_tag.is_empty()) {
+ return;
+ }
+
+ for (int i = 0; i < delimiters.size(); i++) {
+ if (delimiters[i].type != DelimiterType::TYPE_COMMENT) {
+ continue;
+ }
+ if (delimiters[i].end_key.is_empty() && delimiters[i].line_only == true) {
+ code_region_start_string = delimiters[i].start_key + code_region_start_tag;
+ code_region_end_string = delimiters[i].start_key + code_region_end_tag;
+ return;
+ }
+ }
+}
+
/* Delimiters */
void CodeEdit::_update_delimiter_cache(int p_from_line, int p_to_line) {
if (delimiters.size() == 0) {
@@ -2873,6 +3063,9 @@ void CodeEdit::_add_delimiter(const String &p_start_key, const String &p_end_key
delimiter_cache.clear();
_update_delimiter_cache();
}
+ if (p_type == DelimiterType::TYPE_COMMENT) {
+ _update_code_region_tags();
+ }
}
void CodeEdit::_remove_delimiter(const String &p_start_key, DelimiterType p_type) {
@@ -2890,6 +3083,9 @@ void CodeEdit::_remove_delimiter(const String &p_start_key, DelimiterType p_type
delimiter_cache.clear();
_update_delimiter_cache();
}
+ if (p_type == DelimiterType::TYPE_COMMENT) {
+ _update_code_region_tags();
+ }
break;
}
}
@@ -2933,6 +3129,9 @@ void CodeEdit::_clear_delimiters(DelimiterType p_type) {
if (!setting_delimiters) {
_update_delimiter_cache();
}
+ if (p_type == DelimiterType::TYPE_COMMENT) {
+ _update_code_region_tags();
+ }
}
TypedArray<String> CodeEdit::_get_delimiters(DelimiterType p_type) const {
diff --git a/scene/gui/code_edit.h b/scene/gui/code_edit.h
index 1bd4db9e2c..e688af2bda 100644
--- a/scene/gui/code_edit.h
+++ b/scene/gui/code_edit.h
@@ -125,6 +125,11 @@ private:
/* Line Folding */
bool line_folding_enabled = false;
+ String code_region_start_string;
+ String code_region_end_string;
+ String code_region_start_tag = "region";
+ String code_region_end_tag = "endregion";
+ void _update_code_region_tags();
/* Delimiters */
enum DelimiterType {
@@ -232,8 +237,11 @@ private:
struct ThemeCache {
/* Gutters */
Color code_folding_color = Color(1, 1, 1);
+ Color folded_code_region_color = Color(1, 1, 1);
Ref<Texture2D> can_fold_icon;
Ref<Texture2D> folded_icon;
+ Ref<Texture2D> can_fold_code_region_icon;
+ Ref<Texture2D> folded_code_region_icon;
Ref<Texture2D> folded_eol_icon;
Color breakpoint_color = Color(1, 1, 1);
@@ -270,11 +278,17 @@ private:
/* Other visuals */
Ref<StyleBox> style_normal;
+ Color brace_mismatch_color;
+
Ref<Font> font;
int font_size = 16;
int line_spacing = 1;
} theme_cache;
+ virtual Color _get_brace_mismatch_color() const override;
+ virtual Color _get_code_folding_color() const override;
+ virtual Ref<Texture2D> _get_folded_eol_icon() const override;
+
/* Callbacks */
int lines_edited_changed = 0;
int lines_edited_from = -1;
@@ -293,8 +307,6 @@ protected:
static void _bind_compatibility_methods();
#endif
- virtual void _update_theme_item_cache() override;
-
/* Text manipulation */
// Overridable actions
@@ -399,6 +411,14 @@ public:
bool is_line_folded(int p_line) const;
TypedArray<int> get_folded_lines() const;
+ /* Code region */
+ void create_code_region();
+ String get_code_region_start_tag() const;
+ String get_code_region_end_tag() const;
+ void set_code_region_tags(const String &p_start = "region", const String &p_end = "endregion");
+ bool is_line_code_region_start(int p_line) const;
+ bool is_line_code_region_end(int p_line) const;
+
/* Delimiters */
void add_string_delimiter(const String &p_start_key, const String &p_end_key, bool p_line_only = false);
void remove_string_delimiter(const String &p_start_key);
diff --git a/scene/gui/color_mode.cpp b/scene/gui/color_mode.cpp
index adea06eee7..7d068a101e 100644
--- a/scene/gui/color_mode.cpp
+++ b/scene/gui/color_mode.cpp
@@ -73,10 +73,10 @@ void ColorModeRGB::slider_draw(int p_which) {
Color left_color;
Color right_color;
Color color = color_picker->get_pick_color();
- const real_t margin = 16 * color_picker->get_theme_default_base_scale();
+ const real_t margin = 16 * color_picker->theme_cache.base_scale;
if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
+ slider->draw_texture_rect(color_picker->theme_cache.sample_bg, Rect2(Point2(0, 0), Size2(size.x, margin)), true);
left_color = color;
left_color.a = 0;
@@ -168,10 +168,10 @@ void ColorModeHSV::slider_draw(int p_which) {
Color left_color;
Color right_color;
Color color = color_picker->get_pick_color();
- const real_t margin = 16 * color_picker->get_theme_default_base_scale();
+ const real_t margin = 16 * color_picker->theme_cache.base_scale;
if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
+ slider->draw_texture_rect(color_picker->theme_cache.sample_bg, Rect2(Point2(0, 0), Size2(size.x, margin)), true);
left_color = color;
left_color.a = 0;
@@ -204,7 +204,7 @@ void ColorModeHSV::slider_draw(int p_which) {
slider->draw_polygon(pos, col);
if (p_which == 0) { // H
- Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_hue"), SNAME("ColorPicker"));
+ Ref<Texture2D> hue = color_picker->theme_cache.color_hue;
slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false, Color::from_hsv(0, 0, color.get_v(), color.get_s()));
}
}
@@ -243,10 +243,10 @@ void ColorModeRAW::slider_draw(int p_which) {
Color left_color;
Color right_color;
Color color = color_picker->get_pick_color();
- const real_t margin = 16 * color_picker->get_theme_default_base_scale();
+ const real_t margin = 16 * color_picker->theme_cache.base_scale;
if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
+ slider->draw_texture_rect(color_picker->theme_cache.sample_bg, Rect2(Point2(0, 0), Size2(size.x, margin)), true);
left_color = color;
left_color.a = 0;
@@ -334,7 +334,7 @@ Color ColorModeOKHSL::get_color() const {
void ColorModeOKHSL::slider_draw(int p_which) {
HSlider *slider = color_picker->get_slider(p_which);
Size2 size = slider->get_size();
- const real_t margin = 16 * color_picker->get_theme_default_base_scale();
+ const real_t margin = 16 * color_picker->theme_cache.base_scale;
Vector<Vector2> pos;
Vector<Color> col;
@@ -370,7 +370,7 @@ void ColorModeOKHSL::slider_draw(int p_which) {
col.resize(4);
if (p_which == ColorPicker::SLIDER_COUNT) {
- slider->draw_texture_rect(color_picker->get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker")), Rect2(Point2(0, 0), Size2(size.x, margin)), true);
+ slider->draw_texture_rect(color_picker->theme_cache.sample_bg, Rect2(Point2(0, 0), Size2(size.x, margin)), true);
left_color = color;
left_color.a = 0;
@@ -399,7 +399,7 @@ void ColorModeOKHSL::slider_draw(int p_which) {
slider->draw_polygon(pos, col);
if (p_which == 0) { // H
- Ref<Texture2D> hue = color_picker->get_theme_icon(SNAME("color_okhsl_hue"), SNAME("ColorPicker"));
+ Ref<Texture2D> hue = color_picker->theme_cache.color_okhsl_hue;
slider->draw_texture_rect(hue, Rect2(Vector2(), Vector2(size.x, margin)), false, Color::from_hsv(0, 0, color.get_ok_hsl_l() * 2.0, color.get_ok_hsl_s()));
return;
}
diff --git a/scene/gui/color_picker.cpp b/scene/gui/color_picker.cpp
index 2b4d5677c4..5ec0714b64 100644
--- a/scene/gui/color_picker.cpp
+++ b/scene/gui/color_picker.cpp
@@ -39,6 +39,7 @@
#include "scene/resources/image_texture.h"
#include "scene/resources/style_box_flat.h"
#include "scene/resources/style_box_texture.h"
+#include "scene/theme/theme_db.h"
#include "servers/display_server.h"
#include "thirdparty/misc/ok_color.h"
#include "thirdparty/misc/ok_color_shader.h"
@@ -122,34 +123,6 @@ void ColorPicker::_update_theme_item_cache() {
VBoxContainer::_update_theme_item_cache();
theme_cache.base_scale = get_theme_default_base_scale();
-
- theme_cache.content_margin = get_theme_constant(SNAME("margin"));
- theme_cache.label_width = get_theme_constant(SNAME("label_width"));
-
- theme_cache.sv_width = get_theme_constant(SNAME("sv_width"));
- theme_cache.sv_height = get_theme_constant(SNAME("sv_height"));
- theme_cache.h_width = get_theme_constant(SNAME("h_width"));
-
- theme_cache.center_slider_grabbers = get_theme_constant(SNAME("center_slider_grabbers"));
-
- theme_cache.screen_picker = get_theme_icon(SNAME("screen_picker"));
- theme_cache.expanded_arrow = get_theme_icon(SNAME("expanded_arrow"));
- theme_cache.folded_arrow = get_theme_icon(SNAME("folded_arrow"));
- theme_cache.add_preset = get_theme_icon(SNAME("add_preset"));
-
- theme_cache.shape_rect = get_theme_icon(SNAME("shape_rect"));
- theme_cache.shape_rect_wheel = get_theme_icon(SNAME("shape_rect_wheel"));
- theme_cache.shape_circle = get_theme_icon(SNAME("shape_circle"));
-
- theme_cache.bar_arrow = get_theme_icon(SNAME("bar_arrow"));
- theme_cache.sample_background_icon = get_theme_icon(SNAME("sample_bg"), SNAME("ColorPicker"));
- theme_cache.overbright_indicator = get_theme_icon(SNAME("overbright_indicator"), SNAME("ColorPicker"));
- theme_cache.picker_cursor = get_theme_icon(SNAME("picker_cursor"));
- theme_cache.color_hue_icon = get_theme_icon(SNAME("color_hue"));
-
- theme_cache.mode_button_normal = get_theme_stylebox("tab_unselected", "TabContainer");
- theme_cache.mode_button_pressed = get_theme_stylebox("tab_selected", "TabContainer");
- theme_cache.mode_button_hover = get_theme_stylebox("tab_selected", "TabContainer");
}
Ref<Shader> ColorPicker::wheel_shader;
@@ -700,7 +673,7 @@ ColorPicker::PickerShapeType ColorPicker::get_picker_shape() const {
}
inline int ColorPicker::_get_preset_size() {
- return (int(get_minimum_size().width) - (preset_container->get_theme_constant(SNAME("h_separation")) * (PRESET_COLUMN_COUNT - 1))) / PRESET_COLUMN_COUNT;
+ return (int(get_minimum_size().width) - (preset_container->get_h_separation() * (PRESET_COLUMN_COUNT - 1))) / PRESET_COLUMN_COUNT;
}
void ColorPicker::_add_preset_button(int p_size, const Color &p_color) {
@@ -1024,7 +997,7 @@ void ColorPicker::_sample_draw() {
const Rect2 rect_old = Rect2(Point2(), Size2(sample->get_size().width * 0.5, sample->get_size().height * 0.95));
if (old_color.a < 1.0) {
- sample->draw_texture_rect(theme_cache.sample_background_icon, rect_old, true);
+ sample->draw_texture_rect(theme_cache.sample_bg, rect_old, true);
}
sample->draw_rect(rect_old, old_color);
@@ -1038,7 +1011,7 @@ void ColorPicker::_sample_draw() {
}
if (color.a < 1.0) {
- sample->draw_texture_rect(theme_cache.sample_background_icon, rect_new, true);
+ sample->draw_texture_rect(theme_cache.sample_bg, rect_new, true);
}
sample->draw_rect(rect_new, color);
@@ -1152,7 +1125,7 @@ void ColorPicker::_hsv_draw(int p_which, Control *c) {
} else if (p_which == 1) {
if (actual_shape == SHAPE_HSV_RECTANGLE) {
c->draw_set_transform(Point2(), -Math_PI / 2, Size2(c->get_size().x, -c->get_size().y));
- c->draw_texture_rect(theme_cache.color_hue_icon, Rect2(Point2(), Size2(1, 1)));
+ c->draw_texture_rect(theme_cache.color_hue, Rect2(Point2(), Size2(1, 1)));
c->draw_set_transform(Point2(), 0, Size2(1, 1));
int y = c->get_size().y - c->get_size().y * (1.0 - h);
Color col;
@@ -1710,6 +1683,35 @@ void ColorPicker::_bind_methods() {
BIND_ENUM_CONSTANT(SHAPE_VHS_CIRCLE);
BIND_ENUM_CONSTANT(SHAPE_OKHSL_CIRCLE);
BIND_ENUM_CONSTANT(SHAPE_NONE);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, ColorPicker, content_margin, "margin");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, label_width);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, sv_width);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, sv_height);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, h_width);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ColorPicker, center_slider_grabbers);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, screen_picker);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, expanded_arrow);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, folded_arrow);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, add_preset);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, shape_rect);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, shape_rect_wheel);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, shape_circle);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, bar_arrow);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, sample_bg);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, overbright_indicator);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, picker_cursor);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, color_hue);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPicker, color_okhsl_hue);
+
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_normal, "tab_unselected", "TabContainer");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_pressed, "tab_selected", "TabContainer");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, ColorPicker, mode_button_hover, "tab_selected", "TabContainer");
}
ColorPicker::ColorPicker() {
@@ -2011,15 +2013,6 @@ void ColorPickerButton::_notification(int p_what) {
}
}
-void ColorPickerButton::_update_theme_item_cache() {
- Button::_update_theme_item_cache();
-
- theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
- theme_cache.background_icon = get_theme_icon(SNAME("bg"));
-
- theme_cache.overbright_indicator = get_theme_icon(SNAME("overbright_indicator"), SNAME("ColorPicker"));
-}
-
void ColorPickerButton::set_pick_color(const Color &p_color) {
if (color == p_color) {
return;
@@ -2093,6 +2086,10 @@ void ColorPickerButton::_bind_methods() {
ADD_SIGNAL(MethodInfo("picker_created"));
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");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ColorPickerButton, normal_style, "normal");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ColorPickerButton, background_icon, "bg");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_ICON, ColorPickerButton, overbright_indicator, "overbright_indicator", "ColorPicker");
}
ColorPickerButton::ColorPickerButton(const String &p_text) :
@@ -2153,15 +2150,6 @@ void ColorPresetButton::_notification(int p_what) {
}
}
-void ColorPresetButton::_update_theme_item_cache() {
- BaseButton::_update_theme_item_cache();
-
- theme_cache.foreground_style = get_theme_stylebox(SNAME("preset_fg"));
-
- theme_cache.background_icon = get_theme_icon(SNAME("preset_bg"));
- theme_cache.overbright_indicator = get_theme_icon(SNAME("overbright_indicator"));
-}
-
void ColorPresetButton::set_preset_color(const Color &p_color) {
preset_color = p_color;
}
@@ -2170,6 +2158,12 @@ Color ColorPresetButton::get_preset_color() const {
return preset_color;
}
+void ColorPresetButton::_bind_methods() {
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ColorPresetButton, foreground_style, "preset_fg");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ColorPresetButton, background_icon, "preset_bg");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, ColorPresetButton, overbright_indicator);
+}
+
ColorPresetButton::ColorPresetButton(Color p_color, int p_size) {
preset_color = p_color;
set_toggle_mode(true);
diff --git a/scene/gui/color_picker.h b/scene/gui/color_picker.h
index 680b3f7d96..96dbca9a0c 100644
--- a/scene/gui/color_picker.h
+++ b/scene/gui/color_picker.h
@@ -67,9 +67,8 @@ class ColorPresetButton : public BaseButton {
} theme_cache;
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int);
+ static void _bind_methods();
public:
void set_preset_color(const Color &p_color);
@@ -82,6 +81,12 @@ public:
class ColorPicker : public VBoxContainer {
GDCLASS(ColorPicker, VBoxContainer);
+ // These classes poke into theme items for their internal logic.
+ friend class ColorModeRGB;
+ friend class ColorModeHSV;
+ friend class ColorModeRAW;
+ friend class ColorModeOKHSL;
+
public:
enum ColorModeType {
MODE_RGB,
@@ -230,10 +235,11 @@ private:
Ref<Texture2D> shape_circle;
Ref<Texture2D> bar_arrow;
- Ref<Texture2D> sample_background_icon;
+ Ref<Texture2D> sample_bg;
Ref<Texture2D> overbright_indicator;
Ref<Texture2D> picker_cursor;
- Ref<Texture2D> color_hue_icon;
+ Ref<Texture2D> color_hue;
+ Ref<Texture2D> color_okhsl_hue;
/* Mode buttons */
Ref<StyleBox> mode_button_normal;
@@ -393,8 +399,6 @@ class ColorPickerButton : public Button {
void _update_picker();
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int);
static void _bind_methods();
diff --git a/scene/gui/control.cpp b/scene/gui/control.cpp
index d97ce65afc..4510de32a0 100644
--- a/scene/gui/control.cpp
+++ b/scene/gui/control.cpp
@@ -2448,6 +2448,7 @@ void Control::_invalidate_theme_cache() {
}
void Control::_update_theme_item_cache() {
+ ThemeDB::get_singleton()->update_class_instance_items(this);
}
void Control::set_theme_owner_node(Node *p_node) {
@@ -2669,6 +2670,27 @@ int Control::get_theme_constant(const StringName &p_name, const StringName &p_th
return constant;
}
+Variant Control::get_theme_item(Theme::DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const {
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ return get_theme_color(p_name, p_theme_type);
+ case Theme::DATA_TYPE_CONSTANT:
+ return get_theme_constant(p_name, p_theme_type);
+ case Theme::DATA_TYPE_FONT:
+ return get_theme_font(p_name, p_theme_type);
+ case Theme::DATA_TYPE_FONT_SIZE:
+ return get_theme_font_size(p_name, p_theme_type);
+ case Theme::DATA_TYPE_ICON:
+ return get_theme_icon(p_name, p_theme_type);
+ case Theme::DATA_TYPE_STYLEBOX:
+ return get_theme_stylebox(p_name, p_theme_type);
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Variant();
+}
+
#ifdef TOOLS_ENABLED
Ref<Texture2D> Control::get_editor_theme_icon(const StringName &p_name) const {
return get_theme_icon(p_name, SNAME("EditorIcons"));
diff --git a/scene/gui/control.h b/scene/gui/control.h
index bad78a66d3..e5ed076abf 100644
--- a/scene/gui/control.h
+++ b/scene/gui/control.h
@@ -585,6 +585,7 @@ public:
int get_theme_font_size(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
Color get_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
int get_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Variant get_theme_item(Theme::DataType p_data_type, const StringName &p_name, const StringName &p_theme_type = StringName()) const;
#ifdef TOOLS_ENABLED
Ref<Texture2D> get_editor_theme_icon(const StringName &p_name) const;
#endif
diff --git a/scene/gui/dialogs.cpp b/scene/gui/dialogs.cpp
index 6e75be268d..aff0ed6f06 100644
--- a/scene/gui/dialogs.cpp
+++ b/scene/gui/dialogs.cpp
@@ -34,6 +34,7 @@
#include "core/string/print_string.h"
#include "core/string/translation.h"
#include "scene/gui/line_edit.h"
+#include "scene/theme/theme_db.h"
// AcceptDialog
@@ -49,13 +50,6 @@ void AcceptDialog::_parent_focused() {
}
}
-void AcceptDialog::_update_theme_item_cache() {
- Window::_update_theme_item_cache();
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
- theme_cache.buttons_separation = get_theme_constant(SNAME("buttons_separation"));
-}
-
void AcceptDialog::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POST_ENTER_TREE: {
@@ -395,6 +389,9 @@ void AcceptDialog::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_hide_on_ok"), "set_hide_on_ok", "get_hide_on_ok");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_close_on_escape"), "set_close_on_escape", "get_close_on_escape");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "dialog_autowrap"), "set_autowrap", "has_autowrap");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, AcceptDialog, panel_style, "panel");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, AcceptDialog, buttons_separation);
}
bool AcceptDialog::swap_cancel_ok = false;
diff --git a/scene/gui/dialogs.h b/scene/gui/dialogs.h
index 109c7172d0..d5cbaaeef8 100644
--- a/scene/gui/dialogs.h
+++ b/scene/gui/dialogs.h
@@ -70,10 +70,10 @@ class AcceptDialog : public Window {
protected:
virtual Size2 _get_contents_minimum_size() const override;
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
+
virtual void ok_pressed() {}
virtual void cancel_pressed() {}
virtual void custom_action(const String &) {}
diff --git a/scene/gui/file_dialog.cpp b/scene/gui/file_dialog.cpp
index d4da4797eb..d27a40779e 100644
--- a/scene/gui/file_dialog.cpp
+++ b/scene/gui/file_dialog.cpp
@@ -33,6 +33,7 @@
#include "core/os/keyboard.h"
#include "core/string/print_string.h"
#include "scene/gui/label.h"
+#include "scene/theme/theme_db.h"
FileDialog::GetIconFunc FileDialog::get_icon_func = nullptr;
@@ -90,26 +91,11 @@ VBoxContainer *FileDialog::get_vbox() {
return vbox;
}
-void FileDialog::_update_theme_item_cache() {
- ConfirmationDialog::_update_theme_item_cache();
-
- theme_cache.parent_folder = get_theme_icon(SNAME("parent_folder"));
- theme_cache.forward_folder = get_theme_icon(SNAME("forward_folder"));
- theme_cache.back_folder = get_theme_icon(SNAME("back_folder"));
- theme_cache.reload = get_theme_icon(SNAME("reload"));
- theme_cache.toggle_hidden = get_theme_icon(SNAME("toggle_hidden"));
- theme_cache.folder = get_theme_icon(SNAME("folder"));
- theme_cache.file = get_theme_icon(SNAME("file"));
-
- theme_cache.folder_icon_color = get_theme_color(SNAME("folder_icon_color"));
- theme_cache.file_icon_color = get_theme_color(SNAME("file_icon_color"));
- theme_cache.file_disabled_color = get_theme_color(SNAME("file_disabled_color"));
-
- // TODO: Define own colors?
- theme_cache.icon_normal_color = get_theme_color(SNAME("font_color"), SNAME("Button"));
- theme_cache.icon_hover_color = get_theme_color(SNAME("font_hover_color"), SNAME("Button"));
- theme_cache.icon_focus_color = get_theme_color(SNAME("font_focus_color"), SNAME("Button"));
- theme_cache.icon_pressed_color = get_theme_color(SNAME("font_pressed_color"), SNAME("Button"));
+void FileDialog::_validate_property(PropertyInfo &p_property) const {
+ if (p_property.name == "dialog_text") {
+ // File dialogs have a custom layout, and dialog nodes can't have both a text and a layout.
+ p_property.usage = PROPERTY_USAGE_NONE;
+ }
}
void FileDialog::_notification(int p_what) {
@@ -1042,6 +1028,24 @@ void FileDialog::_bind_methods() {
BIND_ENUM_CONSTANT(ACCESS_RESOURCES);
BIND_ENUM_CONSTANT(ACCESS_USERDATA);
BIND_ENUM_CONSTANT(ACCESS_FILESYSTEM);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, parent_folder);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, forward_folder);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, back_folder);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, reload);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, toggle_hidden);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, folder);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, FileDialog, file);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, FileDialog, folder_icon_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, FileDialog, file_icon_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, FileDialog, file_disabled_color);
+
+ // TODO: Define own colors?
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, FileDialog, icon_normal_color, "font_color", "Button");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, FileDialog, icon_hover_color, "font_hover_color", "Button");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, FileDialog, icon_focus_color, "font_focus_color", "Button");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_COLOR, FileDialog, icon_pressed_color, "font_pressed_color", "Button");
}
void FileDialog::set_show_hidden_files(bool p_show) {
diff --git a/scene/gui/file_dialog.h b/scene/gui/file_dialog.h
index dece241ca9..739cb3e31a 100644
--- a/scene/gui/file_dialog.h
+++ b/scene/gui/file_dialog.h
@@ -166,11 +166,10 @@ private:
virtual void _post_popup() override;
protected:
- virtual void _update_theme_item_cache() override;
-
+ void _validate_property(PropertyInfo &p_property) const;
void _notification(int p_what);
static void _bind_methods();
- //bind helpers
+
public:
virtual void popup(const Rect2i &p_rect = Rect2i()) override;
diff --git a/scene/gui/flow_container.cpp b/scene/gui/flow_container.cpp
index 12ce6e17cb..5b5f8e5f2d 100644
--- a/scene/gui/flow_container.cpp
+++ b/scene/gui/flow_container.cpp
@@ -30,6 +30,8 @@
#include "flow_container.h"
+#include "scene/theme/theme_db.h"
+
struct _LineData {
int child_count = 0;
int min_line_height = 0;
@@ -269,13 +271,6 @@ Vector<int> FlowContainer::get_allowed_size_flags_vertical() const {
return flags;
}
-void FlowContainer::_update_theme_item_cache() {
- Container::_update_theme_item_cache();
-
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
-}
-
void FlowContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
@@ -345,4 +340,7 @@ void FlowContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "alignment", PROPERTY_HINT_ENUM, "Begin,Center,End"), "set_alignment", "get_alignment");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "vertical"), "set_vertical", "is_vertical");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, FlowContainer, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, FlowContainer, v_separation);
}
diff --git a/scene/gui/flow_container.h b/scene/gui/flow_container.h
index 4535601fc3..1c06c82815 100644
--- a/scene/gui/flow_container.h
+++ b/scene/gui/flow_container.h
@@ -60,8 +60,6 @@ private:
protected:
bool is_fixed = false;
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/scene/gui/graph_edit.cpp b/scene/gui/graph_edit.cpp
index be0ae45e7e..e37a3671f3 100644
--- a/scene/gui/graph_edit.cpp
+++ b/scene/gui/graph_edit.cpp
@@ -38,6 +38,7 @@
#include "scene/gui/graph_edit_arranger.h"
#include "scene/gui/view_panner.h"
#include "scene/resources/style_box_flat.h"
+#include "scene/theme/theme_db.h"
constexpr int MINIMAP_OFFSET = 12;
constexpr int MINIMAP_PADDING = 5;
@@ -56,23 +57,8 @@ GraphEditFilter::GraphEditFilter(GraphEdit *p_edit) {
ge = p_edit;
}
-GraphEditMinimap::GraphEditMinimap(GraphEdit *p_edit) {
- ge = p_edit;
-
- graph_proportions = Vector2(1, 1);
- graph_padding = Vector2(0, 0);
- camera_position = Vector2(100, 50);
- camera_size = Vector2(200, 200);
- minimap_padding = Vector2(MINIMAP_PADDING, MINIMAP_PADDING);
- minimap_offset = minimap_padding + _convert_from_graph_position(graph_padding);
-
- is_pressing = false;
- is_resizing = false;
-}
-
Control::CursorShape GraphEditMinimap::get_cursor_shape(const Point2 &p_pos) const {
- Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
- if (is_resizing || (p_pos.x < resizer->get_width() && p_pos.y < resizer->get_height())) {
+ if (is_resizing || (p_pos.x < theme_cache.resizer->get_width() && p_pos.y < theme_cache.resizer->get_height())) {
return CURSOR_FDIAGSIZE;
}
@@ -172,8 +158,7 @@ void GraphEditMinimap::gui_input(const Ref<InputEvent> &p_ev) {
if (mb->is_pressed()) {
is_pressing = true;
- Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
- Rect2 resizer_hitbox = Rect2(Point2(), resizer->get_size());
+ Rect2 resizer_hitbox = Rect2(Point2(), theme_cache.resizer->get_size());
if (resizer_hitbox.has_point(mb->get_position())) {
is_resizing = true;
} else {
@@ -207,6 +192,21 @@ void GraphEditMinimap::_adjust_graph_scroll(const Vector2 &p_offset) {
ge->set_scroll_offset(p_offset + graph_offset - camera_size / 2);
}
+void GraphEditMinimap::_bind_methods() {
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphEditMinimap, panel);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, GraphEditMinimap, node_style, "node");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, GraphEditMinimap, camera_style, "camera");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphEditMinimap, resizer);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, GraphEditMinimap, resizer_color);
+}
+
+GraphEditMinimap::GraphEditMinimap(GraphEdit *p_edit) {
+ ge = p_edit;
+
+ minimap_padding = Vector2(MINIMAP_PADDING, MINIMAP_PADDING);
+ minimap_offset = minimap_padding + _convert_from_graph_position(graph_padding);
+}
+
Control::CursorShape GraphEdit::get_cursor_shape(const Point2 &p_pos) const {
if (moving_selection) {
return CURSOR_MOVE;
@@ -493,22 +493,25 @@ void GraphEdit::remove_child_notify(Node *p_child) {
}
}
+void GraphEdit::_update_theme_item_cache() {
+ Control::_update_theme_item_cache();
+
+ theme_cache.base_scale = get_theme_default_base_scale();
+}
+
void GraphEdit::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_THEME_CHANGED: {
- port_hotzone_inner_extent = get_theme_constant("port_hotzone_inner_extent");
- port_hotzone_outer_extent = get_theme_constant("port_hotzone_outer_extent");
-
- zoom_minus_button->set_icon(get_theme_icon(SNAME("zoom_out")));
- zoom_reset_button->set_icon(get_theme_icon(SNAME("zoom_reset")));
- zoom_plus_button->set_icon(get_theme_icon(SNAME("zoom_in")));
+ zoom_minus_button->set_icon(theme_cache.zoom_out);
+ zoom_reset_button->set_icon(theme_cache.zoom_reset);
+ zoom_plus_button->set_icon(theme_cache.zoom_in);
- toggle_snapping_button->set_icon(get_theme_icon(SNAME("snapping_toggle")));
- show_grid_button->set_icon(get_theme_icon(SNAME("grid_toggle")));
- minimap_button->set_icon(get_theme_icon(SNAME("minimap_toggle")));
- layout_button->set_icon(get_theme_icon(SNAME("layout")));
+ toggle_snapping_button->set_icon(theme_cache.snapping_toggle);
+ show_grid_button->set_icon(theme_cache.grid_toggle);
+ minimap_button->set_icon(theme_cache.minimap_toggle);
+ layout_button->set_icon(theme_cache.layout);
- zoom_label->set_custom_minimum_size(Size2(48, 0) * get_theme_default_base_scale());
+ zoom_label->set_custom_minimum_size(Size2(48, 0) * theme_cache.base_scale);
} break;
case NOTIFICATION_READY: {
@@ -528,7 +531,7 @@ void GraphEdit::_notification(int p_what) {
case NOTIFICATION_DRAW: {
// Draw background fill.
- draw_style_box(get_theme_stylebox(SNAME("panel")), Rect2(Point2(), get_size()));
+ draw_style_box(theme_cache.panel, Rect2(Point2(), get_size()));
// Draw background grid.
if (show_grid) {
@@ -538,16 +541,13 @@ void GraphEdit::_notification(int p_what) {
Point2i from_pos = (offset / float(snapping_distance)).floor();
Point2i len = (size / float(snapping_distance)).floor() + Vector2(1, 1);
- Color grid_minor = get_theme_color(SNAME("grid_minor"));
- Color grid_major = get_theme_color(SNAME("grid_major"));
-
for (int i = from_pos.x; i < from_pos.x + len.x; i++) {
Color color;
if (ABS(i) % GRID_MINOR_STEPS_PER_MAJOR_LINE == 0) {
- color = grid_major;
+ color = theme_cache.grid_major;
} else {
- color = grid_minor;
+ color = theme_cache.grid_minor;
}
float base_offset = i * snapping_distance * zoom - offset.x * zoom;
@@ -558,9 +558,9 @@ void GraphEdit::_notification(int p_what) {
Color color;
if (ABS(i) % GRID_MINOR_STEPS_PER_MAJOR_LINE == 0) {
- color = grid_major;
+ color = theme_cache.grid_major;
} else {
- color = grid_minor;
+ color = theme_cache.grid_minor;
}
float base_offset = i * snapping_distance * zoom - offset.y * zoom;
@@ -578,14 +578,14 @@ void GraphEdit::_notification(int p_what) {
}
bool GraphEdit::_filter_input(const Point2 &p_point) {
- Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
-
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
if (!graph_node || !graph_node->is_visible_in_tree()) {
continue;
}
+ Ref<Texture2D> port_icon = graph_node->theme_cache.port;
+
for (int j = 0; j < graph_node->get_input_port_count(); j++) {
Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
@@ -620,8 +620,6 @@ bool GraphEdit::_filter_input(const Point2 &p_point) {
void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
Ref<InputEventMouseButton> mb = p_ev;
if (mb.is_valid() && mb->get_button_index() == MouseButton::LEFT && mb->is_pressed()) {
- Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
-
connecting_valid = false;
click_pos = mb->get_position() / zoom;
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -630,6 +628,8 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
continue;
}
+ Ref<Texture2D> port_icon = graph_node->theme_cache.port;
+
for (int j = 0; j < graph_node->get_output_port_count(); j++) {
Vector2 pos = graph_node->get_output_port_position(j) * zoom + graph_node->get_position();
Vector2i port_size = Vector2i(port_icon->get_width(), port_icon->get_height());
@@ -756,12 +756,13 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
if (connecting_valid) {
Vector2 mpos = mm->get_position() / zoom;
for (int i = get_child_count() - 1; i >= 0; i--) {
- Ref<Texture2D> port_icon = get_theme_icon(SNAME("port"), SNAME("GraphNode"));
GraphNode *graph_node = Object::cast_to<GraphNode>(get_child(i));
if (!graph_node || !graph_node->is_visible_in_tree()) {
continue;
}
+ Ref<Texture2D> port_icon = graph_node->theme_cache.port;
+
if (!connecting_out) {
for (int j = 0; j < graph_node->get_output_port_count(); j++) {
Vector2 pos = graph_node->get_output_port_position(j) * zoom + graph_node->get_position();
@@ -774,7 +775,7 @@ void GraphEdit::_top_layer_input(const Ref<InputEvent> &p_ev) {
int type = graph_node->get_output_port_type(j);
if ((type == connecting_type ||
- valid_connection_types.has(ConnectionType(connecting_type, type))) &&
+ valid_connection_types.has(ConnectionType(type, connecting_type))) &&
is_in_output_hotzone(graph_node, j, mpos, port_size)) {
if (!is_node_hover_valid(graph_node->get_name(), j, connecting_from, connecting_index)) {
continue;
@@ -877,7 +878,7 @@ bool GraphEdit::is_in_input_hotzone(GraphNode *p_graph_node, int p_port_idx, con
bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_port_idx, const Vector2 &p_mouse_pos, const Vector2i &p_port_size) {
if (p_graph_node->is_resizable()) {
- Ref<Texture2D> resizer = p_graph_node->get_theme_icon(SNAME("resizer"));
+ Ref<Texture2D> resizer = p_graph_node->theme_cache.resizer;
Rect2 resizer_rect = Rect2(p_graph_node->get_position() / zoom + p_graph_node->get_size() - resizer->get_size(), resizer->get_size());
if (resizer_rect.has_point(p_mouse_pos)) {
return false;
@@ -895,9 +896,9 @@ bool GraphEdit::is_in_output_hotzone(GraphNode *p_graph_node, int p_port_idx, co
bool GraphEdit::is_in_port_hotzone(const Vector2 &p_pos, const Vector2 &p_mouse_pos, const Vector2i &p_port_size, bool p_left) {
Rect2 hotzone = Rect2(
- p_pos.x - (p_left ? port_hotzone_outer_extent : port_hotzone_inner_extent),
+ p_pos.x - (p_left ? theme_cache.port_hotzone_outer_extent : theme_cache.port_hotzone_inner_extent),
p_pos.y - p_port_size.height / 2.0,
- port_hotzone_inner_extent + port_hotzone_outer_extent,
+ theme_cache.port_hotzone_inner_extent + theme_cache.port_hotzone_outer_extent,
p_port_size.height);
if (!hotzone.has_point(p_mouse_pos)) {
@@ -965,12 +966,10 @@ void GraphEdit::_draw_connection_line(CanvasItem *p_where, const Vector2 &p_from
}
// Thickness below 0.5 doesn't look good on the graph or its minimap.
- p_where->draw_polyline_colors(scaled_points, colors, MAX(0.5, Math::floor(p_width * get_theme_default_base_scale())), lines_antialiased);
+ p_where->draw_polyline_colors(scaled_points, colors, MAX(0.5, Math::floor(p_width * theme_cache.base_scale)), lines_antialiased);
}
void GraphEdit::_connections_layer_draw() {
- Color activity_color = get_theme_color(SNAME("activity"));
-
// Draw connections.
List<List<Connection>::Element *> to_erase;
for (List<Connection>::Element *E = connections.front(); E; E = E->next()) {
@@ -998,8 +997,8 @@ void GraphEdit::_connections_layer_draw() {
Color tocolor = gnode_to->get_input_port_color(c.to_port);
if (c.activity > 0) {
- color = color.lerp(activity_color, c.activity);
- tocolor = tocolor.lerp(activity_color, c.activity);
+ color = color.lerp(theme_cache.activity_color, c.activity);
+ tocolor = tocolor.lerp(theme_cache.activity_color, c.activity);
}
_draw_connection_line(connections_layer, frompos, topos, color, tocolor, lines_thickness, zoom);
}
@@ -1042,8 +1041,8 @@ void GraphEdit::_top_layer_draw() {
}
if (box_selecting) {
- top_layer->draw_rect(box_selecting_rect, get_theme_color(SNAME("selection_fill")));
- top_layer->draw_rect(box_selecting_rect, get_theme_color(SNAME("selection_stroke")), false);
+ top_layer->draw_rect(box_selecting_rect, theme_cache.selection_fill);
+ top_layer->draw_rect(box_selecting_rect, theme_cache.selection_stroke, false);
}
}
@@ -1056,7 +1055,7 @@ void GraphEdit::_minimap_draw() {
// Draw the minimap background.
Rect2 minimap_rect = Rect2(Point2(), minimap->get_size());
- minimap->draw_style_box(minimap->get_theme_stylebox(SNAME("panel")), minimap_rect);
+ minimap->draw_style_box(minimap->theme_cache.panel, minimap_rect);
Vector2 graph_offset = minimap->_get_graph_offset();
Vector2 minimap_offset = minimap->minimap_offset;
@@ -1072,10 +1071,10 @@ void GraphEdit::_minimap_draw() {
Vector2 node_size = minimap->_convert_from_graph_position(graph_node->get_size() * zoom);
Rect2 node_rect = Rect2(node_position, node_size);
- Ref<StyleBoxFlat> sb_minimap = minimap->get_theme_stylebox(SNAME("node"))->duplicate();
+ Ref<StyleBoxFlat> sb_minimap = minimap->theme_cache.node_style->duplicate();
// Override default values with colors provided by the GraphNode's stylebox, if possible.
- Ref<StyleBoxFlat> sb_frame = graph_node->get_theme_stylebox(graph_node->is_selected() ? "panel_selected" : "panel");
+ Ref<StyleBoxFlat> sb_frame = graph_node->is_selected() ? graph_node->theme_cache.panel_selected : graph_node->theme_cache.panel;
if (sb_frame.is_valid()) {
Color node_color = sb_frame->get_bg_color();
sb_minimap->set_bg_color(node_color);
@@ -1085,7 +1084,6 @@ void GraphEdit::_minimap_draw() {
}
// Draw node connections.
- Color activity_color = get_theme_color(SNAME("activity"));
for (const Connection &E : connections) {
Node *from = get_node(NodePath(E.from_node));
GraphNode *graph_node_from = Object::cast_to<GraphNode>(from);
@@ -1107,19 +1105,19 @@ void GraphEdit::_minimap_draw() {
Color to_color = graph_node_to->get_input_port_color(E.to_port);
if (E.activity > 0) {
- from_color = from_color.lerp(activity_color, E.activity);
- to_color = to_color.lerp(activity_color, E.activity);
+ from_color = from_color.lerp(theme_cache.activity_color, E.activity);
+ to_color = to_color.lerp(theme_cache.activity_color, E.activity);
}
_draw_connection_line(minimap, from_position, to_position, from_color, to_color, 0.5, minimap->_convert_from_graph_position(Vector2(zoom, zoom)).length());
}
// Draw the "camera" viewport.
Rect2 camera_rect = minimap->get_camera_rect();
- minimap->draw_style_box(minimap->get_theme_stylebox(SNAME("camera")), camera_rect);
+ minimap->draw_style_box(minimap->theme_cache.camera_style, camera_rect);
// Draw the resizer control.
- Ref<Texture2D> resizer = minimap->get_theme_icon(SNAME("resizer"));
- Color resizer_color = minimap->get_theme_color(SNAME("resizer_color"));
+ Ref<Texture2D> resizer = minimap->theme_cache.resizer;
+ Color resizer_color = minimap->theme_cache.resizer_color;
minimap->draw_texture(resizer, Point2(), resizer_color);
}
@@ -1157,7 +1155,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
// Snapping can be toggled temporarily by holding down Ctrl.
// This is done here as to not toggle the grid when holding down Ctrl.
- if (snapping_enabled ^ Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (snapping_enabled ^ Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
pos = pos.snapped(Vector2(snapping_distance, snapping_distance));
}
@@ -1216,7 +1214,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
}
if (mb->get_button_index() == MouseButton::LEFT && !mb->is_pressed() && dragging) {
- if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (!just_selected && drag_accum == Vector2() && Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
// Deselect current node.
for (int i = get_child_count() - 1; i >= 0; i--) {
GraphElement *graph_element = Object::cast_to<GraphElement>(get_child(i));
@@ -1283,7 +1281,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
dragging = true;
drag_accum = Vector2();
just_selected = !graph_element->is_selected();
- if (!graph_element->is_selected() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (!graph_element->is_selected() && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
for (int i = 0; i < get_child_count(); i++) {
GraphElement *child_element = Object::cast_to<GraphElement>(get_child(i));
if (!child_element) {
@@ -1316,7 +1314,7 @@ void GraphEdit::gui_input(const Ref<InputEvent> &p_ev) {
// Left-clicked on empty space, start box select.
box_selecting = true;
box_selecting_from = mb->get_position();
- if (mb->is_ctrl_pressed()) {
+ if (mb->is_command_or_control_pressed()) {
box_selection_mode_additive = true;
prev_selected.clear();
for (int i = get_child_count() - 1; i >= 0; i--) {
@@ -1909,6 +1907,26 @@ void GraphEdit::_bind_methods() {
BIND_ENUM_CONSTANT(SCROLL_ZOOMS);
BIND_ENUM_CONSTANT(SCROLL_PANS);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphEdit, panel);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, GraphEdit, grid_major);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, GraphEdit, grid_minor);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_COLOR, GraphEdit, activity_color, "activity");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, GraphEdit, selection_fill);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, GraphEdit, selection_stroke);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphEdit, zoom_in);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphEdit, zoom_out);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphEdit, zoom_reset);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphEdit, snapping_toggle);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphEdit, grid_toggle);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphEdit, minimap_toggle);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphEdit, layout);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GraphEdit, port_hotzone_inner_extent);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GraphEdit, port_hotzone_outer_extent);
}
GraphEdit::GraphEdit() {
diff --git a/scene/gui/graph_edit.h b/scene/gui/graph_edit.h
index 5e97ea353d..6b5698ad41 100644
--- a/scene/gui/graph_edit.h
+++ b/scene/gui/graph_edit.h
@@ -47,6 +47,7 @@ class GraphEditFilter : public Control {
friend class GraphEdit;
friend class GraphEditMinimap;
+
GraphEdit *ge = nullptr;
virtual bool has_point(const Point2 &p_point) const override;
@@ -63,24 +64,24 @@ class GraphEditMinimap : public Control {
GraphEdit *ge = nullptr;
-public:
- GraphEditMinimap(GraphEdit *p_edit);
-
- virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
-
- void update_minimap();
- Rect2 get_camera_rect();
-
-private:
Vector2 minimap_padding;
Vector2 minimap_offset;
- Vector2 graph_proportions;
- Vector2 graph_padding;
- Vector2 camera_position;
- Vector2 camera_size;
+ Vector2 graph_proportions = Vector2(1, 1);
+ Vector2 graph_padding = Vector2(0, 0);
+ Vector2 camera_position = Vector2(100, 50);
+ Vector2 camera_size = Vector2(200, 200);
+
+ bool is_pressing = false;
+ bool is_resizing = false;
+
+ struct ThemeCache {
+ Ref<StyleBox> panel;
+ Ref<StyleBox> node_style;
+ Ref<StyleBox> camera_style;
- bool is_pressing;
- bool is_resizing;
+ Ref<Texture2D> resizer;
+ Color resizer_color;
+ } theme_cache;
Vector2 _get_render_size();
Vector2 _get_graph_offset();
@@ -92,6 +93,17 @@ private:
virtual void gui_input(const Ref<InputEvent> &p_ev) override;
void _adjust_graph_scroll(const Vector2 &p_offset);
+
+protected:
+ static void _bind_methods();
+
+public:
+ virtual CursorShape get_cursor_shape(const Point2 &p_pos = Point2i()) const override;
+
+ void update_minimap();
+ Rect2 get_camera_rect();
+
+ GraphEditMinimap(GraphEdit *p_edit);
};
class GraphEdit : public Control {
@@ -150,9 +162,6 @@ private:
HScrollBar *h_scrollbar = nullptr;
VScrollBar *v_scrollbar = nullptr;
- float port_hotzone_inner_extent = 0.0;
- float port_hotzone_outer_extent = 0.0;
-
Ref<ViewPanner> panner;
bool warped_panning = true;
@@ -218,7 +227,30 @@ private:
HashSet<int> valid_left_disconnect_types;
HashSet<int> valid_right_disconnect_types;
- void _scroll_callback(Vector2 p_scroll_vec, bool p_alt);
+ struct ThemeCache {
+ float base_scale = 1.0;
+
+ Ref<StyleBox> panel;
+ Color grid_major;
+ Color grid_minor;
+
+ Color activity_color;
+ Color selection_fill;
+ Color selection_stroke;
+
+ Ref<Texture2D> zoom_in;
+ Ref<Texture2D> zoom_out;
+ Ref<Texture2D> zoom_reset;
+
+ Ref<Texture2D> snapping_toggle;
+ Ref<Texture2D> grid_toggle;
+ Ref<Texture2D> minimap_toggle;
+ Ref<Texture2D> layout;
+
+ float port_hotzone_inner_extent = 0.0;
+ float port_hotzone_outer_extent = 0.0;
+ } theme_cache;
+
void _pan_callback(Vector2 p_scroll_vec, Ref<InputEvent> p_event);
void _zoom_callback(float p_zoom_factor, Vector2 p_origin, Ref<InputEvent> p_event);
@@ -262,12 +294,13 @@ private:
bool _check_clickable_control(Control *p_control, const Vector2 &r_mouse_pos, const Vector2 &p_offset);
protected:
- static void _bind_methods();
+ virtual void _update_theme_item_cache() override;
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
void _notification(int p_what);
+ static void _bind_methods();
virtual bool is_in_input_hotzone(GraphNode *p_graph_node, int p_port_idx, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
virtual bool is_in_output_hotzone(GraphNode *p_graph_node, int p_port_idx, const Vector2 &p_mouse_pos, const Vector2i &p_port_size);
diff --git a/scene/gui/graph_edit_arranger.cpp b/scene/gui/graph_edit_arranger.cpp
index c1750a7b0f..1dc778254b 100644
--- a/scene/gui/graph_edit_arranger.cpp
+++ b/scene/gui/graph_edit_arranger.cpp
@@ -33,7 +33,7 @@
#include "scene/gui/graph_edit.h"
void GraphEditArranger::arrange_nodes() {
- ERR_FAIL_COND(!graph_edit);
+ ERR_FAIL_NULL(graph_edit);
if (!arranging_graph) {
arranging_graph = true;
diff --git a/scene/gui/graph_element.cpp b/scene/gui/graph_element.cpp
index 04c4aa6ce8..ac2cb8bd5d 100644
--- a/scene/gui/graph_element.cpp
+++ b/scene/gui/graph_element.cpp
@@ -32,6 +32,7 @@
#include "core/string/translation.h"
#include "scene/gui/graph_edit.h"
+#include "scene/theme/theme_db.h"
#ifdef TOOLS_ENABLED
void GraphElement::_edit_set_position(const Point2 &p_position) {
@@ -154,9 +155,7 @@ void GraphElement::gui_input(const Ref<InputEvent> &p_ev) {
if (mb->is_pressed() && mb->get_button_index() == MouseButton::LEFT) {
Vector2 mpos = mb->get_position();
- Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
-
- if (resizable && mpos.x > get_size().x - resizer->get_width() && mpos.y > get_size().y - resizer->get_height()) {
+ if (resizable && mpos.x > get_size().x - theme_cache.resizer->get_width() && mpos.y > get_size().y - theme_cache.resizer->get_height()) {
resizing = true;
resizing_from = mpos;
resizing_from_size = get_size();
@@ -241,4 +240,6 @@ void GraphElement::_bind_methods() {
ADD_SIGNAL(MethodInfo("raise_request"));
ADD_SIGNAL(MethodInfo("close_request"));
ADD_SIGNAL(MethodInfo("resize_request", PropertyInfo(Variant::VECTOR2, "new_minsize")));
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphElement, resizer);
}
diff --git a/scene/gui/graph_element.h b/scene/gui/graph_element.h
index 2c0a4760d8..a50c2953fd 100644
--- a/scene/gui/graph_element.h
+++ b/scene/gui/graph_element.h
@@ -49,6 +49,10 @@ protected:
Vector2 position_offset;
+ struct ThemeCache {
+ Ref<Texture2D> resizer;
+ } theme_cache;
+
#ifdef TOOLS_ENABLED
void _edit_set_position(const Point2 &p_position) override;
#endif
diff --git a/scene/gui/graph_node.cpp b/scene/gui/graph_node.cpp
index 385b564b7c..fdebca3d28 100644
--- a/scene/gui/graph_node.cpp
+++ b/scene/gui/graph_node.cpp
@@ -33,6 +33,7 @@
#include "core/string/translation.h"
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
+#include "scene/theme/theme_db.h"
bool GraphNode::_set(const StringName &p_name, const Variant &p_value) {
String str = p_name;
@@ -151,8 +152,8 @@ void GraphNode::_get_property_list(List<PropertyInfo> *p_list) const {
void GraphNode::_resort() {
Size2 new_size = get_size();
- Ref<StyleBox> sb_panel = get_theme_stylebox(SNAME("panel"));
- Ref<StyleBox> sb_titlebar = get_theme_stylebox(SNAME("titlebar"));
+ Ref<StyleBox> sb_panel = theme_cache.panel;
+ Ref<StyleBox> sb_titlebar = theme_cache.titlebar;
// Resort titlebar first.
Size2 titlebar_size = Size2(new_size.width, titlebar_hbox->get_size().height);
@@ -164,8 +165,8 @@ void GraphNode::_resort() {
Size2i titlebar_min_size = titlebar_hbox->get_combined_minimum_size();
// First pass, determine minimum size AND amount of stretchable elements.
- Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
- int separation = get_theme_constant(SNAME("separation"));
+ Ref<StyleBox> sb_slot = theme_cache.slot;
+ int separation = theme_cache.separation;
int children_count = 0;
int stretch_min = 0;
@@ -300,7 +301,7 @@ void GraphNode::draw_port(int p_slot_index, Point2i p_pos, bool p_left, const Co
Point2 icon_offset;
if (!port_icon.is_valid()) {
- port_icon = get_theme_icon(SNAME("port"));
+ port_icon = theme_cache.port;
}
icon_offset = -port_icon->get_size() * 0.5;
@@ -311,19 +312,15 @@ void GraphNode::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
// Used for layout calculations.
- Ref<StyleBox> sb_panel = get_theme_stylebox(SNAME("panel"));
- Ref<StyleBox> sb_titlebar = get_theme_stylebox(SNAME("titlebar"));
+ Ref<StyleBox> sb_panel = theme_cache.panel;
+ Ref<StyleBox> sb_titlebar = theme_cache.titlebar;
// Used for drawing.
- Ref<StyleBox> sb_to_draw_panel = get_theme_stylebox(selected ? SNAME("panel_selected") : SNAME("panel"));
- Ref<StyleBox> sb_to_draw_titlebar = get_theme_stylebox(selected ? SNAME("titlebar_selected") : SNAME("titlebar"));
+ Ref<StyleBox> sb_to_draw_panel = selected ? theme_cache.panel_selected : theme_cache.panel;
+ Ref<StyleBox> sb_to_draw_titlebar = selected ? theme_cache.titlebar_selected : theme_cache.titlebar;
- Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
+ Ref<StyleBox> sb_slot = theme_cache.slot;
- int port_h_offset = get_theme_constant(SNAME("port_h_offset"));
-
- Ref<Texture2D> resizer_icon = get_theme_icon(SNAME("resizer"));
-
- Color resizer_color = get_theme_color(SNAME("resizer_color"));
+ int port_h_offset = theme_cache.port_h_offset;
Rect2 titlebar_rect(Point2(), titlebar_hbox->get_size() + sb_titlebar->get_minimum_size());
Size2 body_size = get_size();
@@ -377,7 +374,7 @@ void GraphNode::_notification(int p_what) {
}
if (resizable) {
- draw_texture(resizer_icon, get_size() - resizer_icon->get_size(), resizer_color);
+ draw_texture(theme_cache.resizer, get_size() - theme_cache.resizer->get_size(), theme_cache.resizer_color);
}
} break;
}
@@ -566,11 +563,11 @@ void GraphNode::set_slot_draw_stylebox(int p_slot_index, bool p_enable) {
}
Size2 GraphNode::get_minimum_size() const {
- Ref<StyleBox> sb_panel = get_theme_stylebox(SNAME("panel"));
- Ref<StyleBox> sb_titlebar = get_theme_stylebox(SNAME("titlebar"));
- Ref<StyleBox> sb_slot = get_theme_stylebox(SNAME("slot"));
+ Ref<StyleBox> sb_panel = theme_cache.panel;
+ Ref<StyleBox> sb_titlebar = theme_cache.titlebar;
+ Ref<StyleBox> sb_slot = theme_cache.slot;
- int separation = get_theme_constant(SNAME("separation"));
+ int separation = theme_cache.separation;
Size2 minsize = titlebar_hbox->get_minimum_size() + sb_titlebar->get_minimum_size();
for (int i = 0; i < get_child_count(false); i++) {
@@ -599,11 +596,11 @@ Size2 GraphNode::get_minimum_size() const {
}
void GraphNode::_port_pos_update() {
- int edgeofs = get_theme_constant(SNAME("port_h_offset"));
- int separation = get_theme_constant(SNAME("separation"));
+ int edgeofs = theme_cache.port_h_offset;
+ int separation = theme_cache.separation;
- Ref<StyleBox> sb_panel = get_theme_stylebox(SNAME("panel"));
- Ref<StyleBox> sb_titlebar = get_theme_stylebox(SNAME("titlebar"));
+ Ref<StyleBox> sb_panel = theme_cache.panel;
+ Ref<StyleBox> sb_titlebar = theme_cache.titlebar;
left_port_cache.clear();
right_port_cache.clear();
@@ -754,9 +751,7 @@ HBoxContainer *GraphNode::get_titlebar_hbox() {
Control::CursorShape GraphNode::get_cursor_shape(const Point2 &p_pos) const {
if (resizable) {
- Ref<Texture2D> resizer = get_theme_icon(SNAME("resizer"));
-
- if (resizing || (p_pos.x > get_size().x - resizer->get_width() && p_pos.y > get_size().y - resizer->get_height())) {
+ if (resizing || (p_pos.x > get_size().x - theme_cache.resizer->get_width() && p_pos.y > get_size().y - theme_cache.resizer->get_height())) {
return CURSOR_FDIAGSIZE;
}
}
@@ -830,6 +825,19 @@ void GraphNode::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "title"), "set_title", "get_title");
ADD_SIGNAL(MethodInfo("slot_updated", PropertyInfo(Variant::INT, "slot_index")));
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, panel);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, panel_selected);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, titlebar);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, titlebar_selected);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, GraphNode, slot);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GraphNode, separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GraphNode, port_h_offset);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphNode, port);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, GraphNode, resizer);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, GraphNode, resizer_color);
}
GraphNode::GraphNode() {
diff --git a/scene/gui/graph_node.h b/scene/gui/graph_node.h
index 1178421819..04ca9e7cb4 100644
--- a/scene/gui/graph_node.h
+++ b/scene/gui/graph_node.h
@@ -38,6 +38,8 @@ class HBoxContainer;
class GraphNode : public GraphElement {
GDCLASS(GraphNode, GraphElement);
+ friend class GraphEdit;
+
struct Slot {
bool enable_left = false;
int type_left = 0;
@@ -74,9 +76,23 @@ class GraphNode : public GraphElement {
Vector<PortCache> right_port_cache;
HashMap<int, Slot> slot_table;
-
Vector<int> slot_y_cache;
+ struct ThemeCache {
+ Ref<StyleBox> panel;
+ Ref<StyleBox> panel_selected;
+ Ref<StyleBox> titlebar;
+ Ref<StyleBox> titlebar_selected;
+ Ref<StyleBox> slot;
+
+ int separation = 0;
+ int port_h_offset = 0;
+
+ Ref<Texture2D> port;
+ Ref<Texture2D> resizer;
+ Color resizer_color;
+ } theme_cache;
+
bool port_pos_dirty = true;
void _port_pos_update();
diff --git a/scene/gui/grid_container.cpp b/scene/gui/grid_container.cpp
index 28f86369a2..a4baf3bb8d 100644
--- a/scene/gui/grid_container.cpp
+++ b/scene/gui/grid_container.cpp
@@ -29,14 +29,9 @@
/**************************************************************************/
#include "grid_container.h"
-#include "core/templates/rb_set.h"
-
-void GridContainer::_update_theme_item_cache() {
- Container::_update_theme_item_cache();
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
-}
+#include "core/templates/rb_set.h"
+#include "scene/theme/theme_db.h"
void GridContainer::_notification(int p_what) {
switch (p_what) {
@@ -264,11 +259,18 @@ int GridContainer::get_columns() const {
return columns;
}
+int GridContainer::get_h_separation() const {
+ return theme_cache.h_separation;
+}
+
void GridContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_columns", "columns"), &GridContainer::set_columns);
ClassDB::bind_method(D_METHOD("get_columns"), &GridContainer::get_columns);
ADD_PROPERTY(PropertyInfo(Variant::INT, "columns", PROPERTY_HINT_RANGE, "1,1024,1"), "set_columns", "get_columns");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GridContainer, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, GridContainer, v_separation);
}
Size2 GridContainer::get_minimum_size() const {
diff --git a/scene/gui/grid_container.h b/scene/gui/grid_container.h
index 6fe944e9a4..f6a51511a9 100644
--- a/scene/gui/grid_container.h
+++ b/scene/gui/grid_container.h
@@ -44,8 +44,6 @@ class GridContainer : public Container {
} theme_cache;
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
static void _bind_methods();
@@ -54,6 +52,8 @@ public:
int get_columns() const;
virtual Size2 get_minimum_size() const override;
+ int get_h_separation() const;
+
GridContainer();
};
diff --git a/scene/gui/item_list.cpp b/scene/gui/item_list.cpp
index b03d3c52d2..e1fc7d7cd4 100644
--- a/scene/gui/item_list.cpp
+++ b/scene/gui/item_list.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
#include "core/string/translation.h"
+#include "scene/theme/theme_db.h"
void ItemList::_shape_text(int p_idx) {
Item &item = items.write[p_idx];
@@ -992,33 +993,6 @@ static Rect2 _adjust_to_max_size(Size2 p_size, Size2 p_max_size) {
return Rect2(ofs_x, ofs_y, tex_width, tex_height);
}
-void ItemList::_update_theme_item_cache() {
- Control::_update_theme_item_cache();
-
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
- theme_cache.focus_style = get_theme_stylebox(SNAME("focus"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_hovered_color = get_theme_color(SNAME("font_hovered_color"));
- theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
- theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
-
- theme_cache.line_separation = get_theme_constant(SNAME("line_separation"));
- theme_cache.icon_margin = get_theme_constant(SNAME("icon_margin"));
- theme_cache.hovered_style = get_theme_stylebox(SNAME("hovered"));
- theme_cache.selected_style = get_theme_stylebox(SNAME("selected"));
- theme_cache.selected_focus_style = get_theme_stylebox(SNAME("selected_focus"));
- theme_cache.cursor_style = get_theme_stylebox(SNAME("cursor_unfocused"));
- theme_cache.cursor_focus_style = get_theme_stylebox(SNAME("cursor"));
- theme_cache.guide_color = get_theme_color(SNAME("guide_color"));
-}
-
void ItemList::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_RESIZED: {
@@ -1037,7 +1011,7 @@ void ItemList::_notification(int p_what) {
} break;
case NOTIFICATION_DRAW: {
- _check_shape_changed();
+ force_update_list_size();
int scroll_bar_minwidth = scroll_bar->get_minimum_size().x;
scroll_bar->set_anchor_and_offset(SIDE_LEFT, ANCHOR_END, -scroll_bar_minwidth);
@@ -1340,7 +1314,7 @@ void ItemList::_notification(int p_what) {
}
}
-void ItemList::_check_shape_changed() {
+void ItemList::force_update_list_size() {
if (!shape_changed) {
return;
}
@@ -1881,6 +1855,8 @@ void ItemList::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_text_overrun_behavior", "overrun_behavior"), &ItemList::set_text_overrun_behavior);
ClassDB::bind_method(D_METHOD("get_text_overrun_behavior"), &ItemList::get_text_overrun_behavior);
+ ClassDB::bind_method(D_METHOD("force_update_list_size"), &ItemList::force_update_list_size);
+
ADD_PROPERTY(PropertyInfo(Variant::INT, "select_mode", PROPERTY_HINT_ENUM, "Single,Multi"), "set_select_mode", "get_select_mode");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_rmb_select"), "set_allow_rmb_select", "get_allow_rmb_select");
@@ -1909,6 +1885,29 @@ void ItemList::_bind_methods() {
ADD_SIGNAL(MethodInfo("item_clicked", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::VECTOR2, "at_position"), PropertyInfo(Variant::INT, "mouse_button_index")));
ADD_SIGNAL(MethodInfo("multi_selected", PropertyInfo(Variant::INT, "index"), PropertyInfo(Variant::BOOL, "selected")));
ADD_SIGNAL(MethodInfo("item_activated", PropertyInfo(Variant::INT, "index")));
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ItemList, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ItemList, v_separation);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ItemList, panel_style, "panel");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ItemList, focus_style, "focus");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, ItemList, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, ItemList, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ItemList, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ItemList, font_hovered_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ItemList, font_selected_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, ItemList, font_outline_size, "outline_size");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ItemList, font_outline_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ItemList, line_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, ItemList, icon_margin);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ItemList, hovered_style, "hovered");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ItemList, selected_style, "selected");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ItemList, selected_focus_style, "selected_focus");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ItemList, cursor_style, "cursor_unfocused");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ItemList, cursor_focus_style, "cursor");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ItemList, guide_color);
}
ItemList::ItemList() {
diff --git a/scene/gui/item_list.h b/scene/gui/item_list.h
index ced04f8718..796e0eb687 100644
--- a/scene/gui/item_list.h
+++ b/scene/gui/item_list.h
@@ -148,13 +148,10 @@ private:
} theme_cache;
void _scroll_changed(double);
- void _check_shape_changed();
void _shape_text(int p_idx);
void _mouse_exited();
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -283,6 +280,8 @@ public:
void set_autoscroll_to_bottom(const bool p_enable);
+ void force_update_list_size();
+
VScrollBar *get_v_scroll_bar() { return scroll_bar; }
ItemList();
diff --git a/scene/gui/label.cpp b/scene/gui/label.cpp
index cf0627c6f1..0d48cb1549 100644
--- a/scene/gui/label.cpp
+++ b/scene/gui/label.cpp
@@ -33,7 +33,7 @@
#include "core/config/project_settings.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
-
+#include "scene/theme/theme_db.h"
#include "servers/text_server.h"
void Label::set_autowrap_mode(TextServer::AutowrapMode p_mode) {
@@ -324,22 +324,6 @@ inline void draw_glyph_outline(const Glyph &p_gl, const RID &p_canvas, const Col
}
}
-void Label::_update_theme_item_cache() {
- Control::_update_theme_item_cache();
-
- theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
- theme_cache.font = get_theme_font(SNAME("font"));
-
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.line_spacing = get_theme_constant(SNAME("line_spacing"));
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color"));
- theme_cache.font_shadow_offset = Point2(get_theme_constant(SNAME("shadow_offset_x")), get_theme_constant(SNAME("shadow_offset_y")));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
- theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.font_shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
-}
-
PackedStringArray Label::get_configuration_warnings() const {
PackedStringArray warnings = Control::get_configuration_warnings();
@@ -1054,6 +1038,19 @@ void Label::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Label, normal_style, "normal");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Label, line_spacing);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, Label, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, Label, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Label, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Label, font_shadow_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, Label, font_shadow_offset.x, "shadow_offset_x");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, Label, font_shadow_offset.y, "shadow_offset_y");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Label, font_outline_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, Label, font_outline_size, "outline_size");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, Label, font_shadow_outline_size, "shadow_outline_size");
}
Label::Label(const String &p_text) {
diff --git a/scene/gui/label.h b/scene/gui/label.h
index 70e15fc2e2..a5126c6b91 100644
--- a/scene/gui/label.h
+++ b/scene/gui/label.h
@@ -88,8 +88,6 @@ private:
void _invalidate();
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/line_edit.cpp b/scene/gui/line_edit.cpp
index c8ad0b0e79..100e0c4548 100644
--- a/scene/gui/line_edit.cpp
+++ b/scene/gui/line_edit.cpp
@@ -36,13 +36,15 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "core/string/translation.h"
-#include "label.h"
+#include "scene/gui/label.h"
+#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
#include "servers/display_server.h"
#include "servers/text_server.h"
+
#ifdef TOOLS_ENABLED
#include "editor/editor_settings.h"
#endif
-#include "scene/main/window.h"
void LineEdit::_swap_current_input_direction() {
if (input_direction == TEXT_DIRECTION_LTR) {
@@ -612,7 +614,7 @@ void LineEdit::gui_input(const Ref<InputEvent> &p_event) {
// Allow unicode handling if:
// * No Modifiers are pressed (except shift)
- bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
+ bool allow_unicode_handling = !(k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
if (allow_unicode_handling && editable && k->get_unicode() >= 32) {
// Handle Unicode if no modifiers are active.
@@ -677,13 +679,13 @@ void LineEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
set_caret_at_pixel_pos(p_point.x);
int caret_column_tmp = caret_column;
bool is_inside_sel = selection.enabled && caret_column >= selection.begin && caret_column <= selection.end;
- if (Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
is_inside_sel = selection.enabled && caret_column > selection.begin && caret_column < selection.end;
}
if (selection.drag_attempt) {
selection.drag_attempt = false;
if (!is_inside_sel) {
- if (!Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (!Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
if (caret_column_tmp > selection.end) {
caret_column_tmp = caret_column_tmp - (selection.end - selection.begin);
}
@@ -733,27 +735,6 @@ bool LineEdit::_is_over_clear_button(const Point2 &p_pos) const {
void LineEdit::_update_theme_item_cache() {
Control::_update_theme_item_cache();
- theme_cache.normal = get_theme_stylebox(SNAME("normal"));
- theme_cache.read_only = get_theme_stylebox(SNAME("read_only"));
- theme_cache.focus = get_theme_stylebox(SNAME("focus"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_uneditable_color = get_theme_color(SNAME("font_uneditable_color"));
- theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
- theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
- theme_cache.font_placeholder_color = get_theme_color(SNAME("font_placeholder_color"));
- theme_cache.caret_width = get_theme_constant(SNAME("caret_width"));
- theme_cache.caret_color = get_theme_color(SNAME("caret_color"));
- theme_cache.minimum_character_width = get_theme_constant(SNAME("minimum_character_width"));
- theme_cache.selection_color = get_theme_color(SNAME("selection_color"));
-
- theme_cache.clear_icon = get_theme_icon(SNAME("clear"));
- theme_cache.clear_button_color = get_theme_color(SNAME("clear_button_color"));
- theme_cache.clear_button_color_pressed = get_theme_color(SNAME("clear_button_color_pressed"));
-
theme_cache.base_scale = get_theme_default_base_scale();
}
@@ -1158,7 +1139,7 @@ void LineEdit::_notification(int p_what) {
if (is_drag_successful()) {
if (selection.drag_attempt) {
selection.drag_attempt = false;
- if (is_editable() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (is_editable() && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
selection_delete();
} else if (deselect_on_focus_loss_enabled) {
deselect();
@@ -2669,6 +2650,27 @@ void LineEdit::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, normal);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, read_only);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LineEdit, focus);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, LineEdit, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, LineEdit, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_uneditable_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_selected_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, LineEdit, font_outline_size, "outline_size");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_outline_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, font_placeholder_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, LineEdit, caret_width);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, caret_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, LineEdit, minimum_character_width);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, selection_color);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, LineEdit, clear_icon, "clear");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, clear_button_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LineEdit, clear_button_color_pressed);
}
LineEdit::LineEdit(const String &p_placeholder) {
diff --git a/scene/gui/line_edit.h b/scene/gui/line_edit.h
index 734813f8a0..4a81f90166 100644
--- a/scene/gui/line_edit.h
+++ b/scene/gui/line_edit.h
@@ -246,14 +246,16 @@ private:
protected:
bool _is_over_clear_button(const Point2 &p_pos) const;
+
virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
+ void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
+
virtual void unhandled_key_input(const Ref<InputEvent> &p_event) override;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- void _validate_property(PropertyInfo &p_property) const;
-
public:
void set_horizontal_alignment(HorizontalAlignment p_alignment);
HorizontalAlignment get_horizontal_alignment() const;
diff --git a/scene/gui/link_button.cpp b/scene/gui/link_button.cpp
index b579791990..5df0bf21a0 100644
--- a/scene/gui/link_button.cpp
+++ b/scene/gui/link_button.cpp
@@ -31,6 +31,7 @@
#include "link_button.h"
#include "core/string/translation.h"
+#include "scene/theme/theme_db.h"
void LinkButton::_shape() {
Ref<Font> font = theme_cache.font;
@@ -141,26 +142,6 @@ Size2 LinkButton::get_minimum_size() const {
return text_buf->get_size();
}
-void LinkButton::_update_theme_item_cache() {
- BaseButton::_update_theme_item_cache();
-
- theme_cache.focus = get_theme_stylebox(SNAME("focus"));
-
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
- theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
- theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
- theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
- theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
-
- theme_cache.underline_spacing = get_theme_constant(SNAME("underline_spacing"));
-}
-
void LinkButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED: {
@@ -284,6 +265,22 @@ void LinkButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
ADD_PROPERTY(PropertyInfo(Variant::INT, "structured_text_bidi_override", PROPERTY_HINT_ENUM, "Default,URI,File,Email,List,None,Custom"), "set_structured_text_bidi_override", "get_structured_text_bidi_override");
ADD_PROPERTY(PropertyInfo(Variant::ARRAY, "structured_text_bidi_override_options"), "set_structured_text_bidi_override_options", "get_structured_text_bidi_override_options");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, LinkButton, focus);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LinkButton, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LinkButton, font_focus_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LinkButton, font_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LinkButton, font_hover_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LinkButton, font_hover_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LinkButton, font_disabled_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, LinkButton, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, LinkButton, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, LinkButton, outline_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, LinkButton, font_outline_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, LinkButton, underline_spacing);
}
LinkButton::LinkButton(const String &p_text) {
diff --git a/scene/gui/link_button.h b/scene/gui/link_button.h
index e3d6ef2c5b..6ed47087bf 100644
--- a/scene/gui/link_button.h
+++ b/scene/gui/link_button.h
@@ -79,7 +79,7 @@ private:
protected:
virtual void pressed() override;
virtual Size2 get_minimum_size() const override;
- virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/margin_container.cpp b/scene/gui/margin_container.cpp
index ca688b3adc..6d331afbb5 100644
--- a/scene/gui/margin_container.cpp
+++ b/scene/gui/margin_container.cpp
@@ -30,14 +30,7 @@
#include "margin_container.h"
-void MarginContainer::_update_theme_item_cache() {
- Container::_update_theme_item_cache();
-
- theme_cache.margin_left = get_theme_constant(SNAME("margin_left"));
- theme_cache.margin_top = get_theme_constant(SNAME("margin_top"));
- theme_cache.margin_right = get_theme_constant(SNAME("margin_right"));
- theme_cache.margin_bottom = get_theme_constant(SNAME("margin_bottom"));
-}
+#include "scene/theme/theme_db.h"
Size2 MarginContainer::get_minimum_size() const {
Size2 max;
@@ -87,6 +80,23 @@ Vector<int> MarginContainer::get_allowed_size_flags_vertical() const {
return flags;
}
+int MarginContainer::get_margin_size(Side p_side) const {
+ ERR_FAIL_INDEX_V((int)p_side, 4, 0);
+
+ switch (p_side) {
+ case SIDE_LEFT:
+ return theme_cache.margin_left;
+ case SIDE_RIGHT:
+ return theme_cache.margin_right;
+ case SIDE_TOP:
+ return theme_cache.margin_top;
+ case SIDE_BOTTOM:
+ return theme_cache.margin_bottom;
+ }
+
+ return 0;
+}
+
void MarginContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_SORT_CHILDREN: {
@@ -113,5 +123,12 @@ void MarginContainer::_notification(int p_what) {
}
}
+void MarginContainer::_bind_methods() {
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MarginContainer, margin_left);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MarginContainer, margin_top);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MarginContainer, margin_right);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MarginContainer, margin_bottom);
+}
+
MarginContainer::MarginContainer() {
}
diff --git a/scene/gui/margin_container.h b/scene/gui/margin_container.h
index da20bf98fd..d57ab9b452 100644
--- a/scene/gui/margin_container.h
+++ b/scene/gui/margin_container.h
@@ -44,9 +44,8 @@ class MarginContainer : public Container {
} theme_cache;
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
+ static void _bind_methods();
public:
virtual Size2 get_minimum_size() const override;
@@ -54,6 +53,8 @@ public:
virtual Vector<int> get_allowed_size_flags_horizontal() const override;
virtual Vector<int> get_allowed_size_flags_vertical() const override;
+ int get_margin_size(Side p_side) const;
+
MarginContainer();
};
diff --git a/scene/gui/menu_bar.cpp b/scene/gui/menu_bar.cpp
index 0dd258d92c..13a42d0407 100644
--- a/scene/gui/menu_bar.cpp
+++ b/scene/gui/menu_bar.cpp
@@ -32,6 +32,7 @@
#include "core/os/keyboard.h"
#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
void MenuBar::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
@@ -305,35 +306,6 @@ void MenuBar::_update_menu() {
queue_redraw();
}
-void MenuBar::_update_theme_item_cache() {
- Control::_update_theme_item_cache();
-
- theme_cache.normal = get_theme_stylebox(SNAME("normal"));
- theme_cache.normal_mirrored = get_theme_stylebox(SNAME("normal_mirrored"));
- theme_cache.disabled = get_theme_stylebox(SNAME("disabled"));
- theme_cache.disabled_mirrored = get_theme_stylebox(SNAME("disabled_mirrored"));
- theme_cache.pressed = get_theme_stylebox(SNAME("pressed"));
- theme_cache.pressed_mirrored = get_theme_stylebox(SNAME("pressed_mirrored"));
- theme_cache.hover = get_theme_stylebox(SNAME("hover"));
- theme_cache.hover_mirrored = get_theme_stylebox(SNAME("hover_mirrored"));
- theme_cache.hover_pressed = get_theme_stylebox(SNAME("hover_pressed"));
- theme_cache.hover_pressed_mirrored = get_theme_stylebox(SNAME("hover_pressed_mirrored"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
-
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
- theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
- theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
- theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
- theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
-
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
-}
-
void MenuBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -684,6 +656,31 @@ void MenuBar::_bind_methods() {
ADD_GROUP("BiDi", "");
ADD_PROPERTY(PropertyInfo(Variant::INT, "text_direction", PROPERTY_HINT_ENUM, "Auto,Left-to-Right,Right-to-Left,Inherited"), "set_text_direction", "get_text_direction");
ADD_PROPERTY(PropertyInfo(Variant::STRING, "language", PROPERTY_HINT_LOCALE_ID, ""), "set_language", "get_language");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, normal);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, normal_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, disabled_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, pressed);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, pressed_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, hover);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, hover_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, hover_pressed);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, MenuBar, hover_pressed_mirrored);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, MenuBar, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, MenuBar, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MenuBar, outline_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_outline_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_disabled_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_hover_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_hover_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, MenuBar, font_focus_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, MenuBar, h_separation);
}
void MenuBar::set_switch_on_hover(bool p_enabled) {
diff --git a/scene/gui/menu_bar.h b/scene/gui/menu_bar.h
index 3436978a0e..4d6e76d9b6 100644
--- a/scene/gui/menu_bar.h
+++ b/scene/gui/menu_bar.h
@@ -121,7 +121,6 @@ class MenuBar : public Control {
protected:
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
virtual void add_child_notify(Node *p_child) override;
virtual void move_child_notify(Node *p_child) override;
diff --git a/scene/gui/option_button.cpp b/scene/gui/option_button.cpp
index a260385a46..f9740b1217 100644
--- a/scene/gui/option_button.cpp
+++ b/scene/gui/option_button.cpp
@@ -32,6 +32,7 @@
#include "core/os/keyboard.h"
#include "core/string/print_string.h"
+#include "scene/theme/theme_db.h"
static const int NONE_SELECTED = -1;
@@ -72,25 +73,6 @@ Size2 OptionButton::get_minimum_size() const {
return minsize;
}
-void OptionButton::_update_theme_item_cache() {
- Button::_update_theme_item_cache();
-
- theme_cache.normal = get_theme_stylebox(SNAME("normal"));
-
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_focus_color = get_theme_color(SNAME("font_focus_color"));
- theme_cache.font_pressed_color = get_theme_color(SNAME("font_pressed_color"));
- theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
- theme_cache.font_hover_pressed_color = get_theme_color(SNAME("font_hover_pressed_color"));
- theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
-
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
-
- theme_cache.arrow_icon = get_theme_icon(SNAME("arrow"));
- theme_cache.arrow_margin = get_theme_constant(SNAME("arrow_margin"));
- theme_cache.modulate_arrow = get_theme_constant(SNAME("modulate_arrow"));
-}
-
void OptionButton::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_POSTINITIALIZE: {
@@ -597,8 +579,24 @@ void OptionButton::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::INT, "selected"), "_select_int", "get_selected");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "fit_to_longest_item"), "set_fit_to_longest_item", "is_fit_to_longest_item");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "allow_reselect"), "set_allow_reselect", "get_allow_reselect");
+
ADD_SIGNAL(MethodInfo("item_selected", PropertyInfo(Variant::INT, "index")));
ADD_SIGNAL(MethodInfo("item_focused", PropertyInfo(Variant::INT, "index")));
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, OptionButton, normal);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, OptionButton, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, OptionButton, font_focus_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, OptionButton, font_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, OptionButton, font_hover_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, OptionButton, font_hover_pressed_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, OptionButton, font_disabled_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, OptionButton, h_separation);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, OptionButton, arrow_icon, "arrow");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, OptionButton, arrow_margin);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, OptionButton, modulate_arrow);
}
void OptionButton::set_disable_shortcuts(bool p_disabled) {
diff --git a/scene/gui/option_button.h b/scene/gui/option_button.h
index e29f14ad54..eef498333b 100644
--- a/scene/gui/option_button.h
+++ b/scene/gui/option_button.h
@@ -72,14 +72,15 @@ class OptionButton : public Button {
protected:
Size2 get_minimum_size() const override;
- virtual void _update_theme_item_cache() override;
virtual void _queue_update_size_cache() override;
+
void _notification(int p_what);
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();
+
virtual void shortcut_input(const Ref<InputEvent> &p_event) override;
public:
diff --git a/scene/gui/panel.cpp b/scene/gui/panel.cpp
index 1377bcdb51..8096191933 100644
--- a/scene/gui/panel.cpp
+++ b/scene/gui/panel.cpp
@@ -29,12 +29,7 @@
/**************************************************************************/
#include "panel.h"
-
-void Panel::_update_theme_item_cache() {
- Control::_update_theme_item_cache();
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
-}
+#include "scene/theme/theme_db.h"
void Panel::_notification(int p_what) {
switch (p_what) {
@@ -45,6 +40,10 @@ void Panel::_notification(int p_what) {
}
}
+void Panel::_bind_methods() {
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Panel, panel_style, "panel");
+}
+
Panel::Panel() {
// Has visible stylebox, so stop by default.
set_mouse_filter(MOUSE_FILTER_STOP);
diff --git a/scene/gui/panel.h b/scene/gui/panel.h
index d6be2664ec..6f3f88987f 100644
--- a/scene/gui/panel.h
+++ b/scene/gui/panel.h
@@ -41,9 +41,8 @@ class Panel : public Control {
} theme_cache;
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
+ static void _bind_methods();
public:
Panel();
diff --git a/scene/gui/panel_container.cpp b/scene/gui/panel_container.cpp
index 619d462c25..306ef4936f 100644
--- a/scene/gui/panel_container.cpp
+++ b/scene/gui/panel_container.cpp
@@ -30,6 +30,8 @@
#include "panel_container.h"
+#include "scene/theme/theme_db.h"
+
Size2 PanelContainer::get_minimum_size() const {
Size2 ms;
for (int i = 0; i < get_child_count(); i++) {
@@ -70,12 +72,6 @@ Vector<int> PanelContainer::get_allowed_size_flags_vertical() const {
return flags;
}
-void PanelContainer::_update_theme_item_cache() {
- Container::_update_theme_item_cache();
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
-}
-
void PanelContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -106,6 +102,10 @@ void PanelContainer::_notification(int p_what) {
}
}
+void PanelContainer::_bind_methods() {
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, PanelContainer, panel_style, "panel");
+}
+
PanelContainer::PanelContainer() {
// Has visible stylebox, so stop by default.
set_mouse_filter(MOUSE_FILTER_STOP);
diff --git a/scene/gui/panel_container.h b/scene/gui/panel_container.h
index 5d13460b3a..45fdbc3ad2 100644
--- a/scene/gui/panel_container.h
+++ b/scene/gui/panel_container.h
@@ -41,8 +41,8 @@ class PanelContainer : public Container {
} theme_cache;
protected:
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
+ static void _bind_methods();
public:
virtual Size2 get_minimum_size() const override;
diff --git a/scene/gui/popup.cpp b/scene/gui/popup.cpp
index 6915f3d242..b16e8371a2 100644
--- a/scene/gui/popup.cpp
+++ b/scene/gui/popup.cpp
@@ -33,6 +33,7 @@
#include "core/config/engine.h"
#include "core/os/keyboard.h"
#include "scene/gui/panel.h"
+#include "scene/theme/theme_db.h"
void Popup::_input_from_window(const Ref<InputEvent> &p_event) {
if (get_flag(FLAG_POPUP) && p_event->is_action_pressed(SNAME("ui_cancel"), false, true)) {
@@ -67,12 +68,6 @@ void Popup::_deinitialize_visible_parents() {
}
}
-void Popup::_update_theme_item_cache() {
- Window::_update_theme_item_cache();
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
-}
-
void Popup::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_VISIBILITY_CHANGED: {
@@ -135,10 +130,6 @@ void Popup::_post_popup() {
popped_up = true;
}
-void Popup::_bind_methods() {
- ADD_SIGNAL(MethodInfo("popup_hide"));
-}
-
void Popup::_validate_property(PropertyInfo &p_property) const {
if (
p_property.name == "transient" ||
@@ -200,6 +191,12 @@ Rect2i Popup::_popup_adjust_rect() const {
return current;
}
+void Popup::_bind_methods() {
+ ADD_SIGNAL(MethodInfo("popup_hide"));
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Popup, panel_style, "panel");
+}
+
Popup::Popup() {
set_wrap_controls(true);
set_visible(false);
@@ -259,12 +256,6 @@ void PopupPanel::_update_child_rects() {
}
}
-void PopupPanel::_update_theme_item_cache() {
- Popup::_update_theme_item_cache();
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
-}
-
void PopupPanel::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_READY:
@@ -279,6 +270,10 @@ void PopupPanel::_notification(int p_what) {
}
}
+void PopupPanel::_bind_methods() {
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, PopupPanel, panel_style, "panel");
+}
+
PopupPanel::PopupPanel() {
panel = memnew(Panel);
add_child(panel, false, INTERNAL_MODE_FRONT);
diff --git a/scene/gui/popup.h b/scene/gui/popup.h
index d2bff5b8d1..d524e448dd 100644
--- a/scene/gui/popup.h
+++ b/scene/gui/popup.h
@@ -56,10 +56,9 @@ protected:
void _close_pressed();
virtual Rect2i _popup_adjust_rect() const override;
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
- static void _bind_methods();
void _validate_property(PropertyInfo &p_property) const;
+ static void _bind_methods();
virtual void _parent_focused();
@@ -82,8 +81,8 @@ class PopupPanel : public Popup {
protected:
void _update_child_rects();
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
+ static void _bind_methods();
virtual Size2 _get_contents_minimum_size() const override;
diff --git a/scene/gui/popup_menu.cpp b/scene/gui/popup_menu.cpp
index 4bba33f18e..d64136a682 100644
--- a/scene/gui/popup_menu.cpp
+++ b/scene/gui/popup_menu.cpp
@@ -38,6 +38,7 @@
#include "core/string/print_string.h"
#include "core/string/translation.h"
#include "scene/gui/menu_bar.h"
+#include "scene/theme/theme_db.h"
String PopupMenu::_get_accel_text(const Item &p_item) const {
if (p_item.shortcut.is_valid()) {
@@ -204,9 +205,9 @@ void PopupMenu::_activate_submenu(int p_over, bool p_by_keyboard) {
Point2 submenu_pos;
if (control->is_layout_rtl()) {
- submenu_pos = this_pos + Point2(-submenu_size.width, items[p_over]._ofs_cache + scroll_offset);
+ submenu_pos = this_pos + Point2(-submenu_size.width, items[p_over]._ofs_cache + scroll_offset - theme_cache.v_separation / 2);
} else {
- submenu_pos = this_pos + Point2(this_rect.size.width, items[p_over]._ofs_cache + scroll_offset);
+ submenu_pos = this_pos + Point2(this_rect.size.width, items[p_over]._ofs_cache + scroll_offset - theme_cache.v_separation / 2);
}
// Fix pos if going outside parent rect.
@@ -558,8 +559,8 @@ void PopupMenu::_draw_items() {
RID ci = control->get_canvas_item();
Size2 margin_size;
- margin_size.width = margin_container->get_theme_constant(SNAME("margin_right")) + margin_container->get_theme_constant(SNAME("margin_left"));
- margin_size.height = margin_container->get_theme_constant(SNAME("margin_top")) + margin_container->get_theme_constant(SNAME("margin_bottom"));
+ margin_size.width = margin_container->get_margin_size(SIDE_LEFT) + margin_container->get_margin_size(SIDE_RIGHT);
+ margin_size.height = margin_container->get_margin_size(SIDE_TOP) + margin_container->get_margin_size(SIDE_BOTTOM);
// Space between the item content and the sides of popup menu.
bool rtl = control->is_layout_rtl();
@@ -839,52 +840,6 @@ void PopupMenu::remove_child_notify(Node *p_child) {
_menu_changed();
}
-void PopupMenu::_update_theme_item_cache() {
- Popup::_update_theme_item_cache();
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
- theme_cache.hover_style = get_theme_stylebox(SNAME("hover"));
-
- theme_cache.separator_style = get_theme_stylebox(SNAME("separator"));
- theme_cache.labeled_separator_left = get_theme_stylebox(SNAME("labeled_separator_left"));
- theme_cache.labeled_separator_right = get_theme_stylebox(SNAME("labeled_separator_right"));
-
- theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.indent = get_theme_constant(SNAME("indent"));
- theme_cache.item_start_padding = get_theme_constant(SNAME("item_start_padding"));
- theme_cache.item_end_padding = get_theme_constant(SNAME("item_end_padding"));
- theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
-
- theme_cache.checked = get_theme_icon(SNAME("checked"));
- theme_cache.checked_disabled = get_theme_icon(SNAME("checked_disabled"));
- theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
- theme_cache.unchecked_disabled = get_theme_icon(SNAME("unchecked_disabled"));
- theme_cache.radio_checked = get_theme_icon(SNAME("radio_checked"));
- theme_cache.radio_checked_disabled = get_theme_icon(SNAME("radio_checked_disabled"));
- theme_cache.radio_unchecked = get_theme_icon(SNAME("radio_unchecked"));
- theme_cache.radio_unchecked_disabled = get_theme_icon(SNAME("radio_unchecked_disabled"));
-
- theme_cache.submenu = get_theme_icon(SNAME("submenu"));
- theme_cache.submenu_mirrored = get_theme_icon(SNAME("submenu_mirrored"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.font_separator = get_theme_font(SNAME("font_separator"));
- theme_cache.font_separator_size = get_theme_font_size(SNAME("font_separator_size"));
-
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_hover_color = get_theme_color(SNAME("font_hover_color"));
- theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
- theme_cache.font_accelerator_color = get_theme_color(SNAME("font_accelerator_color"));
- theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
-
- theme_cache.font_separator_color = get_theme_color(SNAME("font_separator_color"));
- theme_cache.font_separator_outline_size = get_theme_constant(SNAME("separator_outline_size"));
- theme_cache.font_separator_outline_color = get_theme_color(SNAME("font_separator_outline_color"));
-}
-
void PopupMenu::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -2206,6 +2161,8 @@ void PopupMenu::_get_property_list(List<PropertyInfo> *p_list) const {
}
void PopupMenu::_bind_methods() {
+ ClassDB::bind_method(D_METHOD("activate_item_by_event", "event", "for_global_only"), &PopupMenu::activate_item_by_event, DEFVAL(false));
+
ClassDB::bind_method(D_METHOD("add_item", "label", "id", "accel"), &PopupMenu::add_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_icon_item", "texture", "label", "id", "accel"), &PopupMenu::add_icon_item, DEFVAL(-1), DEFVAL(0));
ClassDB::bind_method(D_METHOD("add_check_item", "label", "id", "accel"), &PopupMenu::add_check_item, DEFVAL(-1), DEFVAL(0));
@@ -2308,6 +2265,48 @@ void PopupMenu::_bind_methods() {
ADD_SIGNAL(MethodInfo("id_focused", PropertyInfo(Variant::INT, "id")));
ADD_SIGNAL(MethodInfo("index_pressed", PropertyInfo(Variant::INT, "index")));
ADD_SIGNAL(MethodInfo("menu_changed"));
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, PopupMenu, panel_style, "panel");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, PopupMenu, hover_style, "hover");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, PopupMenu, separator_style, "separator");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, PopupMenu, labeled_separator_left);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, PopupMenu, labeled_separator_right);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, v_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, indent);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, item_start_padding);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, item_end_padding);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, PopupMenu, icon_max_width);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, checked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, checked_disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, unchecked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, unchecked_disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, radio_checked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, radio_checked_disabled);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, radio_unchecked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, radio_unchecked_disabled);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, submenu);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, PopupMenu, submenu_mirrored);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, PopupMenu, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, PopupMenu, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, PopupMenu, font_separator);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, PopupMenu, font_separator_size);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, PopupMenu, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, PopupMenu, font_hover_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, PopupMenu, font_disabled_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, PopupMenu, font_accelerator_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, PopupMenu, font_outline_size, "outline_size");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, PopupMenu, font_outline_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, PopupMenu, font_separator_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, PopupMenu, font_separator_outline_size, "separator_outline_size");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, PopupMenu, font_separator_outline_color);
}
void PopupMenu::popup(const Rect2i &p_bounds) {
diff --git a/scene/gui/popup_menu.h b/scene/gui/popup_menu.h
index ef754315f0..72a579b90a 100644
--- a/scene/gui/popup_menu.h
+++ b/scene/gui/popup_menu.h
@@ -190,10 +190,9 @@ class PopupMenu : public Popup {
void _menu_changed();
protected:
- virtual void _update_theme_item_cache() override;
-
virtual void add_child_notify(Node *p_child) override;
virtual void remove_child_notify(Node *p_child) override;
+
void _notification(int p_what);
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
diff --git a/scene/gui/progress_bar.cpp b/scene/gui/progress_bar.cpp
index 6a27637902..b45319422c 100644
--- a/scene/gui/progress_bar.cpp
+++ b/scene/gui/progress_bar.cpp
@@ -31,6 +31,7 @@
#include "progress_bar.h"
#include "scene/resources/text_line.h"
+#include "scene/theme/theme_db.h"
Size2 ProgressBar::get_minimum_size() const {
Size2 minimum_size = theme_cache.background_style->get_minimum_size();
@@ -47,19 +48,6 @@ Size2 ProgressBar::get_minimum_size() const {
return minimum_size;
}
-void ProgressBar::_update_theme_item_cache() {
- Range::_update_theme_item_cache();
-
- theme_cache.background_style = get_theme_stylebox(SNAME("background"));
- theme_cache.fill_style = get_theme_stylebox(SNAME("fill"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
-}
-
void ProgressBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -158,6 +146,15 @@ void ProgressBar::_bind_methods() {
BIND_ENUM_CONSTANT(FILL_END_TO_BEGIN);
BIND_ENUM_CONSTANT(FILL_TOP_TO_BOTTOM);
BIND_ENUM_CONSTANT(FILL_BOTTOM_TO_TOP);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ProgressBar, background_style, "background");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ProgressBar, fill_style, "fill");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, ProgressBar, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, ProgressBar, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ProgressBar, font_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, ProgressBar, font_outline_size, "outline_size");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, ProgressBar, font_outline_color);
}
ProgressBar::ProgressBar() {
diff --git a/scene/gui/progress_bar.h b/scene/gui/progress_bar.h
index d341cb813d..48daf8d610 100644
--- a/scene/gui/progress_bar.h
+++ b/scene/gui/progress_bar.h
@@ -50,8 +50,6 @@ class ProgressBar : public Range {
} theme_cache;
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/rich_text_label.cpp b/scene/gui/rich_text_label.cpp
index acf6f9d5aa..96e338544c 100644
--- a/scene/gui/rich_text_label.cpp
+++ b/scene/gui/rich_text_label.cpp
@@ -38,6 +38,7 @@
#include "scene/gui/label.h"
#include "scene/resources/atlas_texture.h"
#include "scene/scene_string_names.h"
+#include "scene/theme/theme_db.h"
#include "servers/display_server.h"
#include "modules/modules_enabled.gen.h" // For regex.
@@ -215,7 +216,7 @@ String RichTextLabel::_letters(int p_num, bool p_capitalize) const {
}
void RichTextLabel::_update_line_font(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size) {
- ERR_FAIL_COND(p_frame == nullptr);
+ ERR_FAIL_NULL(p_frame);
ERR_FAIL_COND(p_line < 0 || p_line >= (int)p_frame->lines.size());
Line &l = p_frame->lines[p_line];
@@ -266,7 +267,7 @@ void RichTextLabel::_update_line_font(ItemFrame *p_frame, int p_line, const Ref<
}
float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h) {
- ERR_FAIL_COND_V(p_frame == nullptr, p_h);
+ ERR_FAIL_NULL_V(p_frame, p_h);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), p_h);
Line &l = p_frame->lines[p_line];
@@ -447,7 +448,7 @@ float RichTextLabel::_resize_line(ItemFrame *p_frame, int p_line, const Ref<Font
}
float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font> &p_base_font, int p_base_font_size, int p_width, float p_h, int *r_char_offset) {
- ERR_FAIL_COND_V(p_frame == nullptr, p_h);
+ ERR_FAIL_NULL_V(p_frame, p_h);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), p_h);
Line &l = p_frame->lines[p_line];
@@ -747,7 +748,7 @@ float RichTextLabel::_shape_line(ItemFrame *p_frame, int p_line, const Ref<Font>
}
int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_ofs, int p_width, const Color &p_base_color, int p_outline_size, const Color &p_outline_color, const Color &p_font_shadow_color, int p_shadow_outline_size, const Point2 &p_shadow_ofs, int &r_processed_glyphs) {
- ERR_FAIL_COND_V(p_frame == nullptr, 0);
+ ERR_FAIL_NULL_V(p_frame, 0);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), 0);
Vector2 off;
@@ -967,7 +968,7 @@ int RichTextLabel::_draw_line(ItemFrame *p_frame, int p_line, const Vector2 &p_o
int gl_size = TS->shaped_text_get_glyph_count(rid);
Vector2 gloff = off;
- // Draw oulines and shadow.
+ // Draw outlines and shadow.
int processed_glyphs_ol = r_processed_glyphs;
for (int i = 0; i < gl_size; i++) {
Item *it = _get_item_at_pos(it_from, it_to, glyphs[i].start);
@@ -1744,43 +1745,8 @@ _FORCE_INLINE_ float RichTextLabel::_calculate_line_vertical_offset(const RichTe
void RichTextLabel::_update_theme_item_cache() {
Control::_update_theme_item_cache();
- theme_cache.normal_style = get_theme_stylebox(SNAME("normal"));
- theme_cache.focus_style = get_theme_stylebox(SNAME("focus"));
- theme_cache.progress_bg_style = get_theme_stylebox(SNAME("background"), SNAME("ProgressBar"));
- theme_cache.progress_fg_style = get_theme_stylebox(SNAME("fill"), SNAME("ProgressBar"));
-
- theme_cache.line_separation = get_theme_constant(SNAME("line_separation"));
-
- theme_cache.normal_font = get_theme_font(SNAME("normal_font"));
- theme_cache.normal_font_size = get_theme_font_size(SNAME("normal_font_size"));
-
- theme_cache.default_color = get_theme_color(SNAME("default_color"));
- theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
- use_selected_font_color = theme_cache.font_selected_color != Color(0, 0, 0, 0);
- theme_cache.selection_color = get_theme_color(SNAME("selection_color"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
- theme_cache.font_shadow_color = get_theme_color(SNAME("font_shadow_color"));
- theme_cache.shadow_outline_size = get_theme_constant(SNAME("shadow_outline_size"));
- theme_cache.shadow_offset_x = get_theme_constant(SNAME("shadow_offset_x"));
- theme_cache.shadow_offset_y = get_theme_constant(SNAME("shadow_offset_y"));
- theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
-
- theme_cache.bold_font = get_theme_font(SNAME("bold_font"));
- theme_cache.bold_font_size = get_theme_font_size(SNAME("bold_font_size"));
- theme_cache.bold_italics_font = get_theme_font(SNAME("bold_italics_font"));
- theme_cache.bold_italics_font_size = get_theme_font_size(SNAME("bold_italics_font_size"));
- theme_cache.italics_font = get_theme_font(SNAME("italics_font"));
- theme_cache.italics_font_size = get_theme_font_size(SNAME("italics_font_size"));
- theme_cache.mono_font = get_theme_font(SNAME("mono_font"));
- theme_cache.mono_font_size = get_theme_font_size(SNAME("mono_font_size"));
-
- theme_cache.table_h_separation = get_theme_constant(SNAME("table_h_separation"));
- theme_cache.table_v_separation = get_theme_constant(SNAME("table_v_separation"));
- theme_cache.table_odd_row_bg = get_theme_color(SNAME("table_odd_row_bg"));
- theme_cache.table_even_row_bg = get_theme_color(SNAME("table_even_row_bg"));
- theme_cache.table_border = get_theme_color(SNAME("table_border"));
-
theme_cache.base_scale = get_theme_default_base_scale();
+ use_selected_font_color = theme_cache.font_selected_color != Color(0, 0, 0, 0);
}
void RichTextLabel::_notification(int p_what) {
@@ -5059,7 +5025,7 @@ bool RichTextLabel::_search_table(ItemTable *p_table, List<Item *>::Element *p_f
}
bool RichTextLabel::_search_line(ItemFrame *p_frame, int p_line, const String &p_string, int p_char_idx, bool p_reverse_search) {
- ERR_FAIL_COND_V(p_frame == nullptr, false);
+ ERR_FAIL_NULL_V(p_frame, false);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), false);
Line &l = p_frame->lines[p_line];
@@ -5144,14 +5110,14 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
while (parent_element->get() != selection.from_frame) {
parent_element = p_search_previous ? parent_element->prev() : parent_element->next();
- ERR_FAIL_COND_V(parent_element == nullptr, false);
+ ERR_FAIL_NULL_V(parent_element, false);
}
// Search remainder of table
if (!(p_search_previous && parent_element == parent_table->subitems.front()) &&
parent_element != parent_table->subitems.back()) {
parent_element = p_search_previous ? parent_element->prev() : parent_element->next(); // Don't want to search current item
- ERR_FAIL_COND_V(parent_element == nullptr, false);
+ ERR_FAIL_NULL_V(parent_element, false);
// Search for next element
if (_search_table(parent_table, parent_element, p_string, p_search_previous)) {
@@ -5200,7 +5166,7 @@ bool RichTextLabel::search(const String &p_string, bool p_from_selection, bool p
String RichTextLabel::_get_line_text(ItemFrame *p_frame, int p_line, Selection p_selection) const {
String txt;
- ERR_FAIL_COND_V(p_frame == nullptr, txt);
+ ERR_FAIL_NULL_V(p_frame, txt);
ERR_FAIL_COND_V(p_line < 0 || p_line >= (int)p_frame->lines.size(), txt);
Line &l = p_frame->lines[p_line];
@@ -5821,6 +5787,44 @@ void RichTextLabel::_bind_methods() {
BIND_ENUM_CONSTANT(MENU_COPY);
BIND_ENUM_CONSTANT(MENU_SELECT_ALL);
BIND_ENUM_CONSTANT(MENU_MAX);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, RichTextLabel, normal_style, "normal");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, RichTextLabel, focus_style, "focus");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, RichTextLabel, progress_bg_style, "background", "ProgressBar");
+ BIND_THEME_ITEM_EXT(Theme::DATA_TYPE_STYLEBOX, RichTextLabel, progress_fg_style, "fill", "ProgressBar");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, line_separation);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, RichTextLabel, normal_font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, RichTextLabel, normal_font_size);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, default_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, font_selected_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, selection_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, font_outline_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, font_shadow_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, shadow_outline_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, shadow_offset_x);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, shadow_offset_y);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, outline_size);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, RichTextLabel, bold_font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, RichTextLabel, bold_font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, RichTextLabel, bold_italics_font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, RichTextLabel, bold_italics_font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, RichTextLabel, italics_font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, RichTextLabel, italics_font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, RichTextLabel, mono_font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, RichTextLabel, mono_font_size);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, text_highlight_h_padding);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, text_highlight_v_padding);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, table_h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, RichTextLabel, table_v_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, table_odd_row_bg);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, table_even_row_bg);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, RichTextLabel, table_border);
}
TextServer::VisibleCharactersBehavior RichTextLabel::get_visible_characters_behavior() const {
@@ -6028,8 +6032,6 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
Vector2i fbg_index = Vector2i(end, start);
Color last_color = Color(0, 0, 0, 0);
bool draw_box = false;
- int hpad = get_theme_constant(SNAME("text_highlight_h_padding"));
- int vpad = get_theme_constant(SNAME("text_highlight_v_padding"));
// Draw a box based on color tags associated with glyphs
for (int i = start; i < end; i++) {
Item *it = _get_item_at_pos(it_from, it_to, i);
@@ -6059,8 +6061,8 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
if (draw_box) {
Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, fbg_index.y);
for (int j = 0; j < sel.size(); j++) {
- Vector2 rect_off = line_off + Vector2(sel[j].x - hpad, -TS->shaped_text_get_ascent(p_rid) - vpad);
- Vector2 rect_size = Vector2(sel[j].y - sel[j].x + 2 * hpad, TS->shaped_text_get_size(p_rid).y + 2 * vpad);
+ Vector2 rect_off = line_off + Vector2(sel[j].x - theme_cache.text_highlight_h_padding, -TS->shaped_text_get_ascent(p_rid) - theme_cache.text_highlight_v_padding);
+ Vector2 rect_size = Vector2(sel[j].y - sel[j].x + 2 * theme_cache.text_highlight_h_padding, TS->shaped_text_get_size(p_rid).y + 2 * theme_cache.text_highlight_v_padding);
RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color);
}
fbg_index = Vector2i(end, start);
@@ -6078,8 +6080,8 @@ void RichTextLabel::_draw_fbg_boxes(RID p_ci, RID p_rid, Vector2 line_off, Item
if (last_color.a > 0) {
Vector<Vector2> sel = TS->shaped_text_get_selection(p_rid, fbg_index.x, end);
for (int i = 0; i < sel.size(); i++) {
- Vector2 rect_off = line_off + Vector2(sel[i].x - hpad, -TS->shaped_text_get_ascent(p_rid) - vpad);
- Vector2 rect_size = Vector2(sel[i].y - sel[i].x + 2 * hpad, TS->shaped_text_get_size(p_rid).y + 2 * vpad);
+ Vector2 rect_off = line_off + Vector2(sel[i].x - theme_cache.text_highlight_h_padding, -TS->shaped_text_get_ascent(p_rid) - theme_cache.text_highlight_v_padding);
+ Vector2 rect_size = Vector2(sel[i].y - sel[i].x + 2 * theme_cache.text_highlight_h_padding, TS->shaped_text_get_size(p_rid).y + 2 * theme_cache.text_highlight_v_padding);
RenderingServer::get_singleton()->canvas_item_add_rect(p_ci, Rect2(rect_off, rect_size), last_color);
}
}
diff --git a/scene/gui/rich_text_label.h b/scene/gui/rich_text_label.h
index a3230cf13c..d88623073d 100644
--- a/scene/gui/rich_text_label.h
+++ b/scene/gui/rich_text_label.h
@@ -98,6 +98,7 @@ public:
protected:
virtual void _update_theme_item_cache() override;
+
void _notification(int p_what);
static void _bind_methods();
@@ -591,6 +592,9 @@ private:
Ref<Font> mono_font;
int mono_font_size;
+ int text_highlight_h_padding;
+ int text_highlight_v_padding;
+
int table_h_separation;
int table_v_separation;
Color table_odd_row_bg;
diff --git a/scene/gui/scroll_bar.cpp b/scene/gui/scroll_bar.cpp
index 06b3882d25..2931b5be91 100644
--- a/scene/gui/scroll_bar.cpp
+++ b/scene/gui/scroll_bar.cpp
@@ -34,6 +34,7 @@
#include "core/os/os.h"
#include "core/string/print_string.h"
#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
bool ScrollBar::focus_by_default = false;
@@ -221,24 +222,6 @@ void ScrollBar::gui_input(const Ref<InputEvent> &p_event) {
}
}
-void ScrollBar::_update_theme_item_cache() {
- Range::_update_theme_item_cache();
-
- theme_cache.scroll_style = get_theme_stylebox(SNAME("scroll"));
- theme_cache.scroll_focus_style = get_theme_stylebox(SNAME("scroll_focus"));
- theme_cache.scroll_offset_style = get_theme_stylebox(SNAME("hscroll"));
- theme_cache.grabber_style = get_theme_stylebox(SNAME("grabber"));
- theme_cache.grabber_hl_style = get_theme_stylebox(SNAME("grabber_highlight"));
- theme_cache.grabber_pressed_style = get_theme_stylebox(SNAME("grabber_pressed"));
-
- theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
- theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
- theme_cache.increment_pressed_icon = get_theme_icon(SNAME("increment_pressed"));
- theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
- theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
- theme_cache.decrement_pressed_icon = get_theme_icon(SNAME("decrement_pressed"));
-}
-
void ScrollBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -653,6 +636,20 @@ void ScrollBar::_bind_methods() {
ADD_SIGNAL(MethodInfo("scrolling"));
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_step", PROPERTY_HINT_RANGE, "-1,4096,suffix:px"), "set_custom_step", "get_custom_step");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollBar, scroll_style, "scroll");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollBar, scroll_focus_style, "scroll_focus");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollBar, scroll_offset_style, "hscroll");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollBar, grabber_style, "grabber");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollBar, grabber_hl_style, "grabber_highlight");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollBar, grabber_pressed_style, "grabber_pressed");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ScrollBar, increment_icon, "increment");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ScrollBar, increment_hl_icon, "increment_highlight");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ScrollBar, increment_pressed_icon, "increment_pressed");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ScrollBar, decrement_icon, "decrement");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ScrollBar, decrement_hl_icon, "decrement_highlight");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, ScrollBar, decrement_pressed_icon, "decrement_pressed");
}
ScrollBar::ScrollBar(Orientation p_orientation) {
diff --git a/scene/gui/scroll_bar.h b/scene/gui/scroll_bar.h
index ceef75cdf2..aacf2060b8 100644
--- a/scene/gui/scroll_bar.h
+++ b/scene/gui/scroll_bar.h
@@ -108,8 +108,6 @@ class ScrollBar : public Range {
virtual void gui_input(const Ref<InputEvent> &p_event) override;
protected:
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/scroll_container.cpp b/scene/gui/scroll_container.cpp
index 85dd73beeb..b4e28a1f1b 100644
--- a/scene/gui/scroll_container.cpp
+++ b/scene/gui/scroll_container.cpp
@@ -33,6 +33,7 @@
#include "core/config/project_settings.h"
#include "core/os/os.h"
#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
Size2 ScrollContainer::get_minimum_size() const {
Size2 min_size;
@@ -80,12 +81,6 @@ Size2 ScrollContainer::get_minimum_size() const {
return min_size;
}
-void ScrollContainer::_update_theme_item_cache() {
- Container::_update_theme_item_cache();
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
-}
-
void ScrollContainer::_cancel_drag() {
set_physics_process_internal(false);
drag_touching_deaccel = false;
@@ -356,7 +351,7 @@ void ScrollContainer::_notification(int p_what) {
case NOTIFICATION_READY: {
Viewport *viewport = get_viewport();
- ERR_FAIL_COND(!viewport);
+ ERR_FAIL_NULL(viewport);
viewport->connect("gui_focus_changed", callable_mp(this, &ScrollContainer::_gui_focus_changed));
_reposition_children();
} break;
@@ -627,6 +622,8 @@ void ScrollContainer::_bind_methods() {
BIND_ENUM_CONSTANT(SCROLL_MODE_SHOW_ALWAYS);
BIND_ENUM_CONSTANT(SCROLL_MODE_SHOW_NEVER);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, ScrollContainer, panel_style, "panel");
+
GLOBAL_DEF("gui/common/default_scroll_deadzone", 0);
};
diff --git a/scene/gui/scroll_container.h b/scene/gui/scroll_container.h
index dbd1b3904a..02146618cd 100644
--- a/scene/gui/scroll_container.h
+++ b/scene/gui/scroll_container.h
@@ -76,18 +76,17 @@ private:
void _cancel_drag();
protected:
- virtual void _update_theme_item_cache() override;
Size2 get_minimum_size() const override;
void _gui_focus_changed(Control *p_control);
void _reposition_children();
- void _notification(int p_what);
- void _scroll_moved(float);
+ void _notification(int p_what);
static void _bind_methods();
bool _updating_scrollbars = false;
void _update_scrollbar_position();
+ void _scroll_moved(float);
public:
virtual void gui_input(const Ref<InputEvent> &p_gui_input) override;
diff --git a/scene/gui/separator.cpp b/scene/gui/separator.cpp
index b0879c1931..d0ca7c2e86 100644
--- a/scene/gui/separator.cpp
+++ b/scene/gui/separator.cpp
@@ -30,6 +30,8 @@
#include "separator.h"
+#include "scene/theme/theme_db.h"
+
Size2 Separator::get_minimum_size() const {
Size2 ms(3, 3);
if (orientation == VERTICAL) {
@@ -40,13 +42,6 @@ Size2 Separator::get_minimum_size() const {
return ms;
}
-void Separator::_update_theme_item_cache() {
- Control::_update_theme_item_cache();
-
- theme_cache.separation = get_theme_constant(SNAME("separation"));
- theme_cache.separator_style = get_theme_stylebox(SNAME("separator"));
-}
-
void Separator::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -62,6 +57,11 @@ void Separator::_notification(int p_what) {
}
}
+void Separator::_bind_methods() {
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Separator, separation);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Separator, separator_style, "separator");
+}
+
Separator::Separator() {
}
diff --git a/scene/gui/separator.h b/scene/gui/separator.h
index 9bca65f3da..7c973604ac 100644
--- a/scene/gui/separator.h
+++ b/scene/gui/separator.h
@@ -43,9 +43,8 @@ class Separator : public Control {
protected:
Orientation orientation = Orientation::HORIZONTAL;
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
+ static void _bind_methods();
public:
virtual Size2 get_minimum_size() const override;
diff --git a/scene/gui/slider.cpp b/scene/gui/slider.cpp
index 398f637e85..b1a2f8017e 100644
--- a/scene/gui/slider.cpp
+++ b/scene/gui/slider.cpp
@@ -31,6 +31,7 @@
#include "slider.h"
#include "core/os/keyboard.h"
+#include "scene/theme/theme_db.h"
Size2 Slider::get_minimum_size() const {
Size2i ss = theme_cache.slider_style->get_minimum_size();
@@ -176,22 +177,6 @@ void Slider::gui_input(const Ref<InputEvent> &p_event) {
}
}
-void Slider::_update_theme_item_cache() {
- Range::_update_theme_item_cache();
-
- theme_cache.slider_style = get_theme_stylebox(SNAME("slider"));
- theme_cache.grabber_area_style = get_theme_stylebox(SNAME("grabber_area"));
- theme_cache.grabber_area_hl_style = get_theme_stylebox(SNAME("grabber_area_highlight"));
-
- theme_cache.grabber_icon = get_theme_icon(SNAME("grabber"));
- theme_cache.grabber_hl_icon = get_theme_icon(SNAME("grabber_highlight"));
- theme_cache.grabber_disabled_icon = get_theme_icon(SNAME("grabber_disabled"));
- theme_cache.tick_icon = get_theme_icon(SNAME("tick"));
-
- theme_cache.center_grabber = get_theme_constant(SNAME("center_grabber"));
- theme_cache.grabber_offset = get_theme_constant(SNAME("grabber_offset"));
-}
-
void Slider::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_INTERNAL_PROCESS: {
@@ -392,6 +377,18 @@ void Slider::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "scrollable"), "set_scrollable", "is_scrollable");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tick_count", PROPERTY_HINT_RANGE, "0,4096,1"), "set_ticks", "get_ticks");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ticks_on_borders"), "set_ticks_on_borders", "get_ticks_on_borders");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Slider, slider_style, "slider");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Slider, grabber_area_style, "grabber_area");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Slider, grabber_area_hl_style, "grabber_area_highlight");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, Slider, grabber_icon, "grabber");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, Slider, grabber_hl_icon, "grabber_highlight");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, Slider, grabber_disabled_icon, "grabber_disabled");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, Slider, tick_icon, "tick");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Slider, center_grabber);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Slider, grabber_offset);
}
Slider::Slider(Orientation p_orientation) {
diff --git a/scene/gui/slider.h b/scene/gui/slider.h
index 6d513b8b27..05766fa742 100644
--- a/scene/gui/slider.h
+++ b/scene/gui/slider.h
@@ -71,7 +71,6 @@ protected:
bool ticks_on_borders = false;
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
static void _bind_methods();
diff --git a/scene/gui/spin_box.cpp b/scene/gui/spin_box.cpp
index 4af694ae3d..07429c6a61 100644
--- a/scene/gui/spin_box.cpp
+++ b/scene/gui/spin_box.cpp
@@ -32,6 +32,7 @@
#include "core/input/input.h"
#include "core/math/expression.h"
+#include "scene/theme/theme_db.h"
Size2 SpinBox::get_minimum_size() const {
Size2 ms = line_edit->get_combined_minimum_size();
@@ -65,6 +66,7 @@ void SpinBox::_text_submitted(const String &p_string) {
// Ignore the prefix and suffix in the expression.
Error err = expr->parse(num.trim_prefix(prefix + " ").trim_suffix(" " + suffix));
if (err != OK) {
+ _update_text();
return;
}
@@ -228,12 +230,6 @@ inline void SpinBox::_adjust_width_for_icon(const Ref<Texture2D> &icon) {
}
}
-void SpinBox::_update_theme_item_cache() {
- Range::_update_theme_item_cache();
-
- theme_cache.updown_icon = get_theme_icon(SNAME("updown"));
-}
-
void SpinBox::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_DRAW: {
@@ -379,6 +375,8 @@ void SpinBox::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::STRING, "suffix"), "set_suffix", "get_suffix");
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "custom_arrow_step", PROPERTY_HINT_RANGE, "0,10000,0.0001,or_greater"), "set_custom_arrow_step", "get_custom_arrow_step");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "select_all_on_focus"), "set_select_all_on_focus", "is_select_all_on_focus");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SpinBox, updown_icon, "updown");
}
SpinBox::SpinBox() {
diff --git a/scene/gui/spin_box.h b/scene/gui/spin_box.h
index 29b278c50e..bbb1db637a 100644
--- a/scene/gui/spin_box.h
+++ b/scene/gui/spin_box.h
@@ -76,9 +76,7 @@ class SpinBox : public Range {
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
-
static void _bind_methods();
public:
diff --git a/scene/gui/split_container.cpp b/scene/gui/split_container.cpp
index 0c0125df76..06b32b548f 100644
--- a/scene/gui/split_container.cpp
+++ b/scene/gui/split_container.cpp
@@ -30,8 +30,9 @@
#include "split_container.h"
-#include "label.h"
-#include "margin_container.h"
+#include "scene/gui/label.h"
+#include "scene/gui/margin_container.h"
+#include "scene/theme/theme_db.h"
void SplitContainerDragger::gui_input(const Ref<InputEvent> &p_event) {
ERR_FAIL_COND(p_event.is_null());
@@ -96,7 +97,7 @@ void SplitContainerDragger::_notification(int p_what) {
case NOTIFICATION_MOUSE_ENTER: {
mouse_inside = true;
SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->get_theme_constant(SNAME("autohide"))) {
+ if (sc->theme_cache.autohide) {
queue_redraw();
}
} break;
@@ -104,14 +105,14 @@ void SplitContainerDragger::_notification(int p_what) {
case NOTIFICATION_MOUSE_EXIT: {
mouse_inside = false;
SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (sc->get_theme_constant(SNAME("autohide"))) {
+ if (sc->theme_cache.autohide) {
queue_redraw();
}
} break;
case NOTIFICATION_DRAW: {
SplitContainer *sc = Object::cast_to<SplitContainer>(get_parent());
- if (!dragging && !mouse_inside && sc->get_theme_constant(SNAME("autohide"))) {
+ if (!dragging && !mouse_inside && sc->theme_cache.autohide) {
return;
}
@@ -292,17 +293,6 @@ void SplitContainer::_validate_property(PropertyInfo &p_property) const {
}
}
-void SplitContainer::_update_theme_item_cache() {
- Container::_update_theme_item_cache();
-
- theme_cache.separation = get_theme_constant(SNAME("separation"));
- theme_cache.minimum_grab_thickness = get_theme_constant(SNAME("minimum_grab_thickness"));
- theme_cache.autohide = get_theme_constant(SNAME("autohide"));
- theme_cache.grabber_icon = get_theme_icon(SNAME("grabber"));
- theme_cache.grabber_icon_h = get_theme_icon(SNAME("h_grabber"));
- theme_cache.grabber_icon_v = get_theme_icon(SNAME("v_grabber"));
-}
-
void SplitContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_TRANSLATION_CHANGED:
@@ -428,6 +418,13 @@ void SplitContainer::_bind_methods() {
BIND_ENUM_CONSTANT(DRAGGER_VISIBLE);
BIND_ENUM_CONSTANT(DRAGGER_HIDDEN);
BIND_ENUM_CONSTANT(DRAGGER_HIDDEN_COLLAPSED);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, minimum_grab_thickness);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, SplitContainer, autohide);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon, "grabber");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon_h, "h_grabber");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, SplitContainer, grabber_icon_v, "v_grabber");
}
SplitContainer::SplitContainer(bool p_vertical) {
diff --git a/scene/gui/split_container.h b/scene/gui/split_container.h
index 15a47d9596..f008d2678b 100644
--- a/scene/gui/split_container.h
+++ b/scene/gui/split_container.h
@@ -73,7 +73,7 @@ private:
struct ThemeCache {
int separation = 0;
int minimum_grab_thickness = 0;
- int autohide = 0;
+ bool autohide = false;
Ref<Texture2D> grabber_icon;
Ref<Texture2D> grabber_icon_h;
Ref<Texture2D> grabber_icon_v;
@@ -85,13 +85,9 @@ private:
void _compute_middle_sep(bool p_clamp);
void _resort();
- void _dragging_area_gui_input(const Ref<InputEvent> &p_event);
-
protected:
bool is_fixed = false;
- virtual void _update_theme_item_cache() override;
-
void _notification(int p_what);
void _validate_property(PropertyInfo &p_property) const;
static void _bind_methods();
diff --git a/scene/gui/tab_bar.cpp b/scene/gui/tab_bar.cpp
index 959a51eff9..a9c16a9942 100644
--- a/scene/gui/tab_bar.cpp
+++ b/scene/gui/tab_bar.cpp
@@ -36,6 +36,7 @@
#include "scene/gui/label.h"
#include "scene/gui/texture_rect.h"
#include "scene/main/viewport.h"
+#include "scene/theme/theme_db.h"
Size2 TabBar::get_minimum_size() const {
Size2 ms;
@@ -304,39 +305,6 @@ void TabBar::_shape(int p_tab) {
tabs.write[p_tab].text_buf->add_string(tabs[p_tab].xl_text, theme_cache.font, theme_cache.font_size, tabs[p_tab].language);
}
-void TabBar::_update_theme_item_cache() {
- Control::_update_theme_item_cache();
-
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
-
- theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected"));
- theme_cache.tab_hovered_style = get_theme_stylebox(SNAME("tab_hovered"));
- theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected"));
- theme_cache.tab_disabled_style = get_theme_stylebox(SNAME("tab_disabled"));
-
- theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
- theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
- theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
- theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
- theme_cache.drop_mark_icon = get_theme_icon(SNAME("drop_mark"));
- theme_cache.drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
-
- theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
- theme_cache.font_hovered_color = get_theme_color(SNAME("font_hovered_color"));
- theme_cache.font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
- theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
-
- theme_cache.close_icon = get_theme_icon(SNAME("close"));
- theme_cache.button_pressed_style = get_theme_stylebox(SNAME("button_pressed"));
- theme_cache.button_hl_style = get_theme_stylebox(SNAME("button_highlight"));
-}
-
void TabBar::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED: {
@@ -1698,6 +1666,35 @@ void TabBar::_bind_methods() {
BIND_ENUM_CONSTANT(CLOSE_BUTTON_SHOW_ACTIVE_ONLY);
BIND_ENUM_CONSTANT(CLOSE_BUTTON_SHOW_ALWAYS);
BIND_ENUM_CONSTANT(CLOSE_BUTTON_MAX);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabBar, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabBar, icon_max_width);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, tab_unselected_style, "tab_unselected");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, tab_hovered_style, "tab_hovered");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, tab_selected_style, "tab_selected");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, tab_disabled_style, "tab_disabled");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabBar, increment_icon, "increment");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabBar, increment_hl_icon, "increment_highlight");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabBar, decrement_icon, "decrement");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabBar, decrement_hl_icon, "decrement_highlight");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabBar, drop_mark_icon, "drop_mark");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabBar, drop_mark_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabBar, font_selected_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabBar, font_hovered_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabBar, font_unselected_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabBar, font_disabled_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabBar, font_outline_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, TabBar, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, TabBar, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabBar, outline_size);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabBar, close_icon, "close");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, button_pressed_style, "button_pressed");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabBar, button_hl_style, "button_highlight");
}
TabBar::TabBar() {
diff --git a/scene/gui/tab_bar.h b/scene/gui/tab_bar.h
index 438b6c60b5..d89b1866bf 100644
--- a/scene/gui/tab_bar.h
+++ b/scene/gui/tab_bar.h
@@ -152,7 +152,7 @@ private:
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- virtual void _update_theme_item_cache() override;
+
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;
diff --git a/scene/gui/tab_container.cpp b/scene/gui/tab_container.cpp
index 28bf58ca04..14bc87ad40 100644
--- a/scene/gui/tab_container.cpp
+++ b/scene/gui/tab_container.cpp
@@ -33,6 +33,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/label.h"
#include "scene/gui/texture_rect.h"
+#include "scene/theme/theme_db.h"
int TabContainer::_get_top_margin() const {
int height = 0;
@@ -133,44 +134,6 @@ void TabContainer::gui_input(const Ref<InputEvent> &p_event) {
}
}
-void TabContainer::_update_theme_item_cache() {
- Container::_update_theme_item_cache();
-
- theme_cache.side_margin = get_theme_constant(SNAME("side_margin"));
-
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
- theme_cache.tabbar_style = get_theme_stylebox(SNAME("tabbar_background"));
-
- theme_cache.menu_icon = get_theme_icon(SNAME("menu"));
- theme_cache.menu_hl_icon = get_theme_icon(SNAME("menu_highlight"));
-
- // TabBar overrides.
- theme_cache.icon_separation = get_theme_constant(SNAME("icon_separation"));
- theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
- theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
-
- theme_cache.tab_unselected_style = get_theme_stylebox(SNAME("tab_unselected"));
- theme_cache.tab_hovered_style = get_theme_stylebox(SNAME("tab_hovered"));
- theme_cache.tab_selected_style = get_theme_stylebox(SNAME("tab_selected"));
- theme_cache.tab_disabled_style = get_theme_stylebox(SNAME("tab_disabled"));
-
- theme_cache.increment_icon = get_theme_icon(SNAME("increment"));
- theme_cache.increment_hl_icon = get_theme_icon(SNAME("increment_highlight"));
- theme_cache.decrement_icon = get_theme_icon(SNAME("decrement"));
- theme_cache.decrement_hl_icon = get_theme_icon(SNAME("decrement_highlight"));
- theme_cache.drop_mark_icon = get_theme_icon(SNAME("drop_mark"));
- theme_cache.drop_mark_color = get_theme_color(SNAME("drop_mark_color"));
-
- theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
- theme_cache.font_hovered_color = get_theme_color(SNAME("font_hovered_color"));
- theme_cache.font_unselected_color = get_theme_color(SNAME("font_unselected_color"));
- theme_cache.font_disabled_color = get_theme_color(SNAME("font_disabled_color"));
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
-
- theme_cache.tab_font = get_theme_font(SNAME("font"));
- theme_cache.tab_font_size = get_theme_font_size(SNAME("font_size"));
-}
-
void TabContainer::_notification(int p_what) {
switch (p_what) {
case NOTIFICATION_ENTER_TREE: {
@@ -218,7 +181,7 @@ void TabContainer::_notification(int p_what) {
case NOTIFICATION_LAYOUT_DIRECTION_CHANGED:
case NOTIFICATION_THEME_CHANGED: {
theme_changing = true;
- call_deferred(SNAME("_on_theme_changed")); // Wait until all changed theme.
+ callable_mp(this, &TabContainer::_on_theme_changed).call_deferred(); // Wait until all changed theme.
} break;
}
}
@@ -511,14 +474,14 @@ void TabContainer::_on_tab_hovered(int p_tab) {
}
void TabContainer::_on_tab_changed(int p_tab) {
- call_deferred(SNAME("_repaint"));
+ callable_mp(this, &TabContainer::_repaint).call_deferred();
emit_signal(SNAME("tab_changed"), p_tab);
}
void TabContainer::_on_tab_selected(int p_tab) {
if (p_tab != get_previous_tab()) {
- call_deferred(SNAME("_repaint"));
+ callable_mp(this, &TabContainer::_repaint).call_deferred();
}
emit_signal(SNAME("tab_selected"), p_tab);
@@ -561,7 +524,7 @@ void TabContainer::add_child_notify(Node *p_child) {
// TabBar won't emit the "tab_changed" signal when not inside the tree.
if (!is_inside_tree()) {
- call_deferred("_repaint");
+ callable_mp(this, &TabContainer::_repaint).call_deferred();
}
}
@@ -618,7 +581,7 @@ void TabContainer::remove_child_notify(Node *p_child) {
// TabBar won't emit the "tab_changed" signal when not inside the tree.
if (!is_inside_tree()) {
- call_deferred("_repaint");
+ callable_mp(this, &TabContainer::_repaint).call_deferred();
}
}
@@ -804,7 +767,7 @@ void TabContainer::set_tab_hidden(int p_tab, bool p_hidden) {
if (!get_clip_tabs()) {
update_minimum_size();
}
- call_deferred(SNAME("_repaint"));
+ callable_mp(this, &TabContainer::_repaint).call_deferred();
}
bool TabContainer::is_tab_hidden(int p_tab) const {
@@ -981,9 +944,6 @@ void TabContainer::_bind_methods() {
ClassDB::bind_method(D_METHOD("set_use_hidden_tabs_for_min_size", "enabled"), &TabContainer::set_use_hidden_tabs_for_min_size);
ClassDB::bind_method(D_METHOD("get_use_hidden_tabs_for_min_size"), &TabContainer::get_use_hidden_tabs_for_min_size);
- ClassDB::bind_method(D_METHOD("_repaint"), &TabContainer::_repaint);
- ClassDB::bind_method(D_METHOD("_on_theme_changed"), &TabContainer::_on_theme_changed);
-
ADD_SIGNAL(MethodInfo("active_tab_rearranged", PropertyInfo(Variant::INT, "idx_to")));
ADD_SIGNAL(MethodInfo("tab_changed", PropertyInfo(Variant::INT, "tab")));
ADD_SIGNAL(MethodInfo("tab_clicked", PropertyInfo(Variant::INT, "tab")));
@@ -1000,6 +960,40 @@ void TabContainer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "drag_to_rearrange_enabled"), "set_drag_to_rearrange_enabled", "get_drag_to_rearrange_enabled");
ADD_PROPERTY(PropertyInfo(Variant::INT, "tabs_rearrange_group"), "set_tabs_rearrange_group", "get_tabs_rearrange_group");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "use_hidden_tabs_for_min_size"), "set_use_hidden_tabs_for_min_size", "get_use_hidden_tabs_for_min_size");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabContainer, side_margin);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabContainer, panel_style, "panel");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabContainer, tabbar_style, "tabbar_background");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabContainer, menu_icon, "menu");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabContainer, menu_hl_icon, "menu_highlight");
+
+ // TabBar overrides.
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabContainer, icon_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabContainer, icon_max_width);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabContainer, tab_unselected_style, "tab_unselected");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabContainer, tab_hovered_style, "tab_hovered");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabContainer, tab_selected_style, "tab_selected");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TabContainer, tab_disabled_style, "tab_disabled");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabContainer, increment_icon, "increment");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabContainer, increment_hl_icon, "increment_highlight");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabContainer, decrement_icon, "decrement");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabContainer, decrement_hl_icon, "decrement_highlight");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TabContainer, drop_mark_icon, "drop_mark");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabContainer, drop_mark_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabContainer, font_selected_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabContainer, font_hovered_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabContainer, font_unselected_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabContainer, font_disabled_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TabContainer, font_outline_color);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_FONT, TabContainer, tab_font, "font");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_FONT_SIZE, TabContainer, tab_font_size, "font_size");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TabContainer, outline_size);
}
TabContainer::TabContainer() {
diff --git a/scene/gui/tab_container.h b/scene/gui/tab_container.h
index c7a218c290..2bcc640d05 100644
--- a/scene/gui/tab_container.h
+++ b/scene/gui/tab_container.h
@@ -103,7 +103,6 @@ class TabContainer : public Container {
protected:
virtual void gui_input(const Ref<InputEvent> &p_event) override;
- virtual void _update_theme_item_cache() override;
void _notification(int p_what);
virtual void add_child_notify(Node *p_child) override;
diff --git a/scene/gui/text_edit.cpp b/scene/gui/text_edit.cpp
index 1d5cee61a3..9e159cd303 100644
--- a/scene/gui/text_edit.cpp
+++ b/scene/gui/text_edit.cpp
@@ -39,9 +39,9 @@
#include "core/os/os.h"
#include "core/string/string_builder.h"
#include "core/string/translation.h"
-#include "label.h"
-
+#include "scene/gui/label.h"
#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
///////////////////////////////////////////////////////////////////////////////
/// TEXT ///
@@ -1254,7 +1254,7 @@ void TextEdit::_notification(int p_what) {
if ((brace_matching[c].open_match_line == line && brace_matching[c].open_match_column == glyphs[j].start) ||
(get_caret_column(c) == glyphs[j].start && get_caret_line(c) == line && carets_wrap_index[c] == line_wrap_index && (brace_matching[c].open_matching || brace_matching[c].open_mismatch))) {
if (brace_matching[c].open_mismatch) {
- gl_color = theme_cache.brace_mismatch_color;
+ gl_color = _get_brace_mismatch_color();
}
Rect2 rect = Rect2(char_pos, ofs_y + theme_cache.font->get_underline_position(theme_cache.font_size), glyphs[j].advance * glyphs[j].repeat, MAX(theme_cache.font->get_underline_thickness(theme_cache.font_size) * theme_cache.base_scale, 1));
draw_rect(rect, gl_color);
@@ -1263,7 +1263,7 @@ void TextEdit::_notification(int p_what) {
if ((brace_matching[c].close_match_line == line && brace_matching[c].close_match_column == glyphs[j].start) ||
(get_caret_column(c) == glyphs[j].start + 1 && get_caret_line(c) == line && carets_wrap_index[c] == line_wrap_index && (brace_matching[c].close_matching || brace_matching[c].close_mismatch))) {
if (brace_matching[c].close_mismatch) {
- gl_color = theme_cache.brace_mismatch_color;
+ gl_color = _get_brace_mismatch_color();
}
Rect2 rect = Rect2(char_pos, ofs_y + theme_cache.font->get_underline_position(theme_cache.font_size), glyphs[j].advance * glyphs[j].repeat, MAX(theme_cache.font->get_underline_thickness(theme_cache.font_size) * theme_cache.base_scale, 1));
draw_rect(rect, gl_color);
@@ -1298,7 +1298,8 @@ void TextEdit::_notification(int p_what) {
if (had_glyphs_drawn) {
if (first_visible_char > glyphs[j].start) {
first_visible_char = glyphs[j].start;
- } else if (last_visible_char < glyphs[j].end) {
+ }
+ if (last_visible_char < glyphs[j].end) {
last_visible_char = glyphs[j].end;
}
}
@@ -1313,12 +1314,12 @@ void TextEdit::_notification(int p_what) {
// is_line_folded
if (line_wrap_index == line_wrap_amount && line < text.size() - 1 && _is_line_hidden(line + 1)) {
- int xofs = char_ofs + char_margin + ofs_x + (theme_cache.folded_eol_icon->get_width() / 2);
+ int xofs = char_ofs + char_margin + ofs_x + (_get_folded_eol_icon()->get_width() / 2);
if (xofs >= xmargin_beg && xofs < xmargin_end) {
- int yofs = (text_height - theme_cache.folded_eol_icon->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
- Color eol_color = theme_cache.code_folding_color;
+ int yofs = (text_height - _get_folded_eol_icon()->get_height()) / 2 - ldata->get_line_ascent(line_wrap_index);
+ Color eol_color = _get_code_folding_color();
eol_color.a = 1;
- theme_cache.folded_eol_icon->draw(ci, Point2(xofs, ofs_y + yofs), eol_color);
+ _get_folded_eol_icon()->draw(ci, Point2(xofs, ofs_y + yofs), eol_color);
}
}
@@ -1597,7 +1598,7 @@ void TextEdit::_notification(int p_what) {
if (is_drag_successful()) {
if (selection_drag_attempt) {
selection_drag_attempt = false;
- if (is_editable() && !Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (is_editable() && !Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
delete_selection();
} else if (deselect_on_focus_loss_enabled) {
deselect();
@@ -1752,11 +1753,27 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
const int triple_click_tolerance = 5;
bool is_triple_click = (!mb->is_double_click() && (OS::get_singleton()->get_ticks_msec() - last_dblclk) < triple_click_timeout && mb->get_position().distance_to(last_dblclk_pos) < triple_click_tolerance);
- if (!is_mouse_over_selection() && !mb->is_double_click() && !is_triple_click) {
+ if (!mb->is_double_click() && !is_triple_click) {
if (mb->is_alt_pressed()) {
prev_line = row;
prev_col = col;
+ // Remove caret at clicked location.
+ if (carets.size() > 1) {
+ for (int i = 0; i < carets.size(); i++) {
+ // Deselect if clicked on caret or its selection.
+ if ((get_caret_column(i) == col && get_caret_line(i) == row) || is_mouse_over_selection(true, i)) {
+ remove_caret(i);
+ last_dblclk = 0;
+ return;
+ }
+ }
+ }
+
+ if (is_mouse_over_selection()) {
+ return;
+ }
+
caret = add_caret(row, col);
if (caret == -1) {
return;
@@ -1766,7 +1783,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
carets.write[caret].selection.selecting_column = col;
last_dblclk = 0;
- } else if (!mb->is_shift_pressed()) {
+ } else if (!mb->is_shift_pressed() && !is_mouse_over_selection()) {
caret = 0;
remove_secondary_carets();
}
@@ -2032,7 +2049,7 @@ void TextEdit::gui_input(const Ref<InputEvent> &p_gui_input) {
// Allow unicode handling if:
// * No modifiers are pressed (except Shift and CapsLock)
- bool allow_unicode_handling = !(k->is_command_or_control_pressed() || k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
+ bool allow_unicode_handling = !(k->is_ctrl_pressed() || k->is_alt_pressed() || k->is_meta_pressed());
// Check and handle all built-in shortcuts.
@@ -2984,51 +3001,11 @@ void TextEdit::_update_theme_item_cache() {
Control::_update_theme_item_cache();
theme_cache.base_scale = get_theme_default_base_scale();
-
- /* Internal API for CodeEdit */
- theme_cache.brace_mismatch_color = get_theme_color(SNAME("brace_mismatch_color"), SNAME("CodeEdit"));
- theme_cache.code_folding_color = get_theme_color(SNAME("code_folding_color"), SNAME("CodeEdit"));
- theme_cache.folded_eol_icon = get_theme_icon(SNAME("folded_eol_icon"), SNAME("CodeEdit"));
-
- /* Search */
- theme_cache.search_result_color = get_theme_color(SNAME("search_result_color"));
- theme_cache.search_result_border_color = get_theme_color(SNAME("search_result_border_color"));
-
- /* Caret */
- theme_cache.caret_width = get_theme_constant(SNAME("caret_width"));
- theme_cache.caret_color = get_theme_color(SNAME("caret_color"));
- theme_cache.caret_background_color = get_theme_color(SNAME("caret_background_color"));
-
- /* Selection */
- theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
- theme_cache.selection_color = get_theme_color(SNAME("selection_color"));
use_selected_font_color = theme_cache.font_selected_color != Color(0, 0, 0, 0);
- /* Other visuals */
- theme_cache.style_normal = get_theme_stylebox(SNAME("normal"));
- theme_cache.style_focus = get_theme_stylebox(SNAME("focus"));
- theme_cache.style_readonly = get_theme_stylebox(SNAME("read_only"));
-
- theme_cache.tab_icon = get_theme_icon(SNAME("tab"));
- theme_cache.space_icon = get_theme_icon(SNAME("space"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_readonly_color = get_theme_color(SNAME("font_readonly_color"));
- theme_cache.font_placeholder_color = get_theme_color(SNAME("font_placeholder_color"));
-
- theme_cache.outline_size = get_theme_constant(SNAME("outline_size"));
- theme_cache.outline_color = get_theme_color(SNAME("font_outline_color"));
-
- theme_cache.line_spacing = get_theme_constant(SNAME("line_spacing"));
if (text.get_line_height() + theme_cache.line_spacing < 1) {
WARN_PRINT("Line height is too small, please increase font_size and/or line_spacing");
}
-
- theme_cache.background_color = get_theme_color(SNAME("background_color"));
- theme_cache.current_line_color = get_theme_color(SNAME("current_line_color"));
- theme_cache.word_highlighted_color = get_theme_color(SNAME("word_highlighted_color"));
}
void TextEdit::_update_caches() {
@@ -3100,13 +3077,13 @@ void TextEdit::drop_data(const Point2 &p_point, const Variant &p_data) {
int caret_column_tmp = pos.x;
if (selection_drag_attempt) {
selection_drag_attempt = false;
- if (!is_mouse_over_selection(!Input::get_singleton()->is_key_pressed(Key::CTRL))) {
+ if (!is_mouse_over_selection(!Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL))) {
// Set caret back at selection for undo / redo.
set_caret_line(get_selection_to_line(), false, false);
set_caret_column(get_selection_to_column());
begin_complex_operation();
- if (!Input::get_singleton()->is_key_pressed(Key::CTRL)) {
+ if (!Input::get_singleton()->is_key_pressed(Key::CMD_OR_CTRL)) {
if (caret_row_tmp > get_selection_to_line()) {
caret_row_tmp = caret_row_tmp - (get_selection_to_line() - get_selection_from_line());
} else if (caret_row_tmp == get_selection_to_line() && caret_column_tmp >= get_selection_to_column()) {
@@ -4352,6 +4329,11 @@ Rect2i TextEdit::get_rect_at_line_column(int p_line, int p_column) const {
ERR_FAIL_COND_V(p_column < 0, Rect2i(-1, -1, 0, 0));
ERR_FAIL_COND_V(p_column > text[p_line].length(), Rect2i(-1, -1, 0, 0));
+ if (text.size() == 1 && text[0].length() == 0) {
+ // The TextEdit is empty.
+ return Rect2i();
+ }
+
if (line_drawing_cache.size() == 0 || !line_drawing_cache.has(p_line)) {
// Line is not in the cache, which means it's outside of the viewing area.
return Rect2i(-1, -1, 0, 0);
@@ -6036,8 +6018,12 @@ bool TextEdit::is_drawing_spaces() const {
return draw_spaces;
}
+Color TextEdit::get_font_color() const {
+ return theme_cache.font_color;
+}
+
void TextEdit::_bind_methods() {
- /*Internal. */
+ /* Internal. */
ClassDB::bind_method(D_METHOD("_text_changed_emit"), &TextEdit::_text_changed_emit);
@@ -6496,6 +6482,43 @@ void TextEdit::_bind_methods() {
ADD_SIGNAL(MethodInfo("gutter_added"));
ADD_SIGNAL(MethodInfo("gutter_removed"));
+ /* Theme items */
+ /* Search */
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, search_result_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, search_result_border_color);
+
+ /* Caret */
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TextEdit, caret_width);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, caret_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, caret_background_color);
+
+ /* Selection */
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, font_selected_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, selection_color);
+
+ /* Other visuals */
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TextEdit, style_normal, "normal");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TextEdit, style_focus, "focus");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, TextEdit, style_readonly, "read_only");
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TextEdit, tab_icon, "tab");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_ICON, TextEdit, space_icon, "space");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, TextEdit, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, TextEdit, font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, font_readonly_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, font_placeholder_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TextEdit, outline_size);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_COLOR, TextEdit, outline_color, "font_outline_color");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, TextEdit, line_spacing);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, background_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, current_line_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, TextEdit, word_highlighted_color);
+
/* Settings. */
GLOBAL_DEF(PropertyInfo(Variant::FLOAT, "gui/timers/text_edit_idle_detect_sec", PROPERTY_HINT_RANGE, "0,10,0.01,or_greater"), 3);
GLOBAL_DEF(PropertyInfo(Variant::INT, "gui/common/text_edit_undo_stack_max_size", PROPERTY_HINT_RANGE, "0,10000,1,or_greater"), 1024);
diff --git a/scene/gui/text_edit.h b/scene/gui/text_edit.h
index b52fde9361..56d5b67e0b 100644
--- a/scene/gui/text_edit.h
+++ b/scene/gui/text_edit.h
@@ -543,11 +543,6 @@ private:
struct ThemeCache {
float base_scale = 1.0;
- /* Internal API for CodeEdit */
- Color brace_mismatch_color;
- Color code_folding_color = Color(1, 1, 1);
- Ref<Texture2D> folded_eol_icon;
-
/* Search */
Color search_result_color = Color(1, 1, 1);
Color search_result_border_color = Color(1, 1, 1);
@@ -632,7 +627,7 @@ protected:
virtual void _update_theme_item_cache() override;
/* Internal API for CodeEdit, pending public API. */
- // brace matching
+ // Brace matching.
struct BraceMatchingData {
int open_match_line = -1;
int open_match_column = -1;
@@ -661,6 +656,11 @@ protected:
String lookup_symbol_word;
void _set_symbol_lookup_word(const String &p_symbol);
+ // Theme items.
+ virtual Color _get_brace_mismatch_color() const { return Color(); };
+ virtual Color _get_code_folding_color() const { return Color(); };
+ virtual Ref<Texture2D> _get_folded_eol_icon() const { return Ref<Texture2D>(); };
+
/* Text manipulation */
// Overridable actions
@@ -1027,6 +1027,8 @@ public:
void set_draw_spaces(bool p_enabled);
bool is_drawing_spaces() const;
+ Color get_font_color() const;
+
TextEdit(const String &p_placeholder = String());
};
diff --git a/scene/gui/tree.cpp b/scene/gui/tree.cpp
index 382707fd04..e2b16cdd66 100644
--- a/scene/gui/tree.cpp
+++ b/scene/gui/tree.cpp
@@ -40,6 +40,7 @@
#include "scene/gui/box_container.h"
#include "scene/gui/text_edit.h"
#include "scene/main/window.h"
+#include "scene/theme/theme_db.h"
#include <limits.h>
@@ -1700,76 +1701,6 @@ TreeItem::~TreeItem() {
void Tree::_update_theme_item_cache() {
Control::_update_theme_item_cache();
- theme_cache.panel_style = get_theme_stylebox(SNAME("panel"));
- theme_cache.focus_style = get_theme_stylebox(SNAME("focus"));
-
- theme_cache.font = get_theme_font(SNAME("font"));
- theme_cache.font_size = get_theme_font_size(SNAME("font_size"));
- theme_cache.tb_font = get_theme_font(SNAME("title_button_font"));
- theme_cache.tb_font_size = get_theme_font_size(SNAME("title_button_font_size"));
-
- theme_cache.selected = get_theme_stylebox(SNAME("selected"));
- theme_cache.selected_focus = get_theme_stylebox(SNAME("selected_focus"));
- theme_cache.cursor = get_theme_stylebox(SNAME("cursor"));
- theme_cache.cursor_unfocus = get_theme_stylebox(SNAME("cursor_unfocused"));
- theme_cache.button_pressed = get_theme_stylebox(SNAME("button_pressed"));
-
- theme_cache.checked = get_theme_icon(SNAME("checked"));
- theme_cache.unchecked = get_theme_icon(SNAME("unchecked"));
- theme_cache.indeterminate = get_theme_icon(SNAME("indeterminate"));
- theme_cache.arrow = get_theme_icon(SNAME("arrow"));
- theme_cache.arrow_collapsed = get_theme_icon(SNAME("arrow_collapsed"));
- theme_cache.arrow_collapsed_mirrored = get_theme_icon(SNAME("arrow_collapsed_mirrored"));
- theme_cache.select_arrow = get_theme_icon(SNAME("select_arrow"));
- theme_cache.updown = get_theme_icon(SNAME("updown"));
-
- theme_cache.custom_button = get_theme_stylebox(SNAME("custom_button"));
- theme_cache.custom_button_hover = get_theme_stylebox(SNAME("custom_button_hover"));
- theme_cache.custom_button_pressed = get_theme_stylebox(SNAME("custom_button_pressed"));
- theme_cache.custom_button_font_highlight = get_theme_color(SNAME("custom_button_font_highlight"));
-
- theme_cache.font_color = get_theme_color(SNAME("font_color"));
- theme_cache.font_selected_color = get_theme_color(SNAME("font_selected_color"));
- theme_cache.drop_position_color = get_theme_color(SNAME("drop_position_color"));
- theme_cache.h_separation = get_theme_constant(SNAME("h_separation"));
- theme_cache.v_separation = get_theme_constant(SNAME("v_separation"));
- theme_cache.inner_item_margin_bottom = get_theme_constant(SNAME("inner_item_margin_bottom"));
- theme_cache.inner_item_margin_left = get_theme_constant(SNAME("inner_item_margin_left"));
- theme_cache.inner_item_margin_right = get_theme_constant(SNAME("inner_item_margin_right"));
- theme_cache.inner_item_margin_top = get_theme_constant(SNAME("inner_item_margin_top"));
- theme_cache.item_margin = get_theme_constant(SNAME("item_margin"));
- theme_cache.button_margin = get_theme_constant(SNAME("button_margin"));
- theme_cache.icon_max_width = get_theme_constant(SNAME("icon_max_width"));
-
- theme_cache.font_outline_color = get_theme_color(SNAME("font_outline_color"));
- theme_cache.font_outline_size = get_theme_constant(SNAME("outline_size"));
-
- theme_cache.draw_guides = get_theme_constant(SNAME("draw_guides"));
- theme_cache.guide_color = get_theme_color(SNAME("guide_color"));
- theme_cache.draw_relationship_lines = get_theme_constant(SNAME("draw_relationship_lines"));
- theme_cache.relationship_line_width = get_theme_constant(SNAME("relationship_line_width"));
- theme_cache.parent_hl_line_width = get_theme_constant(SNAME("parent_hl_line_width"));
- theme_cache.children_hl_line_width = get_theme_constant(SNAME("children_hl_line_width"));
- theme_cache.parent_hl_line_margin = get_theme_constant(SNAME("parent_hl_line_margin"));
- theme_cache.relationship_line_color = get_theme_color(SNAME("relationship_line_color"));
- theme_cache.parent_hl_line_color = get_theme_color(SNAME("parent_hl_line_color"));
- theme_cache.children_hl_line_color = get_theme_color(SNAME("children_hl_line_color"));
-
- theme_cache.scroll_border = get_theme_constant(SNAME("scroll_border"));
- theme_cache.scroll_speed = get_theme_constant(SNAME("scroll_speed"));
-
- theme_cache.scrollbar_margin_top = get_theme_constant(SNAME("scrollbar_margin_top"));
- theme_cache.scrollbar_margin_right = get_theme_constant(SNAME("scrollbar_margin_right"));
- theme_cache.scrollbar_margin_bottom = get_theme_constant(SNAME("scrollbar_margin_bottom"));
- theme_cache.scrollbar_margin_left = get_theme_constant(SNAME("scrollbar_margin_left"));
- theme_cache.scrollbar_h_separation = get_theme_constant(SNAME("scrollbar_h_separation"));
- theme_cache.scrollbar_v_separation = get_theme_constant(SNAME("scrollbar_v_separation"));
-
- theme_cache.title_button = get_theme_stylebox(SNAME("title_button_normal"));
- theme_cache.title_button_pressed = get_theme_stylebox(SNAME("title_button_pressed"));
- theme_cache.title_button_hover = get_theme_stylebox(SNAME("title_button_hover"));
- theme_cache.title_button_color = get_theme_color(SNAME("title_button_color"));
-
theme_cache.base_scale = get_theme_default_base_scale();
}
@@ -3884,7 +3815,7 @@ void Tree::gui_input(const Ref<InputEvent> &p_event) {
}
if (mb->get_button_index() == MouseButton::LEFT) {
- if (get_item_at_position(mb->get_position()) == nullptr && !mb->is_shift_pressed() && !mb->is_ctrl_pressed() && !mb->is_command_or_control_pressed()) {
+ if (get_item_at_position(mb->get_position()) == nullptr && !mb->is_shift_pressed() && !mb->is_command_or_control_pressed()) {
emit_signal(SNAME("nothing_selected"));
}
}
@@ -5577,6 +5508,76 @@ void Tree::_bind_methods() {
BIND_ENUM_CONSTANT(DROP_MODE_DISABLED);
BIND_ENUM_CONSTANT(DROP_MODE_ON_ITEM);
BIND_ENUM_CONSTANT(DROP_MODE_INBETWEEN);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Tree, panel_style, "panel");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Tree, focus_style, "focus");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, Tree, font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, Tree, font_size);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_FONT, Tree, tb_font, "title_button_font");
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_FONT_SIZE, Tree, tb_font_size, "title_button_font_size");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, selected);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, selected_focus);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, cursor);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Tree, cursor_unfocus, "cursor_unfocused");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, button_pressed);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, checked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, unchecked);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, indeterminate);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, arrow);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, arrow_collapsed);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, arrow_collapsed_mirrored);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, select_arrow);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Tree, updown);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, custom_button);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, custom_button_hover);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, custom_button_pressed);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, custom_button_font_highlight);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_selected_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, drop_position_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, v_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, inner_item_margin_bottom);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, inner_item_margin_left);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, inner_item_margin_right);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, inner_item_margin_top);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, item_margin);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, button_margin);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, icon_max_width);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, font_outline_color);
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_CONSTANT, Tree, font_outline_size, "outline_size");
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, draw_guides);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, guide_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, draw_relationship_lines);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, relationship_line_width);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, parent_hl_line_width);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, children_hl_line_width);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, parent_hl_line_margin);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, relationship_line_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, parent_hl_line_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, children_hl_line_color);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scroll_border);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scroll_speed);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scrollbar_margin_top);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scrollbar_margin_right);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scrollbar_margin_bottom);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scrollbar_margin_left);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scrollbar_h_separation);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Tree, scrollbar_v_separation);
+
+ BIND_THEME_ITEM_CUSTOM(Theme::DATA_TYPE_STYLEBOX, Tree, title_button, "title_button_normal");
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, title_button_pressed);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Tree, title_button_hover);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Tree, title_button_color);
}
Tree::Tree() {
diff --git a/scene/gui/tree.h b/scene/gui/tree.h
index c174d0e960..4a5814c45c 100644
--- a/scene/gui/tree.h
+++ b/scene/gui/tree.h
@@ -504,8 +504,6 @@ private:
void popup_select(int p_option);
- void _notification(int p_what);
-
void item_edited(int p_column, TreeItem *p_item, MouseButton p_custom_mouse_index = MouseButton::NONE);
void item_changed(int p_column, TreeItem *p_item);
void item_selected(int p_column, TreeItem *p_item);
@@ -676,6 +674,7 @@ private:
protected:
virtual void _update_theme_item_cache() override;
+ void _notification(int p_what);
static void _bind_methods();
public:
diff --git a/scene/main/canvas_item.cpp b/scene/main/canvas_item.cpp
index 0f2bf86079..06acdd0237 100644
--- a/scene/main/canvas_item.cpp
+++ b/scene/main/canvas_item.cpp
@@ -303,7 +303,7 @@ void CanvasItem::_notification(int p_what) {
parent = parent->get_parent();
}
- ERR_FAIL_COND(!viewport);
+ ERR_FAIL_NULL(viewport);
window = Object::cast_to<Window>(viewport);
if (window) {
diff --git a/scene/main/viewport.cpp b/scene/main/viewport.cpp
index 5f8f5225c9..ad11c80c42 100644
--- a/scene/main/viewport.cpp
+++ b/scene/main/viewport.cpp
@@ -319,16 +319,16 @@ void Viewport::_sub_window_update(Window *p_window) {
Rect2i r = Rect2i(p_window->get_position(), sw.window->get_size());
if (!p_window->get_flag(Window::FLAG_BORDERLESS)) {
- Ref<StyleBox> panel = p_window->get_theme_stylebox(gui.subwindow_focused == p_window ? SNAME("embedded_border") : SNAME("embedded_unfocused_border"));
+ Ref<StyleBox> panel = gui.subwindow_focused == p_window ? p_window->theme_cache.embedded_border : p_window->theme_cache.embedded_unfocused_border;
panel->draw(sw.canvas_item, r);
// Draw the title bar text.
- Ref<Font> title_font = p_window->get_theme_font(SNAME("title_font"));
- int font_size = p_window->get_theme_font_size(SNAME("title_font_size"));
- Color title_color = p_window->get_theme_color(SNAME("title_color"));
- int title_height = p_window->get_theme_constant(SNAME("title_height"));
- int close_h_ofs = p_window->get_theme_constant(SNAME("close_h_offset"));
- int close_v_ofs = p_window->get_theme_constant(SNAME("close_v_offset"));
+ Ref<Font> title_font = p_window->theme_cache.title_font;
+ int font_size = p_window->theme_cache.title_font_size;
+ Color title_color = p_window->theme_cache.title_color;
+ int title_height = p_window->theme_cache.title_height;
+ int close_h_ofs = p_window->theme_cache.close_h_offset;
+ int close_v_ofs = p_window->theme_cache.close_v_offset;
TextLine title_text = TextLine(p_window->atr(p_window->get_title()), title_font, font_size);
title_text.set_width(r.size.width - panel->get_minimum_size().x - close_h_ofs);
@@ -336,15 +336,15 @@ void Viewport::_sub_window_update(Window *p_window) {
int x = (r.size.width - title_text.get_size().x) / 2;
int y = (-title_height - title_text.get_size().y) / 2;
- Color font_outline_color = p_window->get_theme_color(SNAME("title_outline_modulate"));
- int outline_size = p_window->get_theme_constant(SNAME("title_outline_size"));
+ Color font_outline_color = p_window->theme_cache.title_outline_modulate;
+ int outline_size = p_window->theme_cache.title_outline_size;
if (outline_size > 0 && font_outline_color.a > 0) {
title_text.draw_outline(sw.canvas_item, r.position + Point2(x, y), outline_size, font_outline_color);
}
title_text.draw(sw.canvas_item, r.position + Point2(x, y), title_color);
bool pressed = gui.subwindow_focused == sw.window && gui.subwindow_drag == SUB_WINDOW_DRAG_CLOSE && gui.subwindow_drag_close_inside;
- Ref<Texture2D> close_icon = p_window->get_theme_icon(pressed ? "close_pressed" : "close");
+ Ref<Texture2D> close_icon = pressed ? p_window->theme_cache.close_pressed : p_window->theme_cache.close;
close_icon->draw(sw.canvas_item, r.position + Vector2(r.size.width - close_h_ofs, -close_v_ofs));
}
@@ -1489,6 +1489,9 @@ void Viewport::_gui_show_tooltip() {
PopupPanel *panel = memnew(PopupPanel);
panel->set_theme_type_variation(SNAME("TooltipPanel"));
+ // Ensure no opaque background behind the panel as its StyleBox can be partially transparent (e.g. corners).
+ panel->set_transparent_background(true);
+
// Controls can implement `make_custom_tooltip` to provide their own tooltip.
// This should be a Control node which will be added as child to a TooltipPanel.
Control *base_tooltip = tooltip_owner->make_custom_tooltip(tooltip_text);
@@ -2039,7 +2042,7 @@ void Viewport::_gui_input_event(Ref<InputEvent> p_event) {
Window *sw = embedder->gui.sub_windows[i].window;
Rect2 swrect = Rect2i(sw->get_position(), sw->get_size());
if (!sw->get_flag(Window::FLAG_BORDERLESS)) {
- int title_height = sw->get_theme_constant(SNAME("title_height"));
+ int title_height = sw->theme_cache.title_height;
swrect.position.y -= title_height;
swrect.size.y += title_height;
}
@@ -2669,7 +2672,7 @@ Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subw
Rect2i r = Rect2i(p_subwindow->get_position(), p_subwindow->get_size());
- int title_height = p_subwindow->get_theme_constant(SNAME("title_height"));
+ int title_height = p_subwindow->theme_cache.title_height;
r.position.y -= title_height;
r.size.y += title_height;
@@ -2681,7 +2684,7 @@ Viewport::SubWindowResize Viewport::_sub_window_get_resize_margin(Window *p_subw
int dist_x = p_point.x < r.position.x ? (p_point.x - r.position.x) : (p_point.x > (r.position.x + r.size.x) ? (p_point.x - (r.position.x + r.size.x)) : 0);
int dist_y = p_point.y < r.position.y ? (p_point.y - r.position.y) : (p_point.y > (r.position.y + r.size.y) ? (p_point.y - (r.position.y + r.size.y)) : 0);
- int limit = p_subwindow->get_theme_constant(SNAME("resize_margin"));
+ int limit = p_subwindow->theme_cache.resize_margin;
if (ABS(dist_x) > limit) {
return SUB_WINDOW_RESIZE_DISABLED;
@@ -2866,7 +2869,7 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
if (!sw.window->get_flag(Window::FLAG_BORDERLESS)) {
// Check top bar.
- int title_height = sw.window->get_theme_constant(SNAME("title_height"));
+ int title_height = sw.window->theme_cache.title_height;
Rect2i title_bar = r;
title_bar.position.y -= title_height;
title_bar.size.y = title_height;
@@ -2874,9 +2877,9 @@ bool Viewport::_sub_windows_forward_input(const Ref<InputEvent> &p_event) {
if (title_bar.size.y > 0 && title_bar.has_point(mb->get_position())) {
click_on_window = sw.window;
- int close_h_ofs = sw.window->get_theme_constant(SNAME("close_h_offset"));
- int close_v_ofs = sw.window->get_theme_constant(SNAME("close_v_offset"));
- Ref<Texture2D> close_icon = sw.window->get_theme_icon(SNAME("close"));
+ int close_h_ofs = sw.window->theme_cache.close_h_offset;
+ int close_v_ofs = sw.window->theme_cache.close_v_offset;
+ Ref<Texture2D> close_icon = sw.window->theme_cache.close;
Rect2 close_rect;
close_rect.position = Vector2(r.position.x + r.size.x - close_h_ofs, r.position.y - close_v_ofs);
@@ -3016,8 +3019,8 @@ void Viewport::_update_mouse_over(Vector2 p_pos) {
Rect2 swrect_border = swrect;
if (!sw->get_flag(Window::FLAG_BORDERLESS)) {
- int title_height = sw->get_theme_constant(SNAME("title_height"));
- int margin = sw->get_theme_constant(SNAME("resize_margin"));
+ int title_height = sw->theme_cache.title_height;
+ int margin = sw->theme_cache.resize_margin;
swrect_border.position.y -= title_height + margin;
swrect_border.size.y += title_height + margin * 2;
swrect_border.position.x -= margin;
diff --git a/scene/main/window.cpp b/scene/main/window.cpp
index ba53a5e3c3..c345c3d179 100644
--- a/scene/main/window.cpp
+++ b/scene/main/window.cpp
@@ -1804,7 +1804,7 @@ Rect2i Window::fit_rect_in_parent(Rect2i p_rect, const Rect2i &p_parent_rect) co
p_rect.position.x = 0;
}
- int title_height = get_flag(Window::FLAG_BORDERLESS) ? 0 : get_theme_constant(SNAME("title_height"));
+ int title_height = get_flag(Window::FLAG_BORDERLESS) ? 0 : theme_cache.title_height;
if (p_rect.position.y < title_height) {
p_rect.position.y = title_height;
@@ -1965,6 +1965,8 @@ void Window::_update_theme_item_cache() {
} else {
child_controls_changed();
}
+
+ ThemeDB::get_singleton()->update_class_instance_items(this);
}
void Window::_update_embedded_window() {
@@ -2138,6 +2140,27 @@ int Window::get_theme_constant(const StringName &p_name, const StringName &p_the
return constant;
}
+Variant Window::get_theme_item(Theme::DataType p_data_type, const StringName &p_name, const StringName &p_theme_type) const {
+ switch (p_data_type) {
+ case Theme::DATA_TYPE_COLOR:
+ return get_theme_color(p_name, p_theme_type);
+ case Theme::DATA_TYPE_CONSTANT:
+ return get_theme_constant(p_name, p_theme_type);
+ case Theme::DATA_TYPE_FONT:
+ return get_theme_font(p_name, p_theme_type);
+ case Theme::DATA_TYPE_FONT_SIZE:
+ return get_theme_font_size(p_name, p_theme_type);
+ case Theme::DATA_TYPE_ICON:
+ return get_theme_icon(p_name, p_theme_type);
+ case Theme::DATA_TYPE_STYLEBOX:
+ return get_theme_stylebox(p_name, p_theme_type);
+ case Theme::DATA_TYPE_MAX:
+ break; // Can't happen, but silences warning.
+ }
+
+ return Variant();
+}
+
#ifdef TOOLS_ENABLED
Ref<Texture2D> Window::get_editor_theme_icon(const StringName &p_name) const {
return get_theme_icon(p_name, SNAME("EditorIcons"));
@@ -2887,6 +2910,23 @@ void Window::_bind_methods() {
BIND_ENUM_CONSTANT(WINDOW_INITIAL_POSITION_CENTER_SCREEN_WITH_KEYBOARD_FOCUS);
GDVIRTUAL_BIND(_get_contents_minimum_size);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Window, embedded_border);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_STYLEBOX, Window, embedded_unfocused_border);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT, Window, title_font);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_FONT_SIZE, Window, title_font_size);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Window, title_color);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, title_height);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_COLOR, Window, title_outline_modulate);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, title_outline_size);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Window, close);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_ICON, Window, close_pressed);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, close_h_offset);
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, close_v_offset);
+
+ BIND_THEME_ITEM(Theme::DATA_TYPE_CONSTANT, Window, resize_margin);
}
Window::Window() {
diff --git a/scene/main/window.h b/scene/main/window.h
index 689fa754cb..11b986239e 100644
--- a/scene/main/window.h
+++ b/scene/main/window.h
@@ -42,7 +42,8 @@ class ThemeOwner;
class ThemeContext;
class Window : public Viewport {
- GDCLASS(Window, Viewport)
+ GDCLASS(Window, Viewport);
+
public:
// Keep synced with enum hint for `mode` property.
enum Mode {
@@ -191,6 +192,25 @@ private:
void _notify_theme_override_changed();
void _invalidate_theme_cache();
+ struct ThemeCache {
+ Ref<StyleBox> embedded_border;
+ Ref<StyleBox> embedded_unfocused_border;
+
+ Ref<Font> title_font;
+ int title_font_size = 0;
+ Color title_color;
+ int title_height = 0;
+ Color title_outline_modulate;
+ int title_outline_size = 0;
+
+ Ref<Texture2D> close;
+ Ref<Texture2D> close_pressed;
+ int close_h_offset = 0;
+ int close_v_offset = 0;
+
+ int resize_margin = 0;
+ } theme_cache;
+
Viewport *embedder = nullptr;
Transform2D window_transform;
@@ -212,12 +232,12 @@ private:
protected:
virtual Rect2i _popup_adjust_rect() const { return Rect2i(); }
+ virtual void _post_popup() {}
virtual void _update_theme_item_cache();
- virtual void _post_popup() {}
- static void _bind_methods();
void _notification(int p_what);
+ static void _bind_methods();
bool _set(const StringName &p_name, const Variant &p_value);
bool _get(const StringName &p_name, Variant &r_ret) const;
@@ -397,6 +417,7 @@ public:
int get_theme_font_size(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
Color get_theme_color(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
int get_theme_constant(const StringName &p_name, const StringName &p_theme_type = StringName()) const;
+ Variant get_theme_item(Theme::DataType p_data_type, const StringName &p_name, const StringName &p_theme_type = StringName()) const;
#ifdef TOOLS_ENABLED
Ref<Texture2D> get_editor_theme_icon(const StringName &p_name) const;
#endif
diff --git a/scene/resources/animation.cpp b/scene/resources/animation.cpp
index f2cd2bc933..c49da1ded1 100644
--- a/scene/resources/animation.cpp
+++ b/scene/resources/animation.cpp
@@ -4484,7 +4484,7 @@ struct AnimationCompressionDataState {
void commit_temp_packets() {
if (temp_packets.size() == 0) {
- return; //nohing to do
+ return; // Nothing to do.
}
//#define DEBUG_PACKET_PUSH
#ifdef DEBUG_PACKET_PUSH
diff --git a/scene/resources/curve.cpp b/scene/resources/curve.cpp
index 2e49022c29..258e3e90c3 100644
--- a/scene/resources/curve.cpp
+++ b/scene/resources/curve.cpp
@@ -1662,7 +1662,7 @@ void Curve3D::_bake() const {
const Vector3 *forward_ptr = baked_forward_vector_cache.ptr();
const Vector3 *points_ptr = baked_point_cache.ptr();
- Basis frame; // X-right, Y-up, Z-forward.
+ Basis frame; // X-right, Y-up, -Z-forward.
Basis frame_prev;
// Set the initial frame based on Y-up rule.
@@ -1683,7 +1683,7 @@ void Curve3D::_bake() const {
Vector3 forward = forward_ptr[idx];
Basis rotate;
- rotate.rotate_to_align(frame_prev.get_column(2), forward);
+ rotate.rotate_to_align(-frame_prev.get_column(2), forward);
frame = rotate * frame_prev;
frame.orthonormalize(); // guard against float error accumulation
diff --git a/scene/resources/importer_mesh.cpp b/scene/resources/importer_mesh.cpp
index a65a75d878..f479ae1e1b 100644
--- a/scene/resources/importer_mesh.cpp
+++ b/scene/resources/importer_mesh.cpp
@@ -475,6 +475,14 @@ void ImporterMesh::generate_lods(float p_normal_merge_angle, float p_normal_spli
if (new_index_count == 0 || (new_index_count >= (index_count * 0.75f))) {
break;
}
+ if (new_index_count > 5000000) {
+ // This limit theoretically shouldn't be needed, but it's here
+ // as an ad-hoc fix to prevent a crash with complex meshes.
+ // The crash still happens with limit of 6000000, but 5000000 works.
+ // In the future, identify what's causing that crash and fix it.
+ WARN_PRINT("Mesh LOD generation failed for mesh " + get_name() + " surface " + itos(i) + ", mesh is too complex. Some automatic LODs were not generated.");
+ break;
+ }
new_indices.resize(new_index_count);
@@ -1225,6 +1233,7 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
for (int i = 0; i < lightmap_surfaces.size(); i++) {
Ref<SurfaceTool> st;
st.instantiate();
+ st->set_skin_weight_count((lightmap_surfaces[i].format & Mesh::ARRAY_FLAG_USE_8_BONE_WEIGHTS) ? SurfaceTool::SKIN_8_WEIGHTS : SurfaceTool::SKIN_4_WEIGHTS);
st->begin(Mesh::PRIMITIVE_TRIANGLES);
st->set_material(lightmap_surfaces[i].material);
st->set_meta("name", lightmap_surfaces[i].name);
@@ -1292,7 +1301,15 @@ Error ImporterMesh::lightmap_unwrap_cached(const Transform3D &p_base_transform,
Ref<SurfaceTool> &tool = surfaces_tools[i];
tool->index();
Array arrays = tool->commit_to_arrays();
- add_surface(tool->get_primitive_type(), arrays, Array(), Dictionary(), tool->get_material(), tool->get_meta("name"), lightmap_surfaces[i].format);
+
+ uint64_t format = lightmap_surfaces[i].format;
+ if (tool->get_skin_weight_count() == SurfaceTool::SKIN_8_WEIGHTS) {
+ format |= RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+ } else {
+ format &= ~RS::ARRAY_FLAG_USE_8_BONE_WEIGHTS;
+ }
+
+ add_surface(tool->get_primitive_type(), arrays, Array(), Dictionary(), tool->get_material(), tool->get_meta("name"), format);
}
set_lightmap_size_hint(Size2(size_x, size_y));
diff --git a/scene/resources/surface_tool.cpp b/scene/resources/surface_tool.cpp
index af8beb1d25..2523215d4d 100644
--- a/scene/resources/surface_tool.cpp
+++ b/scene/resources/surface_tool.cpp
@@ -1279,7 +1279,7 @@ SurfaceTool::CustomFormat SurfaceTool::get_custom_format(int p_channel_index) co
return last_custom_format[p_channel_index];
}
void SurfaceTool::optimize_indices_for_cache() {
- ERR_FAIL_COND(optimize_vertex_cache_func == nullptr);
+ ERR_FAIL_NULL(optimize_vertex_cache_func);
ERR_FAIL_COND(index_array.size() == 0);
ERR_FAIL_COND(primitive != Mesh::PRIMITIVE_TRIANGLES);
ERR_FAIL_COND(index_array.size() % 3 != 0);
@@ -1308,7 +1308,7 @@ Vector<int> SurfaceTool::generate_lod(float p_threshold, int p_target_index_coun
Vector<int> lod;
- ERR_FAIL_COND_V(simplify_func == nullptr, lod);
+ ERR_FAIL_NULL_V(simplify_func, lod);
ERR_FAIL_COND_V(p_target_index_count < 0, lod);
ERR_FAIL_COND_V(vertex_array.size() == 0, lod);
ERR_FAIL_COND_V(index_array.size() == 0, lod);
diff --git a/scene/resources/syntax_highlighter.cpp b/scene/resources/syntax_highlighter.cpp
index 903be41c26..441c8859cf 100644
--- a/scene/resources/syntax_highlighter.cpp
+++ b/scene/resources/syntax_highlighter.cpp
@@ -419,7 +419,7 @@ void CodeHighlighter::_clear_highlighting_cache() {
}
void CodeHighlighter::_update_cache() {
- font_color = text_edit->get_theme_color(SNAME("font_color"));
+ font_color = text_edit->get_font_color();
}
void CodeHighlighter::add_keyword_color(const String &p_keyword, const Color &p_color) {
diff --git a/scene/resources/theme.h b/scene/resources/theme.h
index c7a76f4c5e..b26b5b5e84 100644
--- a/scene/resources/theme.h
+++ b/scene/resources/theme.h
@@ -69,15 +69,6 @@ private:
void _emit_theme_changed(bool p_notify_list_changed = false);
- HashMap<StringName, ThemeIconMap> icon_map;
- HashMap<StringName, ThemeStyleMap> style_map;
- HashMap<StringName, ThemeFontMap> font_map;
- HashMap<StringName, ThemeFontSizeMap> font_size_map;
- HashMap<StringName, ThemeColorMap> color_map;
- HashMap<StringName, ThemeConstantMap> constant_map;
- HashMap<StringName, StringName> variation_map;
- HashMap<StringName, List<StringName>> variation_base_map;
-
Vector<String> _get_icon_list(const String &p_theme_type) const;
Vector<String> _get_icon_type_list() const;
Vector<String> _get_stylebox_list(const String &p_theme_type) const;
@@ -107,6 +98,15 @@ protected:
Ref<Font> default_font;
int default_font_size = -1;
+ HashMap<StringName, ThemeIconMap> icon_map;
+ HashMap<StringName, ThemeStyleMap> style_map;
+ HashMap<StringName, ThemeFontMap> font_map;
+ HashMap<StringName, ThemeFontSizeMap> font_size_map;
+ HashMap<StringName, ThemeColorMap> color_map;
+ HashMap<StringName, ThemeConstantMap> constant_map;
+ HashMap<StringName, StringName> variation_map;
+ HashMap<StringName, List<StringName>> variation_base_map;
+
static void _bind_methods();
void _freeze_change_propagation();
@@ -131,7 +131,7 @@ public:
bool has_default_font_size() const;
void set_icon(const StringName &p_name, const StringName &p_theme_type, const Ref<Texture2D> &p_icon);
- Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_theme_type) const;
+ virtual Ref<Texture2D> get_icon(const StringName &p_name, const StringName &p_theme_type) const;
bool has_icon(const StringName &p_name, const StringName &p_theme_type) const;
bool has_icon_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_icon(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
@@ -142,7 +142,7 @@ public:
void get_icon_type_list(List<StringName> *p_list) const;
void set_stylebox(const StringName &p_name, const StringName &p_theme_type, const Ref<StyleBox> &p_style);
- Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_theme_type) const;
+ virtual Ref<StyleBox> get_stylebox(const StringName &p_name, const StringName &p_theme_type) const;
bool has_stylebox(const StringName &p_name, const StringName &p_theme_type) const;
bool has_stylebox_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_stylebox(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
@@ -153,7 +153,7 @@ public:
void get_stylebox_type_list(List<StringName> *p_list) const;
void set_font(const StringName &p_name, const StringName &p_theme_type, const Ref<Font> &p_font);
- Ref<Font> get_font(const StringName &p_name, const StringName &p_theme_type) const;
+ virtual Ref<Font> get_font(const StringName &p_name, const StringName &p_theme_type) const;
bool has_font(const StringName &p_name, const StringName &p_theme_type) const;
bool has_font_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_font(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
@@ -164,7 +164,7 @@ public:
void get_font_type_list(List<StringName> *p_list) const;
void set_font_size(const StringName &p_name, const StringName &p_theme_type, int p_font_size);
- int get_font_size(const StringName &p_name, const StringName &p_theme_type) const;
+ virtual int get_font_size(const StringName &p_name, const StringName &p_theme_type) const;
bool has_font_size(const StringName &p_name, const StringName &p_theme_type) const;
bool has_font_size_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_font_size(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
@@ -175,7 +175,7 @@ public:
void get_font_size_type_list(List<StringName> *p_list) const;
void set_color(const StringName &p_name, const StringName &p_theme_type, const Color &p_color);
- Color get_color(const StringName &p_name, const StringName &p_theme_type) const;
+ virtual Color get_color(const StringName &p_name, const StringName &p_theme_type) const;
bool has_color(const StringName &p_name, const StringName &p_theme_type) const;
bool has_color_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_color(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
@@ -186,7 +186,7 @@ public:
void get_color_type_list(List<StringName> *p_list) const;
void set_constant(const StringName &p_name, const StringName &p_theme_type, int p_constant);
- int get_constant(const StringName &p_name, const StringName &p_theme_type) const;
+ virtual int get_constant(const StringName &p_name, const StringName &p_theme_type) const;
bool has_constant(const StringName &p_name, const StringName &p_theme_type) const;
bool has_constant_nocheck(const StringName &p_name, const StringName &p_theme_type) const;
void rename_constant(const StringName &p_old_name, const StringName &p_name, const StringName &p_theme_type);
diff --git a/scene/resources/tile_set.cpp b/scene/resources/tile_set.cpp
index da3a18e71b..b372fcb1e9 100644
--- a/scene/resources/tile_set.cpp
+++ b/scene/resources/tile_set.cpp
@@ -4464,6 +4464,10 @@ bool TileSetAtlasSource::is_position_in_tile_texture_region(const Vector2i p_atl
return rect.has_point(p_position);
}
+int TileSetAtlasSource::alternative_no_transform(int p_alternative_id) {
+ return p_alternative_id & ~(TRANSFORM_FLIP_H | TRANSFORM_FLIP_V | TRANSFORM_TRANSPOSE);
+}
+
// Getters for texture and tile region (padded or not)
Ref<Texture2D> TileSetAtlasSource::get_runtime_texture() const {
if (use_texture_padding) {
@@ -4547,6 +4551,7 @@ int TileSetAtlasSource::create_alternative_tile(const Vector2i p_atlas_coords, i
void TileSetAtlasSource::remove_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) {
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
ERR_FAIL_COND_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
+ p_alternative_tile = alternative_no_transform(p_alternative_tile);
ERR_FAIL_COND_MSG(p_alternative_tile == 0, "Cannot remove the alternative with id 0, the base tile alternative cannot be removed.");
memdelete(tiles[p_atlas_coords].alternatives[p_alternative_tile]);
@@ -4560,6 +4565,7 @@ void TileSetAtlasSource::remove_alternative_tile(const Vector2i p_atlas_coords,
void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords, int p_alternative_tile, int p_new_id) {
ERR_FAIL_COND_MSG(!tiles.has(p_atlas_coords), vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
ERR_FAIL_COND_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
+ p_alternative_tile = alternative_no_transform(p_alternative_tile);
ERR_FAIL_COND_MSG(p_alternative_tile == 0, "Cannot change the alternative with id 0, the base tile alternative cannot be modified.");
ERR_FAIL_COND_MSG(tiles[p_atlas_coords].alternatives.has(p_new_id), vformat("TileSetAtlasSource has already an alternative with id %d at %s.", p_new_id, String(p_atlas_coords)));
@@ -4576,7 +4582,7 @@ void TileSetAtlasSource::set_alternative_tile_id(const Vector2i p_atlas_coords,
bool TileSetAtlasSource::has_alternative_tile(const Vector2i p_atlas_coords, int p_alternative_tile) const {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), false, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
- return tiles[p_atlas_coords].alternatives.has(p_alternative_tile);
+ return tiles[p_atlas_coords].alternatives.has(alternative_no_transform(p_alternative_tile));
}
int TileSetAtlasSource::get_next_alternative_tile_id(const Vector2i p_atlas_coords) const {
@@ -4591,6 +4597,7 @@ int TileSetAtlasSource::get_alternative_tiles_count(const Vector2i p_atlas_coord
int TileSetAtlasSource::get_alternative_tile_id(const Vector2i p_atlas_coords, int p_index) const {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), TileSetSource::INVALID_TILE_ALTERNATIVE, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
+ p_index = alternative_no_transform(p_index);
ERR_FAIL_INDEX_V(p_index, tiles[p_atlas_coords].alternatives_ids.size(), TileSetSource::INVALID_TILE_ALTERNATIVE);
return tiles[p_atlas_coords].alternatives_ids[p_index];
@@ -4598,6 +4605,7 @@ int TileSetAtlasSource::get_alternative_tile_id(const Vector2i p_atlas_coords, i
TileData *TileSetAtlasSource::get_tile_data(const Vector2i p_atlas_coords, int p_alternative_tile) const {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("The TileSetAtlasSource atlas has no tile at %s.", String(p_atlas_coords)));
+ p_alternative_tile = alternative_no_transform(p_alternative_tile);
ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
return tiles[p_atlas_coords].alternatives[p_alternative_tile];
@@ -4668,6 +4676,10 @@ void TileSetAtlasSource::_bind_methods() {
BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_DEFAULT)
BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_RANDOM_START_TIMES)
BIND_ENUM_CONSTANT(TILE_ANIMATION_MODE_MAX)
+
+ BIND_CONSTANT(TRANSFORM_FLIP_H)
+ BIND_CONSTANT(TRANSFORM_FLIP_V)
+ BIND_CONSTANT(TRANSFORM_TRANSPOSE)
}
TileSetAtlasSource::~TileSetAtlasSource() {
@@ -4681,6 +4693,7 @@ TileSetAtlasSource::~TileSetAtlasSource() {
TileData *TileSetAtlasSource::_get_atlas_tile_data(Vector2i p_atlas_coords, int p_alternative_tile) {
ERR_FAIL_COND_V_MSG(!tiles.has(p_atlas_coords), nullptr, vformat("TileSetAtlasSource has no tile at %s.", String(p_atlas_coords)));
+ p_alternative_tile = alternative_no_transform(p_alternative_tile);
ERR_FAIL_COND_V_MSG(!tiles[p_atlas_coords].alternatives.has(p_alternative_tile), nullptr, vformat("TileSetAtlasSource has no alternative with id %d for tile coords %s.", p_alternative_tile, String(p_atlas_coords)));
return tiles[p_atlas_coords].alternatives[p_alternative_tile];
@@ -5487,13 +5500,13 @@ int TileData::get_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const
}
bool TileData::is_valid_terrain_peering_bit(TileSet::CellNeighbor p_peering_bit) const {
- ERR_FAIL_COND_V(!tile_set, false);
+ ERR_FAIL_NULL_V(tile_set, false);
return tile_set->is_valid_terrain_peering_bit(terrain_set, p_peering_bit);
}
TileSet::TerrainsPattern TileData::get_terrains_pattern() const {
- ERR_FAIL_COND_V(!tile_set, TileSet::TerrainsPattern());
+ ERR_FAIL_NULL_V(tile_set, TileSet::TerrainsPattern());
TileSet::TerrainsPattern output(tile_set, terrain_set);
output.set_terrain(terrain);
@@ -5529,14 +5542,14 @@ float TileData::get_probability() const {
// Custom data
void TileData::set_custom_data(String p_layer_name, Variant p_value) {
- ERR_FAIL_COND(!tile_set);
+ ERR_FAIL_NULL(tile_set);
int p_layer_id = tile_set->get_custom_data_layer_by_name(p_layer_name);
ERR_FAIL_COND_MSG(p_layer_id < 0, vformat("TileSet has no layer with name: %s", p_layer_name));
set_custom_data_by_layer_id(p_layer_id, p_value);
}
Variant TileData::get_custom_data(String p_layer_name) const {
- ERR_FAIL_COND_V(!tile_set, Variant());
+ ERR_FAIL_NULL_V(tile_set, Variant());
int p_layer_id = tile_set->get_custom_data_layer_by_name(p_layer_name);
ERR_FAIL_COND_V_MSG(p_layer_id < 0, Variant(), vformat("TileSet has no layer with name: %s", p_layer_name));
return get_custom_data_by_layer_id(p_layer_id);
diff --git a/scene/resources/tile_set.h b/scene/resources/tile_set.h
index f053740db1..722d615b09 100644
--- a/scene/resources/tile_set.h
+++ b/scene/resources/tile_set.h
@@ -62,10 +62,10 @@ class TileSetPluginAtlasNavigation;
union TileMapCell {
struct {
- int32_t source_id : 16;
- int16_t coord_x : 16;
- int16_t coord_y : 16;
- int32_t alternative_tile : 16;
+ int16_t source_id;
+ int16_t coord_x;
+ int16_t coord_y;
+ int16_t alternative_tile;
};
uint64_t _u64t;
@@ -137,6 +137,7 @@ public:
Vector2i get_cell_atlas_coords(const Vector2i &p_coords) const;
int get_cell_alternative_tile(const Vector2i &p_coords) const;
+ const HashMap<Vector2i, TileMapCell> &get_pattern() const { return pattern; }
TypedArray<Vector2i> get_used_cells() const;
Size2i get_size() const;
@@ -598,6 +599,12 @@ public:
TILE_ANIMATION_MODE_MAX,
};
+ enum TransformBits {
+ TRANSFORM_FLIP_H = 1 << 12,
+ TRANSFORM_FLIP_V = 1 << 13,
+ TRANSFORM_TRANSPOSE = 1 << 14,
+ };
+
private:
struct TileAlternativesData {
Vector2i size_in_atlas = Vector2i(1, 1);
@@ -736,6 +743,8 @@ public:
Rect2i get_tile_texture_region(Vector2i p_atlas_coords, int p_frame = 0) const;
bool is_position_in_tile_texture_region(const Vector2i p_atlas_coords, int p_alternative_tile, Vector2 p_position) const;
+ static int alternative_no_transform(int p_alternative_id);
+
// Getters for texture and tile region (padded or not)
Ref<Texture2D> get_runtime_texture() const;
Rect2i get_runtime_tile_texture_region(Vector2i p_atlas_coords, int p_frame = 0) const;
diff --git a/scene/theme/default_theme.cpp b/scene/theme/default_theme.cpp
index 61e018c656..7efbc74bf3 100644
--- a/scene/theme/default_theme.cpp
+++ b/scene/theme/default_theme.cpp
@@ -478,6 +478,8 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_icon("executing_line", "CodeEdit", icons["arrow_right"]);
theme->set_icon("can_fold", "CodeEdit", icons["arrow_down"]);
theme->set_icon("folded", "CodeEdit", icons["arrow_right"]);
+ theme->set_icon("can_fold_code_region", "CodeEdit", icons["folder_down_arrow"]);
+ theme->set_icon("folded_code_region", "CodeEdit", icons["folder_right_arrow"]);
theme->set_icon("folded_eol_icon", "CodeEdit", icons["text_edit_ellipsis"]);
theme->set_font("font", "CodeEdit", Ref<Font>());
@@ -501,6 +503,7 @@ void fill_default_theme(Ref<Theme> &theme, const Ref<Font> &default_font, const
theme->set_color("executing_line_color", "CodeEdit", Color(0.98, 0.89, 0.27));
theme->set_color("current_line_color", "CodeEdit", Color(0.25, 0.25, 0.26, 0.8));
theme->set_color("code_folding_color", "CodeEdit", Color(0.8, 0.8, 0.8, 0.8));
+ theme->set_color("folded_code_region_color", "CodeEdit", Color(0.68, 0.46, 0.77, 0.2));
theme->set_color("caret_color", "CodeEdit", control_font_color);
theme->set_color("caret_background_color", "CodeEdit", Color(0, 0, 0));
theme->set_color("brace_mismatch_color", "CodeEdit", Color(1, 0.2, 0.2));
diff --git a/scene/theme/icons/folder_down_arrow.svg b/scene/theme/icons/folder_down_arrow.svg
new file mode 100644
index 0000000000..3bc4f3f73b
--- /dev/null
+++ b/scene/theme/icons/folder_down_arrow.svg
@@ -0,0 +1 @@
+<svg height="12" width="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H6V2a1 1 0 0 0-1-1zm1 5a1 1 0 0 1 1.414-1.414L6 6.172l1.586-1.586A1 1 0 0 1 9 6L6.707 8.293a1 1 0 0 1-1.414 0Z" fill="#fff"/></svg> \ No newline at end of file
diff --git a/scene/theme/icons/folder_right_arrow.svg b/scene/theme/icons/folder_right_arrow.svg
new file mode 100644
index 0000000000..a9b81d54f3
--- /dev/null
+++ b/scene/theme/icons/folder_right_arrow.svg
@@ -0,0 +1 @@
+<svg height="12" width="12" viewBox="0 0 12 12" xmlns="http://www.w3.org/2000/svg"><path d="M2 1a1 1 0 0 0-1 1v7a1 1 0 0 0 1 1h8a1 1 0 0 0 1-1V4a1 1 0 0 0-1-1H6V2a1 1 0 0 0-1-1zm3.5 8a1 1 0 0 1-1.414-1.414L5.672 6 4.086 4.414A1 1 0 0 1 5.5 3l2.293 2.293a1 1 0 0 1 0 1.414Z" fill="#fff"/></svg> \ No newline at end of file
diff --git a/scene/theme/theme_db.cpp b/scene/theme/theme_db.cpp
index 92f3dec5e2..c0e7636f5a 100644
--- a/scene/theme/theme_db.cpp
+++ b/scene/theme/theme_db.cpp
@@ -326,6 +326,50 @@ ThemeContext *ThemeDB::get_nearest_theme_context(Node *p_for_node) const {
return nullptr;
}
+// Theme item binding.
+
+void ThemeDB::bind_class_item(const StringName &p_class_name, const StringName &p_prop_name, const StringName &p_item_name, ThemeItemSetter p_setter) {
+ ERR_FAIL_COND_MSG(theme_item_binds[p_class_name].has(p_prop_name), vformat("Failed to bind theme item '%s' in class '%s': already bound", p_prop_name, p_class_name));
+
+ ThemeItemBind bind;
+ bind.class_name = p_class_name;
+ bind.item_name = p_item_name;
+ bind.setter = p_setter;
+
+ theme_item_binds[p_class_name][p_prop_name] = bind;
+}
+
+void ThemeDB::bind_class_external_item(const StringName &p_class_name, const StringName &p_prop_name, const StringName &p_item_name, const StringName &p_type_name, ThemeItemSetter p_setter) {
+ ERR_FAIL_COND_MSG(theme_item_binds[p_class_name].has(p_prop_name), vformat("Failed to bind theme item '%s' in class '%s': already bound", p_prop_name, p_class_name));
+
+ ThemeItemBind bind;
+ bind.class_name = p_class_name;
+ bind.item_name = p_item_name;
+ bind.type_name = p_type_name;
+ bind.external = true;
+ bind.setter = p_setter;
+
+ theme_item_binds[p_class_name][p_prop_name] = bind;
+}
+
+void ThemeDB::update_class_instance_items(Node *p_instance) {
+ ERR_FAIL_NULL(p_instance);
+
+ // Use the hierarchy to initialize all inherited theme caches. Setters carry the necessary
+ // context and will set the values appropriately.
+ StringName class_name = p_instance->get_class();
+ while (class_name != StringName()) {
+ HashMap<StringName, HashMap<StringName, ThemeItemBind>>::Iterator E = theme_item_binds.find(class_name);
+ if (E) {
+ for (const KeyValue<StringName, ThemeItemBind> &F : E->value) {
+ F.value.setter(p_instance);
+ }
+ }
+
+ class_name = ClassDB::get_parent_class_nocheck(class_name);
+ }
+}
+
// Object methods.
void ThemeDB::_bind_methods() {
diff --git a/scene/theme/theme_db.h b/scene/theme/theme_db.h
index 40ae30ff81..07325e2d05 100644
--- a/scene/theme/theme_db.h
+++ b/scene/theme/theme_db.h
@@ -34,6 +34,8 @@
#include "core/object/class_db.h"
#include "core/object/ref_counted.h"
+#include <functional>
+
class Font;
class Node;
class StyleBox;
@@ -41,6 +43,30 @@ class Texture2D;
class Theme;
class ThemeContext;
+// Macros for binding theme items of this class. This information is used for the documentation, theme
+// overrides, etc. This is also the basis for theme cache.
+
+#define BIND_THEME_ITEM(m_data_type, m_class, m_prop) \
+ ThemeDB::get_singleton()->bind_class_item(get_class_static(), #m_prop, #m_prop, [](Node *p_instance) { \
+ m_class *p_cast = Object::cast_to<m_class>(p_instance); \
+ p_cast->theme_cache.m_prop = p_cast->get_theme_item(m_data_type, _scs_create(#m_prop)); \
+ })
+
+#define BIND_THEME_ITEM_CUSTOM(m_data_type, m_class, m_prop, m_item_name) \
+ ThemeDB::get_singleton()->bind_class_item(get_class_static(), #m_prop, m_item_name, [](Node *p_instance) { \
+ m_class *p_cast = Object::cast_to<m_class>(p_instance); \
+ p_cast->theme_cache.m_prop = p_cast->get_theme_item(m_data_type, _scs_create(m_item_name)); \
+ })
+
+// Macro for binding theme items used by this class, but defined/binded by other classes. This is primarily used for
+// the theme cache. Can also be used to list such items in documentation.
+
+#define BIND_THEME_ITEM_EXT(m_data_type, m_class, m_prop, m_item_name, m_type_name) \
+ ThemeDB::get_singleton()->bind_class_external_item(get_class_static(), #m_prop, m_item_name, m_type_name, [](Node *p_instance) { \
+ m_class *p_cast = Object::cast_to<m_class>(p_instance); \
+ p_cast->theme_cache.m_prop = p_cast->get_theme_item(m_data_type, _scs_create(m_item_name), _scs_create(m_type_name)); \
+ })
+
class ThemeDB : public Object {
GDCLASS(ThemeDB, Object);
@@ -68,6 +94,21 @@ class ThemeDB : public Object {
void _init_default_theme_context();
void _finalize_theme_contexts();
+ // Binding of theme items to Node classes.
+
+ typedef std::function<void(Node *)> ThemeItemSetter;
+
+ struct ThemeItemBind {
+ StringName class_name;
+ StringName item_name;
+ StringName type_name;
+ bool external = false;
+
+ ThemeItemSetter setter;
+ };
+
+ HashMap<StringName, HashMap<StringName, ThemeItemBind>> theme_item_binds;
+
protected:
static void _bind_methods();
@@ -112,6 +153,12 @@ public:
ThemeContext *get_default_theme_context() const;
ThemeContext *get_nearest_theme_context(Node *p_for_node) const;
+ // Theme item binding.
+
+ void bind_class_item(const StringName &p_class_name, const StringName &p_prop_name, const StringName &p_item_name, ThemeItemSetter p_setter);
+ void bind_class_external_item(const StringName &p_class_name, const StringName &p_prop_name, const StringName &p_item_name, const StringName &p_type_name, ThemeItemSetter p_setter);
+ void update_class_instance_items(Node *p_instance);
+
// Memory management, reference, and initialization.
static ThemeDB *get_singleton();
diff --git a/scene/theme/theme_owner.cpp b/scene/theme/theme_owner.cpp
index 1ba9a055fc..92cffeb228 100644
--- a/scene/theme/theme_owner.cpp
+++ b/scene/theme/theme_owner.cpp
@@ -212,7 +212,7 @@ void ThemeOwner::get_theme_type_dependencies(const Node *p_for_node, const Strin
type_variation = for_w->get_theme_type_variation();
}
- // If we are looking for dependencies of the current class (or a variantion of it), check themes from the context.
+ // If we are looking for dependencies of the current class (or a variation of it), check themes from the context.
if (p_theme_type == StringName() || p_theme_type == type_name || p_theme_type == type_variation) {
ThemeContext *global_context = _get_active_owner_context();
for (const Ref<Theme> &theme : global_context->get_themes()) {
diff --git a/servers/audio/effects/audio_stream_generator.cpp b/servers/audio/effects/audio_stream_generator.cpp
index 5cfe51465d..f4727e72ec 100644
--- a/servers/audio/effects/audio_stream_generator.cpp
+++ b/servers/audio/effects/audio_stream_generator.cpp
@@ -143,6 +143,10 @@ void AudioStreamGeneratorPlayback::clear_buffer() {
}
int AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_frames) {
+ if (!active) {
+ return 0;
+ }
+
int read_amount = buffer.data_left();
if (p_frames < read_amount) {
read_amount = p_frames;
@@ -151,16 +155,15 @@ int AudioStreamGeneratorPlayback::_mix_internal(AudioFrame *p_buffer, int p_fram
buffer.read(p_buffer, read_amount);
if (read_amount < p_frames) {
- //skipped, not ideal
+ // Fill with zeros as fallback in case of buffer underrun.
for (int i = read_amount; i < p_frames; i++) {
p_buffer[i] = AudioFrame(0, 0);
}
-
skips++;
}
mixed += p_frames / generator->get_mix_rate();
- return read_amount < p_frames ? read_amount : p_frames;
+ return p_frames;
}
float AudioStreamGeneratorPlayback::get_stream_sampling_rate() {
@@ -181,7 +184,7 @@ void AudioStreamGeneratorPlayback::stop() {
}
bool AudioStreamGeneratorPlayback::is_playing() const {
- return active; //always playing, can't be stopped
+ return active;
}
int AudioStreamGeneratorPlayback::get_loop_count() const {
diff --git a/servers/audio_server.cpp b/servers/audio_server.cpp
index 6a03a67fcd..ce7f6ee6f0 100644
--- a/servers/audio_server.cpp
+++ b/servers/audio_server.cpp
@@ -857,14 +857,16 @@ int AudioServer::get_bus_count() const {
void AudioServer::set_bus_name(int p_bus, const String &p_name) {
ERR_FAIL_INDEX(p_bus, buses.size());
if (p_bus == 0 && p_name != "Master") {
- return; //bus 0 is always master
+ return; // Bus 0 is always "Master".
}
MARK_EDITED
lock();
- if (buses[p_bus]->name == p_name) {
+ StringName old_name = buses[p_bus]->name;
+
+ if (old_name == p_name) {
unlock();
return;
}
@@ -888,12 +890,12 @@ void AudioServer::set_bus_name(int p_bus, const String &p_name) {
attempts++;
attempt = p_name + " " + itos(attempts);
}
- bus_map.erase(buses[p_bus]->name);
+ bus_map.erase(old_name);
buses[p_bus]->name = attempt;
bus_map[attempt] = buses[p_bus];
unlock();
- emit_signal(SNAME("bus_layout_changed"));
+ emit_signal(SNAME("bus_renamed"), p_bus, old_name, attempt);
}
String AudioServer::get_bus_name(int p_bus) const {
@@ -1751,6 +1753,7 @@ void AudioServer::_bind_methods() {
ADD_PROPERTY(PropertyInfo(Variant::FLOAT, "playback_speed_scale"), "set_playback_speed_scale", "get_playback_speed_scale");
ADD_SIGNAL(MethodInfo("bus_layout_changed"));
+ ADD_SIGNAL(MethodInfo("bus_renamed", PropertyInfo(Variant::INT, "bus_index"), PropertyInfo(Variant::STRING_NAME, "old_name"), PropertyInfo(Variant::STRING_NAME, "new_name")));
BIND_ENUM_CONSTANT(SPEAKER_MODE_STEREO);
BIND_ENUM_CONSTANT(SPEAKER_SURROUND_31);
diff --git a/servers/physics_3d/godot_soft_body_3d.cpp b/servers/physics_3d/godot_soft_body_3d.cpp
index 4b35dd1500..2081c132af 100644
--- a/servers/physics_3d/godot_soft_body_3d.cpp
+++ b/servers/physics_3d/godot_soft_body_3d.cpp
@@ -155,11 +155,9 @@ void GodotSoftBody3D::update_rendering_server(PhysicsServer3DRenderingServerHand
for (uint32_t i = 0; i < vertex_count; ++i) {
const uint32_t node_index = map_visual_to_physics[i];
const Node &node = nodes[node_index];
- const Vector3 &vertex_position = node.x;
- const Vector3 &vertex_normal = node.n;
- p_rendering_server_handler->set_vertex(i, &vertex_position);
- p_rendering_server_handler->set_normal(i, &vertex_normal);
+ p_rendering_server_handler->set_vertex(i, node.x);
+ p_rendering_server_handler->set_normal(i, node.n);
}
p_rendering_server_handler->set_aabb(bounds);
diff --git a/servers/physics_server_2d.cpp b/servers/physics_server_2d.cpp
index 79a8ebe3d1..a5fa5291c0 100644
--- a/servers/physics_server_2d.cpp
+++ b/servers/physics_server_2d.cpp
@@ -476,6 +476,7 @@ TypedArray<RID> PhysicsTestMotionParameters2D::get_exclude_bodies() const {
}
void PhysicsTestMotionParameters2D::set_exclude_bodies(const TypedArray<RID> &p_exclude) {
+ parameters.exclude_bodies.clear();
for (int i = 0; i < p_exclude.size(); i++) {
parameters.exclude_bodies.insert(p_exclude[i]);
}
@@ -494,6 +495,7 @@ TypedArray<uint64_t> PhysicsTestMotionParameters2D::get_exclude_objects() const
}
void PhysicsTestMotionParameters2D::set_exclude_objects(const TypedArray<uint64_t> &p_exclude) {
+ parameters.exclude_objects.clear();
for (int i = 0; i < p_exclude.size(); ++i) {
ObjectID object_id = p_exclude[i];
ERR_CONTINUE(object_id.is_null());
diff --git a/servers/physics_server_3d.cpp b/servers/physics_server_3d.cpp
index 8497bc78e2..d523f4b1ec 100644
--- a/servers/physics_server_3d.cpp
+++ b/servers/physics_server_3d.cpp
@@ -34,20 +34,24 @@
#include "core/string/print_string.h"
#include "core/variant/typed_array.h"
-void PhysicsServer3DRenderingServerHandler::set_vertex(int p_vertex_id, const void *p_vector3) {
- GDVIRTUAL_REQUIRED_CALL(_set_vertex, p_vertex_id, p_vector3);
+void PhysicsServer3DRenderingServerHandler::set_vertex(int p_vertex_id, const Vector3 &p_vertex) {
+ GDVIRTUAL_REQUIRED_CALL(_set_vertex, p_vertex_id, p_vertex);
}
-void PhysicsServer3DRenderingServerHandler::set_normal(int p_vertex_id, const void *p_vector3) {
- GDVIRTUAL_REQUIRED_CALL(_set_normal, p_vertex_id, p_vector3);
+void PhysicsServer3DRenderingServerHandler::set_normal(int p_vertex_id, const Vector3 &p_normal) {
+ GDVIRTUAL_REQUIRED_CALL(_set_normal, p_vertex_id, p_normal);
}
void PhysicsServer3DRenderingServerHandler::set_aabb(const AABB &p_aabb) {
GDVIRTUAL_REQUIRED_CALL(_set_aabb, p_aabb);
}
void PhysicsServer3DRenderingServerHandler::_bind_methods() {
- GDVIRTUAL_BIND(_set_vertex, "vertex_id", "vertices");
- GDVIRTUAL_BIND(_set_normal, "vertex_id", "normals");
+ GDVIRTUAL_BIND(_set_vertex, "vertex_id", "vertex");
+ GDVIRTUAL_BIND(_set_normal, "vertex_id", "normal");
GDVIRTUAL_BIND(_set_aabb, "aabb");
+
+ ClassDB::bind_method(D_METHOD("set_vertex", "vertex_id", "vertex"), &PhysicsServer3DRenderingServerHandler::set_vertex);
+ ClassDB::bind_method(D_METHOD("set_normal", "vertex_id", "normal"), &PhysicsServer3DRenderingServerHandler::set_normal);
+ ClassDB::bind_method(D_METHOD("set_aabb", "aabb"), &PhysicsServer3DRenderingServerHandler::set_aabb);
}
PhysicsServer3D *PhysicsServer3D::singleton = nullptr;
@@ -497,6 +501,7 @@ TypedArray<RID> PhysicsTestMotionParameters3D::get_exclude_bodies() const {
}
void PhysicsTestMotionParameters3D::set_exclude_bodies(const TypedArray<RID> &p_exclude) {
+ parameters.exclude_bodies.clear();
for (int i = 0; i < p_exclude.size(); i++) {
parameters.exclude_bodies.insert(p_exclude[i]);
}
@@ -515,6 +520,7 @@ TypedArray<uint64_t> PhysicsTestMotionParameters3D::get_exclude_objects() const
}
void PhysicsTestMotionParameters3D::set_exclude_objects(const TypedArray<uint64_t> &p_exclude) {
+ parameters.exclude_objects.clear();
for (int i = 0; i < p_exclude.size(); ++i) {
ObjectID object_id = p_exclude[i];
ERR_CONTINUE(object_id.is_null());
diff --git a/servers/physics_server_3d.h b/servers/physics_server_3d.h
index 553d73b549..68dda8b84d 100644
--- a/servers/physics_server_3d.h
+++ b/servers/physics_server_3d.h
@@ -211,15 +211,15 @@ public:
class PhysicsServer3DRenderingServerHandler : public Object {
GDCLASS(PhysicsServer3DRenderingServerHandler, Object)
protected:
- GDVIRTUAL2(_set_vertex, int, GDExtensionConstPtr<void>)
- GDVIRTUAL2(_set_normal, int, GDExtensionConstPtr<void>)
+ GDVIRTUAL2(_set_vertex, int, const Vector3 &)
+ GDVIRTUAL2(_set_normal, int, const Vector3 &)
GDVIRTUAL1(_set_aabb, const AABB &)
static void _bind_methods();
public:
- virtual void set_vertex(int p_vertex_id, const void *p_vector3);
- virtual void set_normal(int p_vertex_id, const void *p_vector3);
+ virtual void set_vertex(int p_vertex_id, const Vector3 &p_vertex);
+ virtual void set_normal(int p_vertex_id, const Vector3 &p_normal);
virtual void set_aabb(const AABB &p_aabb);
virtual ~PhysicsServer3DRenderingServerHandler() {}
diff --git a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
index b1ad7e16ed..4fede0defc 100644
--- a/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
+++ b/servers/rendering/renderer_rd/renderer_canvas_render_rd.cpp
@@ -2480,6 +2480,7 @@ RendererCanvasRenderRD::RendererCanvasRenderRD() {
actions.render_mode_defines["skip_vertex_transform"] = "#define SKIP_TRANSFORM_USED\n";
actions.render_mode_defines["unshaded"] = "#define MODE_UNSHADED\n";
actions.render_mode_defines["light_only"] = "#define MODE_LIGHT_ONLY\n";
+ actions.render_mode_defines["world_vertex_coords"] = "#define USE_WORLD_VERTEX_COORDS\n";
actions.custom_samplers["TEXTURE"] = "texture_sampler";
actions.custom_samplers["NORMAL_TEXTURE"] = "texture_sampler";
diff --git a/servers/rendering/renderer_rd/shaders/canvas.glsl b/servers/rendering/renderer_rd/shaders/canvas.glsl
index 31c5aadc88..7a13ac7207 100644
--- a/servers/rendering/renderer_rd/shaders/canvas.glsl
+++ b/servers/rendering/renderer_rd/shaders/canvas.glsl
@@ -180,6 +180,10 @@ void main() {
#ifdef USE_POINT_SIZE
float point_size = 1.0;
#endif
+
+#ifdef USE_WORLD_VERTEX_COORDS
+ vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
+#endif
{
#CODE : VERTEX
}
@@ -188,7 +192,7 @@ void main() {
pixel_size_interp = abs(draw_data.dst_rect.zw) * vertex_base;
#endif
-#if !defined(SKIP_TRANSFORM_USED)
+#if !defined(SKIP_TRANSFORM_USED) && !defined(USE_WORLD_VERTEX_COORDS)
vertex = (model_matrix * vec4(vertex, 0.0, 1.0)).xy;
#endif
diff --git a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
index cfba408fe1..2b8b8fa9d2 100644
--- a/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_clustered/scene_forward_clustered.glsl
@@ -1277,9 +1277,10 @@ void fragment_shader(in SceneData scene_data) {
} else if (bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(instances.data[instance_index].flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
uint ofs = instances.data[instance_index].gi_offset & 0xFFFF;
+ uint slice = instances.data[instance_index].gi_offset >> 16;
vec3 uvw;
uvw.xy = uv2 * instances.data[instance_index].lightmap_uv_scale.zw + instances.data[instance_index].lightmap_uv_scale.xy;
- uvw.z = float((instances.data[instance_index].gi_offset >> 16) & 0xFFFF);
+ uvw.z = float(slice);
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
@@ -1288,9 +1289,8 @@ void fragment_shader(in SceneData scene_data) {
vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
- uint idx = instances.data[instance_index].gi_offset >> 20;
- vec3 n = normalize(lightmaps.data[idx].normal_xform * normal);
- float en = lightmaps.data[idx].exposure_normalization;
+ vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
+ float en = lightmaps.data[ofs].exposure_normalization;
ambient_light += lm_light_l0 * 0.282095f * en;
ambient_light += lm_light_l1n1 * 0.32573 * n.y * en;
@@ -1304,8 +1304,7 @@ void fragment_shader(in SceneData scene_data) {
}
} else {
- uint idx = instances.data[instance_index].gi_offset >> 20;
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[idx].exposure_normalization;
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
}
}
#else
diff --git a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
index cdf81bb6ec..7f6a9a50e5 100644
--- a/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
+++ b/servers/rendering/renderer_rd/shaders/forward_mobile/scene_forward_mobile.glsl
@@ -1121,11 +1121,10 @@ void main() {
} else if (bool(draw_call.flags & INSTANCE_FLAGS_USE_LIGHTMAP)) { // has actual lightmap
bool uses_sh = bool(draw_call.flags & INSTANCE_FLAGS_USE_SH_LIGHTMAP);
uint ofs = draw_call.gi_offset & 0xFFFF;
+ uint slice = draw_call.gi_offset >> 16;
vec3 uvw;
uvw.xy = uv2 * draw_call.lightmap_uv_scale.zw + draw_call.lightmap_uv_scale.xy;
- uvw.z = float((draw_call.gi_offset >> 16) & 0xFFFF);
-
- uint idx = draw_call.gi_offset >> 20;
+ uvw.z = float(slice);
if (uses_sh) {
uvw.z *= 4.0; //SH textures use 4 times more data
@@ -1134,8 +1133,8 @@ void main() {
vec3 lm_light_l1_0 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 2.0), 0.0).rgb;
vec3 lm_light_l1p1 = textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw + vec3(0.0, 0.0, 3.0), 0.0).rgb;
- vec3 n = normalize(lightmaps.data[idx].normal_xform * normal);
- float exposure_normalization = lightmaps.data[idx].exposure_normalization;
+ vec3 n = normalize(lightmaps.data[ofs].normal_xform * normal);
+ float exposure_normalization = lightmaps.data[ofs].exposure_normalization;
ambient_light += lm_light_l0 * 0.282095f;
ambient_light += lm_light_l1n1 * 0.32573 * n.y * exposure_normalization;
@@ -1149,7 +1148,7 @@ void main() {
}
} else {
- ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[idx].exposure_normalization;
+ ambient_light += textureLod(sampler2DArray(lightmap_textures[ofs], SAMPLER_LINEAR_CLAMP), uvw, 0.0).rgb * lightmaps.data[ofs].exposure_normalization;
}
}
diff --git a/servers/rendering/renderer_viewport.cpp b/servers/rendering/renderer_viewport.cpp
index 5880bf3951..8dd591a28e 100644
--- a/servers/rendering/renderer_viewport.cpp
+++ b/servers/rendering/renderer_viewport.cpp
@@ -714,7 +714,7 @@ void RendererViewport::draw_viewports() {
// commit our eyes
Vector<BlitToScreen> blits = xr_interface->post_draw_viewport(vp->render_target, vp->viewport_to_screen_rect);
if (vp->viewport_to_screen != DisplayServer::INVALID_WINDOW_ID) {
- if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3" || OS::get_singleton()->get_current_rendering_driver_name() == "opengl3_angle") {
if (blits.size() > 0) {
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blits.ptr(), blits.size());
}
@@ -753,7 +753,7 @@ void RendererViewport::draw_viewports() {
blit_to_screen_list[vp->viewport_to_screen] = Vector<BlitToScreen>();
}
- if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3") {
+ if (OS::get_singleton()->get_current_rendering_driver_name() == "opengl3" || OS::get_singleton()->get_current_rendering_driver_name() == "opengl3_angle") {
Vector<BlitToScreen> blit_to_screen_vec;
blit_to_screen_vec.push_back(blit);
RSG::rasterizer->blit_render_targets_to_screen(vp->viewport_to_screen, blit_to_screen_vec.ptr(), 1);
diff --git a/servers/rendering/rendering_server_default.cpp b/servers/rendering/rendering_server_default.cpp
index c4464cb180..b13d33de9e 100644
--- a/servers/rendering/rendering_server_default.cpp
+++ b/servers/rendering/rendering_server_default.cpp
@@ -91,7 +91,7 @@ void RenderingServerDefault::_draw(bool p_swap_buffers, double frame_step) {
RSG::viewport->draw_viewports();
RSG::canvas_render->update();
- if (OS::get_singleton()->get_current_rendering_driver_name() != "opengl3") {
+ if (OS::get_singleton()->get_current_rendering_driver_name() != "opengl3" && OS::get_singleton()->get_current_rendering_driver_name() != "opengl3_angle") {
// Already called for gl_compatibility renderer.
RSG::rasterizer->end_frame(p_swap_buffers);
}
diff --git a/servers/rendering/shader_types.cpp b/servers/rendering/shader_types.cpp
index 728089f516..38574b0597 100644
--- a/servers/rendering/shader_types.cpp
+++ b/servers/rendering/shader_types.cpp
@@ -321,6 +321,7 @@ ShaderTypes::ShaderTypes() {
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ PNAME("blend"), "mix", "add", "sub", "mul", "premul_alpha", "disabled" });
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ PNAME("unshaded") });
shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ PNAME("light_only") });
+ shader_modes[RS::SHADER_CANVAS_ITEM].modes.push_back({ PNAME("world_vertex_coords") });
}
/************ PARTICLES **************************/
diff --git a/servers/xr/xr_interface.cpp b/servers/xr/xr_interface.cpp
index 416f08dbb6..9ced28fd52 100644
--- a/servers/xr/xr_interface.cpp
+++ b/servers/xr/xr_interface.cpp
@@ -79,6 +79,8 @@ void XRInterface::_bind_methods() {
/** environment blend mode. */
ClassDB::bind_method(D_METHOD("get_supported_environment_blend_modes"), &XRInterface::get_supported_environment_blend_modes);
ClassDB::bind_method(D_METHOD("set_environment_blend_mode", "mode"), &XRInterface::set_environment_blend_mode);
+ ClassDB::bind_method(D_METHOD("get_environment_blend_mode"), &XRInterface::get_environment_blend_mode);
+ ADD_PROPERTY(PropertyInfo(Variant::INT, "environment_blend_mode"), "set_environment_blend_mode", "get_environment_blend_mode");
ADD_GROUP("AR", "ar_");
ADD_PROPERTY(PropertyInfo(Variant::BOOL, "ar_is_anchor_detection_enabled"), "set_anchor_detection_is_enabled", "get_anchor_detection_is_enabled");
diff --git a/servers/xr/xr_interface.h b/servers/xr/xr_interface.h
index b42cb37234..c76d0fbf68 100644
--- a/servers/xr/xr_interface.h
+++ b/servers/xr/xr_interface.h
@@ -147,6 +147,7 @@ public:
/** environment blend mode. */
virtual Array get_supported_environment_blend_modes();
+ virtual XRInterface::EnvironmentBlendMode get_environment_blend_mode() const { return XR_ENV_BLEND_MODE_OPAQUE; }
virtual bool set_environment_blend_mode(EnvironmentBlendMode mode) { return false; }
XRInterface();
diff --git a/tests/core/io/test_resource.h b/tests/core/io/test_resource.h
index 8fc2a2f040..9ddb51220b 100644
--- a/tests/core/io/test_resource.h
+++ b/tests/core/io/test_resource.h
@@ -139,7 +139,7 @@ TEST_CASE("[Resource] Breaking circular references on save") {
loaded_resource_c_binary->get_name() == "C",
"The loaded child resource name should be equal to the expected value.");
CHECK_MESSAGE(
- !loaded_resource_c_binary->get_meta("next"),
+ !loaded_resource_c_binary->has_meta("next"),
"The loaded child resource circular reference should be NULL.");
const Ref<Resource> &loaded_resource_a_text = ResourceLoader::load(save_path_text);
@@ -155,7 +155,7 @@ TEST_CASE("[Resource] Breaking circular references on save") {
loaded_resource_c_text->get_name() == "C",
"The loaded child resource name should be equal to the expected value.");
CHECK_MESSAGE(
- !loaded_resource_c_text->get_meta("next"),
+ !loaded_resource_c_text->has_meta("next"),
"The loaded child resource circular reference should be NULL.");
// Break circular reference to avoid memory leak
diff --git a/tests/core/math/test_math_funcs.h b/tests/core/math/test_math_funcs.h
index e3504ef1e5..d046656b0f 100644
--- a/tests/core/math/test_math_funcs.h
+++ b/tests/core/math/test_math_funcs.h
@@ -54,6 +54,8 @@ TEST_CASE("[Math] C++ macros") {
CHECK(SIGN(-5) == -1.0);
CHECK(SIGN(0) == 0.0);
CHECK(SIGN(5) == 1.0);
+ // Check that SIGN(NAN) returns 0.0.
+ CHECK(SIGN(NAN) == 0.0);
}
TEST_CASE("[Math] Power of two functions") {
diff --git a/tests/core/variant/test_variant_utility.h b/tests/core/variant/test_variant_utility.h
new file mode 100644
index 0000000000..93458b63f4
--- /dev/null
+++ b/tests/core/variant/test_variant_utility.h
@@ -0,0 +1,141 @@
+/**************************************************************************/
+/* test_variant_utility.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_VARIANT_UTILITY_H
+#define TEST_VARIANT_UTILITY_H
+
+#include "core/variant/variant_utility.h"
+
+#include "tests/test_macros.h"
+
+namespace TestVariantUtility {
+
+TEST_CASE("[VariantUtility] Type conversion") {
+ Variant converted;
+ converted = VariantUtilityFunctions::type_convert("Hi!", Variant::Type::NIL);
+ CHECK(converted.get_type() == Variant::Type::NIL);
+ CHECK(converted == Variant());
+
+ converted = VariantUtilityFunctions::type_convert("Hi!", Variant::Type::INT);
+ CHECK(converted.get_type() == Variant::Type::INT);
+ CHECK(converted == Variant(0));
+
+ converted = VariantUtilityFunctions::type_convert("123", Variant::Type::INT);
+ CHECK(converted.get_type() == Variant::Type::INT);
+ CHECK(converted == Variant(123));
+
+ converted = VariantUtilityFunctions::type_convert(123, Variant::Type::STRING);
+ CHECK(converted.get_type() == Variant::Type::STRING);
+ CHECK(converted == Variant("123"));
+
+ converted = VariantUtilityFunctions::type_convert(123.4, Variant::Type::INT);
+ CHECK(converted.get_type() == Variant::Type::INT);
+ CHECK(converted == Variant(123));
+
+ converted = VariantUtilityFunctions::type_convert(5, Variant::Type::VECTOR2);
+ CHECK(converted.get_type() == Variant::Type::VECTOR2);
+ CHECK(converted == Variant(Vector2(0, 0)));
+
+ converted = VariantUtilityFunctions::type_convert(Vector3(1, 2, 3), Variant::Type::VECTOR2);
+ CHECK(converted.get_type() == Variant::Type::VECTOR2);
+ CHECK(converted == Variant(Vector2(1, 2)));
+
+ converted = VariantUtilityFunctions::type_convert(Vector2(1, 2), Variant::Type::VECTOR4);
+ CHECK(converted.get_type() == Variant::Type::VECTOR4);
+ CHECK(converted == Variant(Vector4(1, 2, 0, 0)));
+
+ converted = VariantUtilityFunctions::type_convert(Vector4(1.2, 3.4, 5.6, 7.8), Variant::Type::VECTOR3I);
+ CHECK(converted.get_type() == Variant::Type::VECTOR3I);
+ CHECK(converted == Variant(Vector3i(1, 3, 5)));
+
+ {
+ Basis basis = Basis::from_scale(Vector3(1.2, 3.4, 5.6));
+ Transform3D transform = Transform3D(basis, Vector3());
+
+ converted = VariantUtilityFunctions::type_convert(transform, Variant::Type::BASIS);
+ CHECK(converted.get_type() == Variant::Type::BASIS);
+ CHECK(converted == basis);
+
+ converted = VariantUtilityFunctions::type_convert(basis, Variant::Type::TRANSFORM3D);
+ CHECK(converted.get_type() == Variant::Type::TRANSFORM3D);
+ CHECK(converted == transform);
+
+ converted = VariantUtilityFunctions::type_convert(basis, Variant::Type::STRING);
+ CHECK(converted.get_type() == Variant::Type::STRING);
+ CHECK(converted == Variant("[X: (1.2, 0, 0), Y: (0, 3.4, 0), Z: (0, 0, 5.6)]"));
+ }
+
+ {
+ Array arr;
+ arr.push_back(1.2);
+ arr.push_back(3.4);
+ arr.push_back(5.6);
+
+ PackedFloat64Array packed;
+ packed.push_back(1.2);
+ packed.push_back(3.4);
+ packed.push_back(5.6);
+
+ converted = VariantUtilityFunctions::type_convert(arr, Variant::Type::PACKED_FLOAT64_ARRAY);
+ CHECK(converted.get_type() == Variant::Type::PACKED_FLOAT64_ARRAY);
+ CHECK(converted == packed);
+
+ converted = VariantUtilityFunctions::type_convert(packed, Variant::Type::ARRAY);
+ CHECK(converted.get_type() == Variant::Type::ARRAY);
+ CHECK(converted == arr);
+ }
+
+ {
+ // Check that using Variant::call_utility_function also works.
+ Vector<const Variant *> args;
+ Variant data_arg = "Hi!";
+ args.push_back(&data_arg);
+ Variant type_arg = Variant::Type::NIL;
+ args.push_back(&type_arg);
+ Callable::CallError call_error;
+ Variant::call_utility_function("type_convert", &converted, (const Variant **)args.ptr(), 2, call_error);
+ CHECK(converted.get_type() == Variant::Type::NIL);
+ CHECK(converted == Variant());
+
+ type_arg = Variant::Type::INT;
+ Variant::call_utility_function("type_convert", &converted, (const Variant **)args.ptr(), 2, call_error);
+ CHECK(converted.get_type() == Variant::Type::INT);
+ CHECK(converted == Variant(0));
+
+ data_arg = "123";
+ Variant::call_utility_function("type_convert", &converted, (const Variant **)args.ptr(), 2, call_error);
+ CHECK(converted.get_type() == Variant::Type::INT);
+ CHECK(converted == Variant(123));
+ }
+}
+
+} // namespace TestVariantUtility
+
+#endif // TEST_VARIANT_UTILITY_H
diff --git a/tests/scene/test_code_edit.h b/tests/scene/test_code_edit.h
index 72421c9cc9..8576b38ce2 100644
--- a/tests/scene/test_code_edit.h
+++ b/tests/scene/test_code_edit.h
@@ -2839,6 +2839,194 @@ TEST_CASE("[SceneTree][CodeEdit] folding") {
memdelete(code_edit);
}
+TEST_CASE("[SceneTree][CodeEdit] region folding") {
+ CodeEdit *code_edit = memnew(CodeEdit);
+ SceneTree::get_singleton()->get_root()->add_child(code_edit);
+ code_edit->grab_focus();
+
+ SUBCASE("[CodeEdit] region folding") {
+ code_edit->set_line_folding_enabled(true);
+
+ // Region tag detection.
+ code_edit->set_text("#region region_name\nline2\n#endregion");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ CHECK(code_edit->is_line_code_region_start(0));
+ CHECK_FALSE(code_edit->is_line_code_region_start(1));
+ CHECK_FALSE(code_edit->is_line_code_region_start(2));
+ CHECK_FALSE(code_edit->is_line_code_region_end(0));
+ CHECK_FALSE(code_edit->is_line_code_region_end(1));
+ CHECK(code_edit->is_line_code_region_end(2));
+
+ // Region tag customization.
+ code_edit->set_text("#region region_name\nline2\n#endregion\n#open region_name\nline2\n#close");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ CHECK(code_edit->is_line_code_region_start(0));
+ CHECK(code_edit->is_line_code_region_end(2));
+ CHECK_FALSE(code_edit->is_line_code_region_start(3));
+ CHECK_FALSE(code_edit->is_line_code_region_end(5));
+ code_edit->set_code_region_tags("open", "close");
+ CHECK_FALSE(code_edit->is_line_code_region_start(0));
+ CHECK_FALSE(code_edit->is_line_code_region_end(2));
+ CHECK(code_edit->is_line_code_region_start(3));
+ CHECK(code_edit->is_line_code_region_end(5));
+ code_edit->set_code_region_tags("region", "endregion");
+
+ // Setting identical start and end region tags should fail.
+ CHECK(code_edit->get_code_region_start_tag() == "region");
+ CHECK(code_edit->get_code_region_end_tag() == "endregion");
+ ERR_PRINT_OFF;
+ code_edit->set_code_region_tags("same_tag", "same_tag");
+ ERR_PRINT_ON;
+ CHECK(code_edit->get_code_region_start_tag() == "region");
+ CHECK(code_edit->get_code_region_end_tag() == "endregion");
+
+ // Region creation with selection adds start / close region lines.
+ code_edit->set_text("line1\nline2\nline3");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->select(1, 0, 1, 4);
+ code_edit->create_code_region();
+ CHECK(code_edit->is_line_code_region_start(1));
+ CHECK(code_edit->get_line(2).contains("line2"));
+ CHECK(code_edit->is_line_code_region_end(3));
+
+ // Region creation without any selection has no effect.
+ code_edit->set_text("line1\nline2\nline3");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->create_code_region();
+ CHECK(code_edit->get_text() == "line1\nline2\nline3");
+
+ // Region creation with multiple selections.
+ code_edit->set_text("line1\nline2\nline3");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->select(0, 0, 0, 4, 0);
+ code_edit->add_caret(2, 5);
+ code_edit->select(2, 0, 2, 5, 1);
+ code_edit->create_code_region();
+ CHECK(code_edit->get_text() == "#region New Code Region\nline1\n#endregion\nline2\n#region New Code Region\nline3\n#endregion");
+
+ // Two selections on the same line create only one region.
+ code_edit->set_text("test line1\ntest line2\ntest line3");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->select(0, 0, 1, 2, 0);
+ code_edit->add_caret(1, 4);
+ code_edit->select(1, 4, 2, 5, 1);
+ code_edit->create_code_region();
+ CHECK(code_edit->get_text() == "#region New Code Region\ntest line1\ntest line2\ntest line3\n#endregion");
+
+ // Region tag with // comment delimiter.
+ code_edit->set_text("//region region_name\nline2\n//endregion");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("//", "");
+ CHECK(code_edit->is_line_code_region_start(0));
+ CHECK(code_edit->is_line_code_region_end(2));
+
+ // Creating region with no valid one line comment delimiter has no effect.
+ code_edit->set_text("line1\nline2\nline3");
+ code_edit->clear_comment_delimiters();
+ code_edit->create_code_region();
+ CHECK(code_edit->get_text() == "line1\nline2\nline3");
+ code_edit->add_comment_delimiter("/*", "*/");
+ code_edit->create_code_region();
+ CHECK(code_edit->get_text() == "line1\nline2\nline3");
+
+ // Choose one line comment delimiter.
+ code_edit->set_text("//region region_name\nline2\n//endregion");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("/*", "*/");
+ code_edit->add_comment_delimiter("//", "");
+ CHECK(code_edit->is_line_code_region_start(0));
+ CHECK(code_edit->is_line_code_region_end(2));
+
+ // Update code region delimiter when removing comment delimiter.
+ code_edit->set_text("//region region_name\nline2\n//endregion\n#region region_name\nline2\n#endregion");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("//", "");
+ code_edit->add_comment_delimiter("#", "");
+ CHECK(code_edit->is_line_code_region_start(0));
+ CHECK(code_edit->is_line_code_region_end(2));
+ CHECK_FALSE(code_edit->is_line_code_region_start(3));
+ CHECK_FALSE(code_edit->is_line_code_region_end(5));
+ code_edit->remove_comment_delimiter("//");
+ CHECK_FALSE(code_edit->is_line_code_region_start(0));
+ CHECK_FALSE(code_edit->is_line_code_region_end(2));
+ CHECK(code_edit->is_line_code_region_start(3));
+ CHECK(code_edit->is_line_code_region_end(5));
+
+ // Update code region delimiter when clearing comment delimiters.
+ code_edit->set_text("//region region_name\nline2\n//endregion");
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("//", "");
+ CHECK(code_edit->is_line_code_region_start(0));
+ CHECK(code_edit->is_line_code_region_end(2));
+ code_edit->clear_comment_delimiters();
+ CHECK_FALSE(code_edit->is_line_code_region_start(0));
+ CHECK_FALSE(code_edit->is_line_code_region_end(2));
+
+ // Fold region.
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->set_text("#region region_name\nline2\nline3\n#endregion\nvisible line");
+ CHECK(code_edit->can_fold_line(0));
+ for (int i = 1; i < 5; i++) {
+ CHECK_FALSE(code_edit->can_fold_line(i));
+ }
+ for (int i = 0; i < 5; i++) {
+ CHECK_FALSE(code_edit->is_line_folded(i));
+ }
+ code_edit->fold_line(0);
+ CHECK(code_edit->is_line_folded(0));
+ CHECK(code_edit->get_next_visible_line_offset_from(1, 1) == 4);
+
+ // Region with no end can't be folded.
+ ERR_PRINT_OFF;
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->set_text("#region region_name\nline2\nline3\n#bad_end_tag\nvisible line");
+ CHECK_FALSE(code_edit->can_fold_line(0));
+ ERR_PRINT_ON;
+
+ // Bad nested region can't be folded.
+ ERR_PRINT_OFF;
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->set_text("#region without end\n#region region2\nline3\n#endregion\n#no_end");
+ CHECK_FALSE(code_edit->can_fold_line(0));
+ CHECK(code_edit->can_fold_line(1));
+ ERR_PRINT_ON;
+
+ // Nested region folding.
+ ERR_PRINT_OFF;
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->set_text("#region region1\n#region region2\nline3\n#endregion\n#endregion");
+ CHECK(code_edit->can_fold_line(0));
+ CHECK(code_edit->can_fold_line(1));
+ code_edit->fold_line(1);
+ CHECK(code_edit->get_next_visible_line_offset_from(2, 1) == 3);
+ code_edit->fold_line(0);
+ CHECK(code_edit->get_next_visible_line_offset_from(1, 1) == 4);
+ ERR_PRINT_ON;
+
+ // Unfolding a line inside a region unfold whole region.
+ code_edit->clear_comment_delimiters();
+ code_edit->add_comment_delimiter("#", "");
+ code_edit->set_text("#region region\ninside\nline3\n#endregion\nvisible");
+ code_edit->fold_line(0);
+ CHECK(code_edit->is_line_folded(0));
+ CHECK(code_edit->get_next_visible_line_offset_from(1, 1) == 4);
+ code_edit->unfold_line(1);
+ CHECK_FALSE(code_edit->is_line_folded(0));
+ }
+
+ memdelete(code_edit);
+}
+
TEST_CASE("[SceneTree][CodeEdit] completion") {
CodeEdit *code_edit = memnew(CodeEdit);
SceneTree::get_singleton()->get_root()->add_child(code_edit);
diff --git a/tests/scene/test_curve_3d.h b/tests/scene/test_curve_3d.h
index 4d7b718d7e..d73bb1ad35 100644
--- a/tests/scene/test_curve_3d.h
+++ b/tests/scene/test_curve_3d.h
@@ -209,6 +209,14 @@ TEST_CASE("[Curve3D] Sampling") {
CHECK(curve->get_closest_point(Vector3(50, 50, 0)) == Vector3(0, 50, 0));
CHECK(curve->get_closest_point(Vector3(0, 100, 0)) == Vector3(0, 50, 0));
}
+
+ SUBCASE("sample_baked_up_vector, off-axis") {
+ // Regression test for issue #81879
+ Ref<Curve3D> c = memnew(Curve3D);
+ c->add_point(Vector3());
+ c->add_point(Vector3(0, .1, 1));
+ CHECK_LT((c->sample_baked_up_vector(c->get_closest_offset(Vector3(0, 0, .9))) - Vector3(0, 0.995037, -0.099504)).length(), 0.01);
+ }
}
TEST_CASE("[Curve3D] Tessellation") {
diff --git a/tests/scene/test_text_edit.h b/tests/scene/test_text_edit.h
index 79766cd919..7e9b472af1 100644
--- a/tests/scene/test_text_edit.h
+++ b/tests/scene/test_text_edit.h
@@ -3241,6 +3241,15 @@ TEST_CASE("[SceneTree][TextEdit] mouse") {
SceneTree::get_singleton()->get_root()->add_child(text_edit);
text_edit->set_size(Size2(800, 200));
+
+ CHECK(text_edit->get_rect_at_line_column(0, 0).get_position() == Point2i(0, 0));
+
+ text_edit->set_line(0, "A");
+ MessageQueue::get_singleton()->flush();
+ CHECK(text_edit->get_rect_at_line_column(0, 1).get_position().x > 0);
+
+ text_edit->clear(); // Necessary, otherwise the following test cases fail.
+
text_edit->set_line(0, "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Donec vasius mattis leo, sed porta ex lacinia bibendum. Nunc bibendum pellentesque.");
MessageQueue::get_singleton()->flush();
diff --git a/tests/servers/rendering/test_shader_preprocessor.h b/tests/servers/rendering/test_shader_preprocessor.h
index c8c143641b..e12da8a2db 100644
--- a/tests/servers/rendering/test_shader_preprocessor.h
+++ b/tests/servers/rendering/test_shader_preprocessor.h
@@ -294,7 +294,7 @@ TEST_CASE("[ShaderPreprocessor] Concatenation sorting network") {
CHECK_SHADER_EQ(result, expected);
}
-TEST_CASE("[ShaderPreprocessor] Undefined behaviour") {
+TEST_CASE("[ShaderPreprocessor] Undefined behavior") {
// None of these are valid concatenation, nor valid shader code.
// Don't care about results, just make sure there's no crash.
const String filename("somefile.gdshader");
diff --git a/tests/test_main.cpp b/tests/test_main.cpp
index 3a80fc8c00..a43dfaa57f 100644
--- a/tests/test_main.cpp
+++ b/tests/test_main.cpp
@@ -89,6 +89,7 @@
#include "tests/core/variant/test_array.h"
#include "tests/core/variant/test_dictionary.h"
#include "tests/core/variant/test_variant.h"
+#include "tests/core/variant/test_variant_utility.h"
#include "tests/scene/test_animation.h"
#include "tests/scene/test_arraymesh.h"
#include "tests/scene/test_audio_stream_wav.h"
diff --git a/thirdparty/README.md b/thirdparty/README.md
index bd3c626b65..87d9d8e32c 100644
--- a/thirdparty/README.md
+++ b/thirdparty/README.md
@@ -17,6 +17,18 @@ Files extracted from upstream source:
- `license.txt`
+## angle
+
+- Upstream: https://chromium.googlesource.com/angle/angle/
+- Version: git (chromium/5907, 430a4f559cbc2bcd5d026e8b36ee46ddd80e9651, 2023)
+- License: BSD-3-Clause
+
+Files extracted from upstream source:
+
+- `include/*`
+- `LICENSE`
+
+
## astcenc
- Upstream: https://github.com/ARM-software/astc-encoder
@@ -243,7 +255,10 @@ Files extracted from upstream source:
- `LICENSE`
Files generated from [upstream web instance](https://gen.glad.sh/):
+- `EGL/eglplatform.h`
- `KHR/khrplatform.h`
+- `egl.c`
+- `glad/egl.h`
- `gl.c`
- `glad/gl.h`
- `glx.c`
@@ -252,6 +267,9 @@ Files generated from [upstream web instance](https://gen.glad.sh/):
See the permalinks in `glad/gl.h` and `glad/glx.h` to regenrate the files with
a new version of the web instance.
+Some changes have been made in order to allow loading OpenGL and OpenGLES APIs at the same time.
+See the patches in the `patches` directory.
+
## glslang
@@ -417,7 +435,7 @@ Files extracted from upstream source:
## libwebp
- Upstream: https://chromium.googlesource.com/webm/libwebp/
-- Version: 1.3.1 (fd7bb21c0cb56e8a82e9bfa376164b842f433f3b, 2023)
+- Version: 1.3.2 (ca332209cb5567c9b249c86788cb2dbf8847e760, 2023)
- License: BSD-3-Clause
Files extracted from upstream source:
diff --git a/thirdparty/angle/LICENSE b/thirdparty/angle/LICENSE
new file mode 100644
index 0000000000..0f65fd60fd
--- /dev/null
+++ b/thirdparty/angle/LICENSE
@@ -0,0 +1,32 @@
+// Copyright 2018 The ANGLE Project Authors.
+// All rights reserved.
+//
+// Redistribution and use in source and binary forms, with or without
+// modification, are permitted provided that the following conditions
+// are met:
+//
+// Redistributions of source code must retain the above copyright
+// notice, this list of conditions and the following disclaimer.
+//
+// Redistributions in binary form must reproduce the above
+// copyright notice, this list of conditions and the following
+// disclaimer in the documentation and/or other materials provided
+// with the distribution.
+//
+// Neither the name of TransGaming Inc., Google Inc., 3DLabs Inc.
+// Ltd., nor the names of their contributors may be used to endorse
+// or promote products derived from this software without specific
+// prior written permission.
+//
+// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+// "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+// LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+// FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+// COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
+// INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING,
+// BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
+// CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+// LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN
+// ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
+// POSSIBILITY OF SUCH DAMAGE.
diff --git a/thirdparty/angle/include/EGL/egl.h b/thirdparty/angle/include/EGL/egl.h
new file mode 100644
index 0000000000..97d0878cc7
--- /dev/null
+++ b/thirdparty/angle/include/EGL/egl.h
@@ -0,0 +1,342 @@
+#ifndef __egl_h_
+#define __egl_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright 2013-2020 The Khronos Group Inc.
+** SPDX-License-Identifier: Apache-2.0
+**
+** This header is generated from the Khronos EGL XML API Registry.
+** The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.khronos.org/registry/egl
+**
+** Khronos $Git commit SHA1: 6fb1daea15 $ on $Git commit date: 2022-05-25 09:41:13 -0600 $
+*/
+
+#include <EGL/eglplatform.h>
+
+#ifndef EGL_EGL_PROTOTYPES
+#define EGL_EGL_PROTOTYPES 1
+#endif
+
+/* Generated on date 20220525 */
+
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: .*
+ * Default extensions included: None
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_VERSION_1_0
+#define EGL_VERSION_1_0 1
+typedef unsigned int EGLBoolean;
+typedef void *EGLDisplay;
+#include <KHR/khrplatform.h>
+#include <EGL/eglplatform.h>
+typedef void *EGLConfig;
+typedef void *EGLSurface;
+typedef void *EGLContext;
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_DONT_CARE EGL_CAST(EGLint,-1)
+#define EGL_DRAW 0x3059
+#define EGL_EXTENSIONS 0x3055
+#define EGL_FALSE 0
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_HEIGHT 0x3056
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_LEVEL 0x3029
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_NONE 0x3038
+#define EGL_NON_CONFORMANT_CONFIG 0x3051
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)
+#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)
+#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)
+#define EGL_PBUFFER_BIT 0x0001
+#define EGL_PIXMAP_BIT 0x0002
+#define EGL_READ 0x305A
+#define EGL_RED_SIZE 0x3024
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SLOW_CONFIG 0x3050
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_SUCCESS 0x3000
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_TRANSPARENT_RGB 0x3052
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRUE 1
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_WIDTH 0x3057
+#define EGL_WINDOW_BIT 0x0004
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCHOOSECONFIGPROC) (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOPYBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+typedef EGLContext (EGLAPIENTRYP PFNEGLCREATECONTEXTPROC) (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERSURFACEPROC) (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGATTRIBPROC) (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCONFIGSPROC) (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETCURRENTDISPLAYPROC) (void);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLGETCURRENTSURFACEPROC) (EGLint readdraw);
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETDISPLAYPROC) (EGLNativeDisplayType display_id);
+typedef EGLint (EGLAPIENTRYP PFNEGLGETERRORPROC) (void);
+typedef __eglMustCastToProperFunctionPointerType (EGLAPIENTRYP PFNEGLGETPROCADDRESSPROC) (const char *procname);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLINITIALIZEPROC) (EGLDisplay dpy, EGLint *major, EGLint *minor);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLMAKECURRENTPROC) (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYCONTEXTPROC) (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGPROC) (EGLDisplay dpy, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSPROC) (EGLDisplay dpy, EGLSurface surface);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLTERMINATEPROC) (EGLDisplay dpy);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITGLPROC) (void);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITNATIVEPROC) (EGLint engine);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglChooseConfig (EGLDisplay dpy, const EGLint *attrib_list, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLBoolean EGLAPIENTRY eglCopyBuffers (EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+EGLAPI EGLContext EGLAPIENTRY eglCreateContext (EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferSurface (EGLDisplay dpy, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurface (EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreateWindowSurface (EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyContext (EGLDisplay dpy, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySurface (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigAttrib (EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetConfigs (EGLDisplay dpy, EGLConfig *configs, EGLint config_size, EGLint *num_config);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetCurrentDisplay (void);
+EGLAPI EGLSurface EGLAPIENTRY eglGetCurrentSurface (EGLint readdraw);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetDisplay (EGLNativeDisplayType display_id);
+EGLAPI EGLint EGLAPIENTRY eglGetError (void);
+EGLAPI __eglMustCastToProperFunctionPointerType EGLAPIENTRY eglGetProcAddress (const char *procname);
+EGLAPI EGLBoolean EGLAPIENTRY eglInitialize (EGLDisplay dpy, EGLint *major, EGLint *minor);
+EGLAPI EGLBoolean EGLAPIENTRY eglMakeCurrent (EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryContext (EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint *value);
+EGLAPI const char *EGLAPIENTRY eglQueryString (EGLDisplay dpy, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffers (EGLDisplay dpy, EGLSurface surface);
+EGLAPI EGLBoolean EGLAPIENTRY eglTerminate (EGLDisplay dpy);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitGL (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitNative (EGLint engine);
+#endif
+#endif /* EGL_VERSION_1_0 */
+
+#ifndef EGL_VERSION_1_1
+#define EGL_VERSION_1_1 1
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_CONTEXT_LOST 0x300E
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_TEXTURE_2D 0x305F
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_TARGET 0x3081
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDTEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASETEXIMAGEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSURFACEATTRIBPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPINTERVALPROC) (EGLDisplay dpy, EGLint interval);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglBindTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseTexImage (EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+EGLAPI EGLBoolean EGLAPIENTRY eglSurfaceAttrib (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapInterval (EGLDisplay dpy, EGLint interval);
+#endif
+#endif /* EGL_VERSION_1_1 */
+
+#ifndef EGL_VERSION_1_2
+#define EGL_VERSION_1_2 1
+typedef unsigned int EGLenum;
+typedef void *EGLClientBuffer;
+#define EGL_ALPHA_FORMAT 0x3088
+#define EGL_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_ALPHA_FORMAT_PRE 0x308C
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_BUFFER_PRESERVED 0x3094
+#define EGL_BUFFER_DESTROYED 0x3095
+#define EGL_CLIENT_APIS 0x308D
+#define EGL_COLORSPACE 0x3087
+#define EGL_COLORSPACE_sRGB 0x3089
+#define EGL_COLORSPACE_LINEAR 0x308A
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+#define EGL_DISPLAY_SCALING 10000
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_LUMINANCE_BUFFER 0x308F
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_OPENGL_ES_BIT 0x0001
+#define EGL_OPENVG_BIT 0x0002
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENVG_API 0x30A1
+#define EGL_OPENVG_IMAGE 0x3096
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_RGB_BUFFER 0x308E
+#define EGL_SINGLE_BUFFER 0x3085
+#define EGL_SWAP_BEHAVIOR 0x3093
+#define EGL_UNKNOWN EGL_CAST(EGLint,-1)
+#define EGL_VERTICAL_RESOLUTION 0x3091
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDAPIPROC) (EGLenum api);
+typedef EGLenum (EGLAPIENTRYP PFNEGLQUERYAPIPROC) (void);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLRELEASETHREADPROC) (void);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITCLIENTPROC) (void);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglBindAPI (EGLenum api);
+EGLAPI EGLenum EGLAPIENTRY eglQueryAPI (void);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePbufferFromClientBuffer (EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseThread (void);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitClient (void);
+#endif
+#endif /* EGL_VERSION_1_2 */
+
+#ifndef EGL_VERSION_1_3
+#define EGL_VERSION_1_3 1
+#define EGL_CONFORMANT 0x3042
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_MATCH_NATIVE_PIXMAP 0x3041
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_VG_ALPHA_FORMAT 0x3088
+#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
+#define EGL_VG_COLORSPACE 0x3087
+#define EGL_VG_COLORSPACE_sRGB 0x3089
+#define EGL_VG_COLORSPACE_LINEAR 0x308A
+#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
+#endif /* EGL_VERSION_1_3 */
+
+#ifndef EGL_VERSION_1_4
+#define EGL_VERSION_1_4 1
+#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
+#define EGL_MULTISAMPLE_RESOLVE 0x3099
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
+#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
+#define EGL_OPENGL_API 0x30A2
+#define EGL_OPENGL_BIT 0x0008
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
+typedef EGLContext (EGLAPIENTRYP PFNEGLGETCURRENTCONTEXTPROC) (void);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLContext EGLAPIENTRY eglGetCurrentContext (void);
+#endif
+#endif /* EGL_VERSION_1_4 */
+
+#ifndef EGL_VERSION_1_5
+#define EGL_VERSION_1_5 1
+typedef void *EGLSync;
+typedef intptr_t EGLAttrib;
+typedef khronos_utime_nanoseconds_t EGLTime;
+typedef void *EGLImage;
+#define EGL_CONTEXT_MAJOR_VERSION 0x3098
+#define EGL_CONTEXT_MINOR_VERSION 0x30FB
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
+#define EGL_NO_RESET_NOTIFICATION 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
+#define EGL_OPENGL_ES3_BIT 0x00000040
+#define EGL_CL_EVENT_HANDLE 0x309C
+#define EGL_SYNC_CL_EVENT 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
+#define EGL_SYNC_TYPE 0x30F7
+#define EGL_SYNC_STATUS 0x30F1
+#define EGL_SYNC_CONDITION 0x30F8
+#define EGL_SIGNALED 0x30F2
+#define EGL_UNSIGNALED 0x30F3
+#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
+#define EGL_FOREVER 0xFFFFFFFFFFFFFFFFull
+#define EGL_TIMEOUT_EXPIRED 0x30F5
+#define EGL_CONDITION_SATISFIED 0x30F6
+#define EGL_NO_SYNC EGL_CAST(EGLSync,0)
+#define EGL_SYNC_FENCE 0x30F9
+#define EGL_GL_COLORSPACE 0x309D
+#define EGL_GL_COLORSPACE_SRGB 0x3089
+#define EGL_GL_COLORSPACE_LINEAR 0x308A
+#define EGL_GL_RENDERBUFFER 0x30B9
+#define EGL_GL_TEXTURE_2D 0x30B1
+#define EGL_GL_TEXTURE_LEVEL 0x30BC
+#define EGL_GL_TEXTURE_3D 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
+#define EGL_IMAGE_PRESERVED 0x30D2
+#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)
+typedef EGLSync (EGLAPIENTRYP PFNEGLCREATESYNCPROC) (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCPROC) (EGLDisplay dpy, EGLSync sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBPROC) (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
+typedef EGLImage (EGLAPIENTRYP PFNEGLCREATEIMAGEPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEPROC) (EGLDisplay dpy, EGLImage image);
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYPROC) (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLWAITSYNCPROC) (EGLDisplay dpy, EGLSync sync, EGLint flags);
+#if EGL_EGL_PROTOTYPES
+EGLAPI EGLSync EGLAPIENTRY eglCreateSync (EGLDisplay dpy, EGLenum type, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySync (EGLDisplay dpy, EGLSync sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttrib (EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib *value);
+EGLAPI EGLImage EGLAPIENTRY eglCreateImage (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImage (EGLDisplay dpy, EGLImage image);
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplay (EGLenum platform, void *native_display, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurface (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLAttrib *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurface (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglWaitSync (EGLDisplay dpy, EGLSync sync, EGLint flags);
+#endif
+#endif /* EGL_VERSION_1_5 */
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/thirdparty/angle/include/EGL/eglext.h b/thirdparty/angle/include/EGL/eglext.h
new file mode 100644
index 0000000000..d226b7f6da
--- /dev/null
+++ b/thirdparty/angle/include/EGL/eglext.h
@@ -0,0 +1,1486 @@
+#ifndef __eglext_h_
+#define __eglext_h_ 1
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+/*
+** Copyright 2013-2020 The Khronos Group Inc.
+** SPDX-License-Identifier: Apache-2.0
+**
+** This header is generated from the Khronos EGL XML API Registry.
+** The current version of the Registry, generator scripts
+** used to make the header, and the header can be found at
+** http://www.khronos.org/registry/egl
+**
+** Khronos $Git commit SHA1: 6fb1daea15 $ on $Git commit date: 2022-05-25 09:41:13 -0600 $
+*/
+
+#include <EGL/eglplatform.h>
+
+#define EGL_EGLEXT_VERSION 20220525
+
+/* Generated C header for:
+ * API: egl
+ * Versions considered: .*
+ * Versions emitted: _nomatch_^
+ * Default extensions included: egl
+ * Additional extensions included: _nomatch_^
+ * Extensions removed: _nomatch_^
+ */
+
+#ifndef EGL_KHR_cl_event
+#define EGL_KHR_cl_event 1
+#define EGL_CL_EVENT_HANDLE_KHR 0x309C
+#define EGL_SYNC_CL_EVENT_KHR 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE_KHR 0x30FF
+#endif /* EGL_KHR_cl_event */
+
+#ifndef EGL_KHR_cl_event2
+#define EGL_KHR_cl_event2 1
+typedef void *EGLSyncKHR;
+typedef intptr_t EGLAttribKHR;
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNC64KHRPROC) (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSync64KHR (EGLDisplay dpy, EGLenum type, const EGLAttribKHR *attrib_list);
+#endif
+#endif /* EGL_KHR_cl_event2 */
+
+#ifndef EGL_KHR_client_get_all_proc_addresses
+#define EGL_KHR_client_get_all_proc_addresses 1
+#endif /* EGL_KHR_client_get_all_proc_addresses */
+
+#ifndef EGL_KHR_config_attribs
+#define EGL_KHR_config_attribs 1
+#define EGL_CONFORMANT_KHR 0x3042
+#define EGL_VG_COLORSPACE_LINEAR_BIT_KHR 0x0020
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT_KHR 0x0040
+#endif /* EGL_KHR_config_attribs */
+
+#ifndef EGL_KHR_context_flush_control
+#define EGL_KHR_context_flush_control 1
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_NONE_KHR 0
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_KHR 0x2097
+#define EGL_CONTEXT_RELEASE_BEHAVIOR_FLUSH_KHR 0x2098
+#endif /* EGL_KHR_context_flush_control */
+
+#ifndef EGL_KHR_create_context
+#define EGL_KHR_create_context 1
+#define EGL_CONTEXT_MAJOR_VERSION_KHR 0x3098
+#define EGL_CONTEXT_MINOR_VERSION_KHR 0x30FB
+#define EGL_CONTEXT_FLAGS_KHR 0x30FC
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK_KHR 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_KHR 0x31BD
+#define EGL_NO_RESET_NOTIFICATION_KHR 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_KHR 0x31BF
+#define EGL_CONTEXT_OPENGL_DEBUG_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE_BIT_KHR 0x00000002
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_BIT_KHR 0x00000004
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT_KHR 0x00000001
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT_KHR 0x00000002
+#define EGL_OPENGL_ES3_BIT_KHR 0x00000040
+#endif /* EGL_KHR_create_context */
+
+#ifndef EGL_KHR_create_context_no_error
+#define EGL_KHR_create_context_no_error 1
+#define EGL_CONTEXT_OPENGL_NO_ERROR_KHR 0x31B3
+#endif /* EGL_KHR_create_context_no_error */
+
+#ifndef EGL_KHR_debug
+#define EGL_KHR_debug 1
+typedef void *EGLLabelKHR;
+typedef void *EGLObjectKHR;
+typedef void (EGLAPIENTRY *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);
+#define EGL_OBJECT_THREAD_KHR 0x33B0
+#define EGL_OBJECT_DISPLAY_KHR 0x33B1
+#define EGL_OBJECT_CONTEXT_KHR 0x33B2
+#define EGL_OBJECT_SURFACE_KHR 0x33B3
+#define EGL_OBJECT_IMAGE_KHR 0x33B4
+#define EGL_OBJECT_SYNC_KHR 0x33B5
+#define EGL_OBJECT_STREAM_KHR 0x33B6
+#define EGL_DEBUG_MSG_CRITICAL_KHR 0x33B9
+#define EGL_DEBUG_MSG_ERROR_KHR 0x33BA
+#define EGL_DEBUG_MSG_WARN_KHR 0x33BB
+#define EGL_DEBUG_MSG_INFO_KHR 0x33BC
+#define EGL_DEBUG_CALLBACK_KHR 0x33B8
+typedef EGLint (EGLAPIENTRYP PFNEGLDEBUGMESSAGECONTROLKHRPROC) (EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEBUGKHRPROC) (EGLint attribute, EGLAttrib *value);
+typedef EGLint (EGLAPIENTRYP PFNEGLLABELOBJECTKHRPROC) (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDebugMessageControlKHR (EGLDEBUGPROCKHR callback, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDebugKHR (EGLint attribute, EGLAttrib *value);
+EGLAPI EGLint EGLAPIENTRY eglLabelObjectKHR (EGLDisplay display, EGLenum objectType, EGLObjectKHR object, EGLLabelKHR label);
+#endif
+#endif /* EGL_KHR_debug */
+
+#ifndef EGL_KHR_display_reference
+#define EGL_KHR_display_reference 1
+#define EGL_TRACK_REFERENCES_KHR 0x3352
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBKHRPROC) (EGLDisplay dpy, EGLint name, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribKHR (EGLDisplay dpy, EGLint name, EGLAttrib *value);
+#endif
+#endif /* EGL_KHR_display_reference */
+
+#ifndef EGL_KHR_fence_sync
+#define EGL_KHR_fence_sync 1
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_KHR 0x30F0
+#define EGL_SYNC_CONDITION_KHR 0x30F8
+#define EGL_SYNC_FENCE_KHR 0x30F9
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESYNCKHRPROC) (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateSyncKHR (EGLDisplay dpy, EGLenum type, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncKHR (EGLDisplay dpy, EGLSyncKHR sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags, EGLTimeKHR timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_fence_sync */
+
+#ifndef EGL_KHR_get_all_proc_addresses
+#define EGL_KHR_get_all_proc_addresses 1
+#endif /* EGL_KHR_get_all_proc_addresses */
+
+#ifndef EGL_KHR_gl_colorspace
+#define EGL_KHR_gl_colorspace 1
+#define EGL_GL_COLORSPACE_KHR 0x309D
+#define EGL_GL_COLORSPACE_SRGB_KHR 0x3089
+#define EGL_GL_COLORSPACE_LINEAR_KHR 0x308A
+#endif /* EGL_KHR_gl_colorspace */
+
+#ifndef EGL_KHR_gl_renderbuffer_image
+#define EGL_KHR_gl_renderbuffer_image 1
+#define EGL_GL_RENDERBUFFER_KHR 0x30B9
+#endif /* EGL_KHR_gl_renderbuffer_image */
+
+#ifndef EGL_KHR_gl_texture_2D_image
+#define EGL_KHR_gl_texture_2D_image 1
+#define EGL_GL_TEXTURE_2D_KHR 0x30B1
+#define EGL_GL_TEXTURE_LEVEL_KHR 0x30BC
+#endif /* EGL_KHR_gl_texture_2D_image */
+
+#ifndef EGL_KHR_gl_texture_3D_image
+#define EGL_KHR_gl_texture_3D_image 1
+#define EGL_GL_TEXTURE_3D_KHR 0x30B2
+#define EGL_GL_TEXTURE_ZOFFSET_KHR 0x30BD
+#endif /* EGL_KHR_gl_texture_3D_image */
+
+#ifndef EGL_KHR_gl_texture_cubemap_image
+#define EGL_KHR_gl_texture_cubemap_image 1
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X_KHR 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X_KHR 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y_KHR 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y_KHR 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z_KHR 0x30B7
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z_KHR 0x30B8
+#endif /* EGL_KHR_gl_texture_cubemap_image */
+
+#ifndef EGL_KHR_image
+#define EGL_KHR_image 1
+typedef void *EGLImageKHR;
+#define EGL_NATIVE_PIXMAP_KHR 0x30B0
+#define EGL_NO_IMAGE_KHR EGL_CAST(EGLImageKHR,0)
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEIMAGEKHRPROC) (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYIMAGEKHRPROC) (EGLDisplay dpy, EGLImageKHR image);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateImageKHR (EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyImageKHR (EGLDisplay dpy, EGLImageKHR image);
+#endif
+#endif /* EGL_KHR_image */
+
+#ifndef EGL_KHR_image_base
+#define EGL_KHR_image_base 1
+#define EGL_IMAGE_PRESERVED_KHR 0x30D2
+#endif /* EGL_KHR_image_base */
+
+#ifndef EGL_KHR_image_pixmap
+#define EGL_KHR_image_pixmap 1
+#endif /* EGL_KHR_image_pixmap */
+
+#ifndef EGL_KHR_lock_surface
+#define EGL_KHR_lock_surface 1
+#define EGL_READ_SURFACE_BIT_KHR 0x0001
+#define EGL_WRITE_SURFACE_BIT_KHR 0x0002
+#define EGL_LOCK_SURFACE_BIT_KHR 0x0080
+#define EGL_OPTIMAL_FORMAT_BIT_KHR 0x0100
+#define EGL_MATCH_FORMAT_KHR 0x3043
+#define EGL_FORMAT_RGB_565_EXACT_KHR 0x30C0
+#define EGL_FORMAT_RGB_565_KHR 0x30C1
+#define EGL_FORMAT_RGBA_8888_EXACT_KHR 0x30C2
+#define EGL_FORMAT_RGBA_8888_KHR 0x30C3
+#define EGL_MAP_PRESERVE_PIXELS_KHR 0x30C4
+#define EGL_LOCK_USAGE_HINT_KHR 0x30C5
+#define EGL_BITMAP_POINTER_KHR 0x30C6
+#define EGL_BITMAP_PITCH_KHR 0x30C7
+#define EGL_BITMAP_ORIGIN_KHR 0x30C8
+#define EGL_BITMAP_PIXEL_RED_OFFSET_KHR 0x30C9
+#define EGL_BITMAP_PIXEL_GREEN_OFFSET_KHR 0x30CA
+#define EGL_BITMAP_PIXEL_BLUE_OFFSET_KHR 0x30CB
+#define EGL_BITMAP_PIXEL_ALPHA_OFFSET_KHR 0x30CC
+#define EGL_BITMAP_PIXEL_LUMINANCE_OFFSET_KHR 0x30CD
+#define EGL_LOWER_LEFT_KHR 0x30CE
+#define EGL_UPPER_LEFT_KHR 0x30CF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNLOCKSURFACEKHRPROC) (EGLDisplay dpy, EGLSurface surface);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglLockSurfaceKHR (EGLDisplay dpy, EGLSurface surface, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnlockSurfaceKHR (EGLDisplay dpy, EGLSurface surface);
+#endif
+#endif /* EGL_KHR_lock_surface */
+
+#ifndef EGL_KHR_lock_surface2
+#define EGL_KHR_lock_surface2 1
+#define EGL_BITMAP_PIXEL_SIZE_KHR 0x3110
+#endif /* EGL_KHR_lock_surface2 */
+
+#ifndef EGL_KHR_lock_surface3
+#define EGL_KHR_lock_surface3 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACE64KHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurface64KHR (EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLAttribKHR *value);
+#endif
+#endif /* EGL_KHR_lock_surface3 */
+
+#ifndef EGL_KHR_mutable_render_buffer
+#define EGL_KHR_mutable_render_buffer 1
+#define EGL_MUTABLE_RENDER_BUFFER_BIT_KHR 0x1000
+#endif /* EGL_KHR_mutable_render_buffer */
+
+#ifndef EGL_KHR_no_config_context
+#define EGL_KHR_no_config_context 1
+#define EGL_NO_CONFIG_KHR EGL_CAST(EGLConfig,0)
+#endif /* EGL_KHR_no_config_context */
+
+#ifndef EGL_KHR_partial_update
+#define EGL_KHR_partial_update 1
+#define EGL_BUFFER_AGE_KHR 0x313D
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETDAMAGEREGIONKHRPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSetDamageRegionKHR (EGLDisplay dpy, EGLSurface surface, EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_KHR_partial_update */
+
+#ifndef EGL_KHR_platform_android
+#define EGL_KHR_platform_android 1
+#define EGL_PLATFORM_ANDROID_KHR 0x3141
+#endif /* EGL_KHR_platform_android */
+
+#ifndef EGL_KHR_platform_gbm
+#define EGL_KHR_platform_gbm 1
+#define EGL_PLATFORM_GBM_KHR 0x31D7
+#endif /* EGL_KHR_platform_gbm */
+
+#ifndef EGL_KHR_platform_wayland
+#define EGL_KHR_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
+#endif /* EGL_KHR_platform_wayland */
+
+#ifndef EGL_KHR_platform_x11
+#define EGL_KHR_platform_x11 1
+#define EGL_PLATFORM_X11_KHR 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6
+#endif /* EGL_KHR_platform_x11 */
+
+#ifndef EGL_KHR_reusable_sync
+#define EGL_KHR_reusable_sync 1
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_STATUS_KHR 0x30F1
+#define EGL_SIGNALED_KHR 0x30F2
+#define EGL_UNSIGNALED_KHR 0x30F3
+#define EGL_TIMEOUT_EXPIRED_KHR 0x30F5
+#define EGL_CONDITION_SATISFIED_KHR 0x30F6
+#define EGL_SYNC_TYPE_KHR 0x30F7
+#define EGL_SYNC_REUSABLE_KHR 0x30FA
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_KHR 0x0001
+#define EGL_FOREVER_KHR 0xFFFFFFFFFFFFFFFFull
+#define EGL_NO_SYNC_KHR EGL_CAST(EGLSyncKHR,0)
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLenum mode);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_reusable_sync */
+
+#ifndef EGL_KHR_stream
+#define EGL_KHR_stream 1
+typedef void *EGLStreamKHR;
+typedef khronos_uint64_t EGLuint64KHR;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_NO_STREAM_KHR EGL_CAST(EGLStreamKHR,0)
+#define EGL_CONSUMER_LATENCY_USEC_KHR 0x3210
+#define EGL_PRODUCER_FRAME_KHR 0x3212
+#define EGL_CONSUMER_FRAME_KHR 0x3213
+#define EGL_STREAM_STATE_KHR 0x3214
+#define EGL_STREAM_STATE_CREATED_KHR 0x3215
+#define EGL_STREAM_STATE_CONNECTING_KHR 0x3216
+#define EGL_STREAM_STATE_EMPTY_KHR 0x3217
+#define EGL_STREAM_STATE_NEW_FRAME_AVAILABLE_KHR 0x3218
+#define EGL_STREAM_STATE_OLD_FRAME_AVAILABLE_KHR 0x3219
+#define EGL_STREAM_STATE_DISCONNECTED_KHR 0x321A
+#define EGL_BAD_STREAM_KHR 0x321B
+#define EGL_BAD_STATE_KHR 0x321C
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMKHRPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMU64KHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamKHR (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroyStreamKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLint *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamu64KHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLuint64KHR *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_stream */
+
+#ifndef EGL_KHR_stream_attrib
+#define EGL_KHR_stream_attrib 1
+#ifdef KHRONOS_SUPPORT_INT64
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMATTRIBKHRPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEATTRIBKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamAttribKHR (EGLDisplay dpy, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLAttrib *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseAttribKHR (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_KHR_stream_attrib */
+
+#ifndef EGL_KHR_stream_consumer_gltexture
+#define EGL_KHR_stream_consumer_gltexture 1
+#ifdef EGL_KHR_stream
+#define EGL_CONSUMER_ACQUIRE_TIMEOUT_USEC_KHR 0x321E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERACQUIREKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERRELEASEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerAcquireKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerReleaseKHR (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_consumer_gltexture */
+
+#ifndef EGL_KHR_stream_cross_process_fd
+#define EGL_KHR_stream_cross_process_fd 1
+typedef int EGLNativeFileDescriptorKHR;
+#ifdef EGL_KHR_stream
+#define EGL_NO_FILE_DESCRIPTOR_KHR EGL_CAST(EGLNativeFileDescriptorKHR,-1)
+typedef EGLNativeFileDescriptorKHR (EGLAPIENTRYP PFNEGLGETSTREAMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+typedef EGLStreamKHR (EGLAPIENTRYP PFNEGLCREATESTREAMFROMFILEDESCRIPTORKHRPROC) (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLNativeFileDescriptorKHR EGLAPIENTRY eglGetStreamFileDescriptorKHR (EGLDisplay dpy, EGLStreamKHR stream);
+EGLAPI EGLStreamKHR EGLAPIENTRY eglCreateStreamFromFileDescriptorKHR (EGLDisplay dpy, EGLNativeFileDescriptorKHR file_descriptor);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_cross_process_fd */
+
+#ifndef EGL_KHR_stream_fifo
+#define EGL_KHR_stream_fifo 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_FIFO_LENGTH_KHR 0x31FC
+#define EGL_STREAM_TIME_NOW_KHR 0x31FD
+#define EGL_STREAM_TIME_CONSUMER_KHR 0x31FE
+#define EGL_STREAM_TIME_PRODUCER_KHR 0x31FF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMTIMEKHRPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamTimeKHR (EGLDisplay dpy, EGLStreamKHR stream, EGLenum attribute, EGLTimeKHR *value);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_fifo */
+
+#ifndef EGL_KHR_stream_producer_aldatalocator
+#define EGL_KHR_stream_producer_aldatalocator 1
+#ifdef EGL_KHR_stream
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_aldatalocator */
+
+#ifndef EGL_KHR_stream_producer_eglsurface
+#define EGL_KHR_stream_producer_eglsurface 1
+#ifdef EGL_KHR_stream
+#define EGL_STREAM_BIT_KHR 0x0800
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERSURFACEKHRPROC) (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreateStreamProducerSurfaceKHR (EGLDisplay dpy, EGLConfig config, EGLStreamKHR stream, const EGLint *attrib_list);
+#endif
+#endif /* EGL_KHR_stream */
+#endif /* EGL_KHR_stream_producer_eglsurface */
+
+#ifndef EGL_KHR_surfaceless_context
+#define EGL_KHR_surfaceless_context 1
+#endif /* EGL_KHR_surfaceless_context */
+
+#ifndef EGL_KHR_swap_buffers_with_damage
+#define EGL_KHR_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEKHRPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageKHR (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_KHR_swap_buffers_with_damage */
+
+#ifndef EGL_KHR_vg_parent_image
+#define EGL_KHR_vg_parent_image 1
+#define EGL_VG_PARENT_IMAGE_KHR 0x30BA
+#endif /* EGL_KHR_vg_parent_image */
+
+#ifndef EGL_KHR_wait_sync
+#define EGL_KHR_wait_sync 1
+typedef EGLint (EGLAPIENTRYP PFNEGLWAITSYNCKHRPROC) (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglWaitSyncKHR (EGLDisplay dpy, EGLSyncKHR sync, EGLint flags);
+#endif
+#endif /* EGL_KHR_wait_sync */
+
+#ifndef EGL_ANDROID_GLES_layers
+#define EGL_ANDROID_GLES_layers 1
+#endif /* EGL_ANDROID_GLES_layers */
+
+#ifndef EGL_ANDROID_blob_cache
+#define EGL_ANDROID_blob_cache 1
+typedef khronos_ssize_t EGLsizeiANDROID;
+typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
+typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
+typedef void (EGLAPIENTRYP PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglSetBlobCacheFuncsANDROID (EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+#endif
+#endif /* EGL_ANDROID_blob_cache */
+
+#ifndef EGL_ANDROID_create_native_client_buffer
+#define EGL_ANDROID_create_native_client_buffer 1
+#define EGL_NATIVE_BUFFER_USAGE_ANDROID 0x3143
+#define EGL_NATIVE_BUFFER_USAGE_PROTECTED_BIT_ANDROID 0x00000001
+#define EGL_NATIVE_BUFFER_USAGE_RENDERBUFFER_BIT_ANDROID 0x00000002
+#define EGL_NATIVE_BUFFER_USAGE_TEXTURE_BIT_ANDROID 0x00000004
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLCREATENATIVECLIENTBUFFERANDROIDPROC) (const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglCreateNativeClientBufferANDROID (const EGLint *attrib_list);
+#endif
+#endif /* EGL_ANDROID_create_native_client_buffer */
+
+#ifndef EGL_ANDROID_framebuffer_target
+#define EGL_ANDROID_framebuffer_target 1
+#define EGL_FRAMEBUFFER_TARGET_ANDROID 0x3147
+#endif /* EGL_ANDROID_framebuffer_target */
+
+#ifndef EGL_ANDROID_front_buffer_auto_refresh
+#define EGL_ANDROID_front_buffer_auto_refresh 1
+#define EGL_FRONT_BUFFER_AUTO_REFRESH_ANDROID 0x314C
+#endif /* EGL_ANDROID_front_buffer_auto_refresh */
+
+#ifndef EGL_ANDROID_get_frame_timestamps
+#define EGL_ANDROID_get_frame_timestamps 1
+typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+#define EGL_TIMESTAMP_PENDING_ANDROID EGL_CAST(EGLnsecsANDROID,-2)
+#define EGL_TIMESTAMP_INVALID_ANDROID EGL_CAST(EGLnsecsANDROID,-1)
+#define EGL_TIMESTAMPS_ANDROID 0x3430
+#define EGL_COMPOSITE_DEADLINE_ANDROID 0x3431
+#define EGL_COMPOSITE_INTERVAL_ANDROID 0x3432
+#define EGL_COMPOSITE_TO_PRESENT_LATENCY_ANDROID 0x3433
+#define EGL_REQUESTED_PRESENT_TIME_ANDROID 0x3434
+#define EGL_RENDERING_COMPLETE_TIME_ANDROID 0x3435
+#define EGL_COMPOSITION_LATCH_TIME_ANDROID 0x3436
+#define EGL_FIRST_COMPOSITION_START_TIME_ANDROID 0x3437
+#define EGL_LAST_COMPOSITION_START_TIME_ANDROID 0x3438
+#define EGL_FIRST_COMPOSITION_GPU_FINISHED_TIME_ANDROID 0x3439
+#define EGL_DISPLAY_PRESENT_TIME_ANDROID 0x343A
+#define EGL_DEQUEUE_READY_TIME_ANDROID 0x343B
+#define EGL_READS_DONE_TIME_ANDROID 0x343C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGSUPPORTEDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETCOMPOSITORTIMINGANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETNEXTFRAMEIDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSUPPORTEDANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETFRAMETIMESTAMPSANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetCompositorTimingSupportedANDROID (EGLDisplay dpy, EGLSurface surface, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetCompositorTimingANDROID (EGLDisplay dpy, EGLSurface surface, EGLint numTimestamps, const EGLint *names, EGLnsecsANDROID *values);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetNextFrameIdANDROID (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR *frameId);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetFrameTimestampSupportedANDROID (EGLDisplay dpy, EGLSurface surface, EGLint timestamp);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetFrameTimestampsANDROID (EGLDisplay dpy, EGLSurface surface, EGLuint64KHR frameId, EGLint numTimestamps, const EGLint *timestamps, EGLnsecsANDROID *values);
+#endif
+#endif /* EGL_ANDROID_get_frame_timestamps */
+
+#ifndef EGL_ANDROID_get_native_client_buffer
+#define EGL_ANDROID_get_native_client_buffer 1
+struct AHardwareBuffer;
+typedef EGLClientBuffer (EGLAPIENTRYP PFNEGLGETNATIVECLIENTBUFFERANDROIDPROC) (const struct AHardwareBuffer *buffer);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLClientBuffer EGLAPIENTRY eglGetNativeClientBufferANDROID (const struct AHardwareBuffer *buffer);
+#endif
+#endif /* EGL_ANDROID_get_native_client_buffer */
+
+#ifndef EGL_ANDROID_image_native_buffer
+#define EGL_ANDROID_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_ANDROID 0x3140
+#endif /* EGL_ANDROID_image_native_buffer */
+
+#ifndef EGL_ANDROID_native_fence_sync
+#define EGL_ANDROID_native_fence_sync 1
+#define EGL_SYNC_NATIVE_FENCE_ANDROID 0x3144
+#define EGL_SYNC_NATIVE_FENCE_FD_ANDROID 0x3145
+#define EGL_SYNC_NATIVE_FENCE_SIGNALED_ANDROID 0x3146
+#define EGL_NO_NATIVE_FENCE_FD_ANDROID -1
+typedef EGLint (EGLAPIENTRYP PFNEGLDUPNATIVEFENCEFDANDROIDPROC) (EGLDisplay dpy, EGLSyncKHR sync);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglDupNativeFenceFDANDROID (EGLDisplay dpy, EGLSyncKHR sync);
+#endif
+#endif /* EGL_ANDROID_native_fence_sync */
+
+#ifndef EGL_ANDROID_presentation_time
+#define EGL_ANDROID_presentation_time 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPRESENTATIONTIMEANDROIDPROC) (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPresentationTimeANDROID (EGLDisplay dpy, EGLSurface surface, EGLnsecsANDROID time);
+#endif
+#endif /* EGL_ANDROID_presentation_time */
+
+#ifndef EGL_ANDROID_recordable
+#define EGL_ANDROID_recordable 1
+#define EGL_RECORDABLE_ANDROID 0x3142
+#endif /* EGL_ANDROID_recordable */
+
+#ifndef EGL_ANGLE_d3d_share_handle_client_buffer
+#define EGL_ANGLE_d3d_share_handle_client_buffer 1
+#define EGL_D3D_TEXTURE_2D_SHARE_HANDLE_ANGLE 0x3200
+#endif /* EGL_ANGLE_d3d_share_handle_client_buffer */
+
+#ifndef EGL_ANGLE_device_d3d
+#define EGL_ANGLE_device_d3d 1
+#define EGL_D3D9_DEVICE_ANGLE 0x33A0
+#define EGL_D3D11_DEVICE_ANGLE 0x33A1
+#endif /* EGL_ANGLE_device_d3d */
+
+#ifndef EGL_ANGLE_query_surface_pointer
+#define EGL_ANGLE_query_surface_pointer 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSURFACEPOINTERANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySurfacePointerANGLE (EGLDisplay dpy, EGLSurface surface, EGLint attribute, void **value);
+#endif
+#endif /* EGL_ANGLE_query_surface_pointer */
+
+#ifndef EGL_ANGLE_surface_d3d_texture_2d_share_handle
+#define EGL_ANGLE_surface_d3d_texture_2d_share_handle 1
+#endif /* EGL_ANGLE_surface_d3d_texture_2d_share_handle */
+
+#ifndef EGL_ANGLE_sync_control_rate
+#define EGL_ANGLE_sync_control_rate 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETMSCRATEANGLEPROC) (EGLDisplay dpy, EGLSurface surface, EGLint *numerator, EGLint *denominator);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetMscRateANGLE (EGLDisplay dpy, EGLSurface surface, EGLint *numerator, EGLint *denominator);
+#endif
+#endif /* EGL_ANGLE_sync_control_rate */
+
+#ifndef EGL_ANGLE_window_fixed_size
+#define EGL_ANGLE_window_fixed_size 1
+#define EGL_FIXED_SIZE_ANGLE 0x3201
+#endif /* EGL_ANGLE_window_fixed_size */
+
+#ifndef EGL_ARM_image_format
+#define EGL_ARM_image_format 1
+#define EGL_COLOR_COMPONENT_TYPE_UNSIGNED_INTEGER_ARM 0x3287
+#define EGL_COLOR_COMPONENT_TYPE_INTEGER_ARM 0x3288
+#endif /* EGL_ARM_image_format */
+
+#ifndef EGL_ARM_implicit_external_sync
+#define EGL_ARM_implicit_external_sync 1
+#define EGL_SYNC_PRIOR_COMMANDS_IMPLICIT_EXTERNAL_ARM 0x328A
+#endif /* EGL_ARM_implicit_external_sync */
+
+#ifndef EGL_ARM_pixmap_multisample_discard
+#define EGL_ARM_pixmap_multisample_discard 1
+#define EGL_DISCARD_SAMPLES_ARM 0x3286
+#endif /* EGL_ARM_pixmap_multisample_discard */
+
+#ifndef EGL_EXT_bind_to_front
+#define EGL_EXT_bind_to_front 1
+#define EGL_FRONT_BUFFER_EXT 0x3464
+#endif /* EGL_EXT_bind_to_front */
+
+#ifndef EGL_EXT_buffer_age
+#define EGL_EXT_buffer_age 1
+#define EGL_BUFFER_AGE_EXT 0x313D
+#endif /* EGL_EXT_buffer_age */
+
+#ifndef EGL_EXT_client_extensions
+#define EGL_EXT_client_extensions 1
+#endif /* EGL_EXT_client_extensions */
+
+#ifndef EGL_EXT_client_sync
+#define EGL_EXT_client_sync 1
+#define EGL_SYNC_CLIENT_EXT 0x3364
+#define EGL_SYNC_CLIENT_SIGNAL_EXT 0x3365
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCLIENTSIGNALSYNCEXTPROC) (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglClientSignalSyncEXT (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_EXT_client_sync */
+
+#ifndef EGL_EXT_compositor
+#define EGL_EXT_compositor 1
+#define EGL_PRIMARY_COMPOSITOR_CONTEXT_EXT 0x3460
+#define EGL_EXTERNAL_REF_ID_EXT 0x3461
+#define EGL_COMPOSITOR_DROP_NEWEST_FRAME_EXT 0x3462
+#define EGL_COMPOSITOR_KEEP_NEWEST_FRAME_EXT 0x3463
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETCONTEXTLISTEXTPROC) (const EGLint *external_ref_ids, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETCONTEXTATTRIBUTESEXTPROC) (EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETWINDOWLISTEXTPROC) (EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETWINDOWATTRIBUTESEXTPROC) (EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORBINDTEXWINDOWEXTPROC) (EGLint external_win_id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSETSIZEEXTPROC) (EGLint external_win_id, EGLint width, EGLint height);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLCOMPOSITORSWAPPOLICYEXTPROC) (EGLint external_win_id, EGLint policy);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetContextListEXT (const EGLint *external_ref_ids, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetContextAttributesEXT (EGLint external_ref_id, const EGLint *context_attributes, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetWindowListEXT (EGLint external_ref_id, const EGLint *external_win_ids, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetWindowAttributesEXT (EGLint external_win_id, const EGLint *window_attributes, EGLint num_entries);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorBindTexWindowEXT (EGLint external_win_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSetSizeEXT (EGLint external_win_id, EGLint width, EGLint height);
+EGLAPI EGLBoolean EGLAPIENTRY eglCompositorSwapPolicyEXT (EGLint external_win_id, EGLint policy);
+#endif
+#endif /* EGL_EXT_compositor */
+
+#ifndef EGL_EXT_config_select_group
+#define EGL_EXT_config_select_group 1
+#define EGL_CONFIG_SELECT_GROUP_EXT 0x34C0
+#endif /* EGL_EXT_config_select_group */
+
+#ifndef EGL_EXT_create_context_robustness
+#define EGL_EXT_create_context_robustness 1
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS_EXT 0x30BF
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY_EXT 0x3138
+#define EGL_NO_RESET_NOTIFICATION_EXT 0x31BE
+#define EGL_LOSE_CONTEXT_ON_RESET_EXT 0x31BF
+#endif /* EGL_EXT_create_context_robustness */
+
+#ifndef EGL_EXT_device_base
+#define EGL_EXT_device_base 1
+typedef void *EGLDeviceEXT;
+#define EGL_NO_DEVICE_EXT EGL_CAST(EGLDeviceEXT,0)
+#define EGL_BAD_DEVICE_EXT 0x322B
+#define EGL_DEVICE_EXT 0x322C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICEATTRIBEXTPROC) (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYDEVICESTRINGEXTPROC) (EGLDeviceEXT device, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICESEXTPROC) (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBEXTPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDeviceAttribEXT (EGLDeviceEXT device, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryDeviceStringEXT (EGLDeviceEXT device, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDevicesEXT (EGLint max_devices, EGLDeviceEXT *devices, EGLint *num_devices);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribEXT (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#endif
+#endif /* EGL_EXT_device_base */
+
+#ifndef EGL_EXT_device_drm
+#define EGL_EXT_device_drm 1
+#define EGL_DRM_DEVICE_FILE_EXT 0x3233
+#define EGL_DRM_MASTER_FD_EXT 0x333C
+#endif /* EGL_EXT_device_drm */
+
+#ifndef EGL_EXT_device_drm_render_node
+#define EGL_EXT_device_drm_render_node 1
+#define EGL_DRM_RENDER_NODE_FILE_EXT 0x3377
+#endif /* EGL_EXT_device_drm_render_node */
+
+#ifndef EGL_EXT_device_enumeration
+#define EGL_EXT_device_enumeration 1
+#endif /* EGL_EXT_device_enumeration */
+
+#ifndef EGL_EXT_device_openwf
+#define EGL_EXT_device_openwf 1
+#define EGL_OPENWF_DEVICE_ID_EXT 0x3237
+#define EGL_OPENWF_DEVICE_EXT 0x333D
+#endif /* EGL_EXT_device_openwf */
+
+#ifndef EGL_EXT_device_persistent_id
+#define EGL_EXT_device_persistent_id 1
+#define EGL_DEVICE_UUID_EXT 0x335C
+#define EGL_DRIVER_UUID_EXT 0x335D
+#define EGL_DRIVER_NAME_EXT 0x335E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDEVICEBINARYEXTPROC) (EGLDeviceEXT device, EGLint name, EGLint max_size, void *value, EGLint *size);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDeviceBinaryEXT (EGLDeviceEXT device, EGLint name, EGLint max_size, void *value, EGLint *size);
+#endif
+#endif /* EGL_EXT_device_persistent_id */
+
+#ifndef EGL_EXT_device_query
+#define EGL_EXT_device_query 1
+#endif /* EGL_EXT_device_query */
+
+#ifndef EGL_EXT_device_query_name
+#define EGL_EXT_device_query_name 1
+#define EGL_RENDERER_EXT 0x335F
+#endif /* EGL_EXT_device_query_name */
+
+#ifndef EGL_EXT_explicit_device
+#define EGL_EXT_explicit_device 1
+#endif /* EGL_EXT_explicit_device */
+
+#ifndef EGL_EXT_gl_colorspace_bt2020_linear
+#define EGL_EXT_gl_colorspace_bt2020_linear 1
+#define EGL_GL_COLORSPACE_BT2020_LINEAR_EXT 0x333F
+#endif /* EGL_EXT_gl_colorspace_bt2020_linear */
+
+#ifndef EGL_EXT_gl_colorspace_bt2020_pq
+#define EGL_EXT_gl_colorspace_bt2020_pq 1
+#define EGL_GL_COLORSPACE_BT2020_PQ_EXT 0x3340
+#endif /* EGL_EXT_gl_colorspace_bt2020_pq */
+
+#ifndef EGL_EXT_gl_colorspace_display_p3
+#define EGL_EXT_gl_colorspace_display_p3 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_EXT 0x3363
+#endif /* EGL_EXT_gl_colorspace_display_p3 */
+
+#ifndef EGL_EXT_gl_colorspace_display_p3_linear
+#define EGL_EXT_gl_colorspace_display_p3_linear 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_LINEAR_EXT 0x3362
+#endif /* EGL_EXT_gl_colorspace_display_p3_linear */
+
+#ifndef EGL_EXT_gl_colorspace_display_p3_passthrough
+#define EGL_EXT_gl_colorspace_display_p3_passthrough 1
+#define EGL_GL_COLORSPACE_DISPLAY_P3_PASSTHROUGH_EXT 0x3490
+#endif /* EGL_EXT_gl_colorspace_display_p3_passthrough */
+
+#ifndef EGL_EXT_gl_colorspace_scrgb
+#define EGL_EXT_gl_colorspace_scrgb 1
+#define EGL_GL_COLORSPACE_SCRGB_EXT 0x3351
+#endif /* EGL_EXT_gl_colorspace_scrgb */
+
+#ifndef EGL_EXT_gl_colorspace_scrgb_linear
+#define EGL_EXT_gl_colorspace_scrgb_linear 1
+#define EGL_GL_COLORSPACE_SCRGB_LINEAR_EXT 0x3350
+#endif /* EGL_EXT_gl_colorspace_scrgb_linear */
+
+#ifndef EGL_EXT_image_dma_buf_import
+#define EGL_EXT_image_dma_buf_import 1
+#define EGL_LINUX_DMA_BUF_EXT 0x3270
+#define EGL_LINUX_DRM_FOURCC_EXT 0x3271
+#define EGL_DMA_BUF_PLANE0_FD_EXT 0x3272
+#define EGL_DMA_BUF_PLANE0_OFFSET_EXT 0x3273
+#define EGL_DMA_BUF_PLANE0_PITCH_EXT 0x3274
+#define EGL_DMA_BUF_PLANE1_FD_EXT 0x3275
+#define EGL_DMA_BUF_PLANE1_OFFSET_EXT 0x3276
+#define EGL_DMA_BUF_PLANE1_PITCH_EXT 0x3277
+#define EGL_DMA_BUF_PLANE2_FD_EXT 0x3278
+#define EGL_DMA_BUF_PLANE2_OFFSET_EXT 0x3279
+#define EGL_DMA_BUF_PLANE2_PITCH_EXT 0x327A
+#define EGL_YUV_COLOR_SPACE_HINT_EXT 0x327B
+#define EGL_SAMPLE_RANGE_HINT_EXT 0x327C
+#define EGL_YUV_CHROMA_HORIZONTAL_SITING_HINT_EXT 0x327D
+#define EGL_YUV_CHROMA_VERTICAL_SITING_HINT_EXT 0x327E
+#define EGL_ITU_REC601_EXT 0x327F
+#define EGL_ITU_REC709_EXT 0x3280
+#define EGL_ITU_REC2020_EXT 0x3281
+#define EGL_YUV_FULL_RANGE_EXT 0x3282
+#define EGL_YUV_NARROW_RANGE_EXT 0x3283
+#define EGL_YUV_CHROMA_SITING_0_EXT 0x3284
+#define EGL_YUV_CHROMA_SITING_0_5_EXT 0x3285
+#endif /* EGL_EXT_image_dma_buf_import */
+
+#ifndef EGL_EXT_image_dma_buf_import_modifiers
+#define EGL_EXT_image_dma_buf_import_modifiers 1
+#define EGL_DMA_BUF_PLANE3_FD_EXT 0x3440
+#define EGL_DMA_BUF_PLANE3_OFFSET_EXT 0x3441
+#define EGL_DMA_BUF_PLANE3_PITCH_EXT 0x3442
+#define EGL_DMA_BUF_PLANE0_MODIFIER_LO_EXT 0x3443
+#define EGL_DMA_BUF_PLANE0_MODIFIER_HI_EXT 0x3444
+#define EGL_DMA_BUF_PLANE1_MODIFIER_LO_EXT 0x3445
+#define EGL_DMA_BUF_PLANE1_MODIFIER_HI_EXT 0x3446
+#define EGL_DMA_BUF_PLANE2_MODIFIER_LO_EXT 0x3447
+#define EGL_DMA_BUF_PLANE2_MODIFIER_HI_EXT 0x3448
+#define EGL_DMA_BUF_PLANE3_MODIFIER_LO_EXT 0x3449
+#define EGL_DMA_BUF_PLANE3_MODIFIER_HI_EXT 0x344A
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFFORMATSEXTPROC) (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDMABUFMODIFIERSEXTPROC) (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufFormatsEXT (EGLDisplay dpy, EGLint max_formats, EGLint *formats, EGLint *num_formats);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDmaBufModifiersEXT (EGLDisplay dpy, EGLint format, EGLint max_modifiers, EGLuint64KHR *modifiers, EGLBoolean *external_only, EGLint *num_modifiers);
+#endif
+#endif /* EGL_EXT_image_dma_buf_import_modifiers */
+
+#ifndef EGL_EXT_image_gl_colorspace
+#define EGL_EXT_image_gl_colorspace 1
+#define EGL_GL_COLORSPACE_DEFAULT_EXT 0x314D
+#endif /* EGL_EXT_image_gl_colorspace */
+
+#ifndef EGL_EXT_image_implicit_sync_control
+#define EGL_EXT_image_implicit_sync_control 1
+#define EGL_IMPORT_SYNC_TYPE_EXT 0x3470
+#define EGL_IMPORT_IMPLICIT_SYNC_EXT 0x3471
+#define EGL_IMPORT_EXPLICIT_SYNC_EXT 0x3472
+#endif /* EGL_EXT_image_implicit_sync_control */
+
+#ifndef EGL_EXT_multiview_window
+#define EGL_EXT_multiview_window 1
+#define EGL_MULTIVIEW_VIEW_COUNT_EXT 0x3134
+#endif /* EGL_EXT_multiview_window */
+
+#ifndef EGL_EXT_output_base
+#define EGL_EXT_output_base 1
+typedef void *EGLOutputLayerEXT;
+typedef void *EGLOutputPortEXT;
+#define EGL_NO_OUTPUT_LAYER_EXT EGL_CAST(EGLOutputLayerEXT,0)
+#define EGL_NO_OUTPUT_PORT_EXT EGL_CAST(EGLOutputPortEXT,0)
+#define EGL_BAD_OUTPUT_LAYER_EXT 0x322D
+#define EGL_BAD_OUTPUT_PORT_EXT 0x322E
+#define EGL_SWAP_INTERVAL_EXT 0x322F
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTLAYERSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETOUTPUTPORTSEXTPROC) (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTLAYERSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTATTRIBEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYOUTPUTPORTSTRINGEXTPROC) (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetOutputLayersEXT (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputLayerEXT *layers, EGLint max_layers, EGLint *num_layers);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetOutputPortsEXT (EGLDisplay dpy, const EGLAttrib *attrib_list, EGLOutputPortEXT *ports, EGLint max_ports, EGLint *num_ports);
+EGLAPI EGLBoolean EGLAPIENTRY eglOutputLayerAttribEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryOutputLayerAttribEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryOutputLayerStringEXT (EGLDisplay dpy, EGLOutputLayerEXT layer, EGLint name);
+EGLAPI EGLBoolean EGLAPIENTRY eglOutputPortAttribEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib value);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryOutputPortAttribEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint attribute, EGLAttrib *value);
+EGLAPI const char *EGLAPIENTRY eglQueryOutputPortStringEXT (EGLDisplay dpy, EGLOutputPortEXT port, EGLint name);
+#endif
+#endif /* EGL_EXT_output_base */
+
+#ifndef EGL_EXT_output_drm
+#define EGL_EXT_output_drm 1
+#define EGL_DRM_CRTC_EXT 0x3234
+#define EGL_DRM_PLANE_EXT 0x3235
+#define EGL_DRM_CONNECTOR_EXT 0x3236
+#endif /* EGL_EXT_output_drm */
+
+#ifndef EGL_EXT_output_openwf
+#define EGL_EXT_output_openwf 1
+#define EGL_OPENWF_PIPELINE_ID_EXT 0x3238
+#define EGL_OPENWF_PORT_ID_EXT 0x3239
+#endif /* EGL_EXT_output_openwf */
+
+#ifndef EGL_EXT_pixel_format_float
+#define EGL_EXT_pixel_format_float 1
+#define EGL_COLOR_COMPONENT_TYPE_EXT 0x3339
+#define EGL_COLOR_COMPONENT_TYPE_FIXED_EXT 0x333A
+#define EGL_COLOR_COMPONENT_TYPE_FLOAT_EXT 0x333B
+#endif /* EGL_EXT_pixel_format_float */
+
+#ifndef EGL_EXT_platform_base
+#define EGL_EXT_platform_base 1
+typedef EGLDisplay (EGLAPIENTRYP PFNEGLGETPLATFORMDISPLAYEXTPROC) (EGLenum platform, void *native_display, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMWINDOWSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPLATFORMPIXMAPSURFACEEXTPROC) (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDisplay EGLAPIENTRY eglGetPlatformDisplayEXT (EGLenum platform, void *native_display, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformWindowSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_window, const EGLint *attrib_list);
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePlatformPixmapSurfaceEXT (EGLDisplay dpy, EGLConfig config, void *native_pixmap, const EGLint *attrib_list);
+#endif
+#endif /* EGL_EXT_platform_base */
+
+#ifndef EGL_EXT_platform_device
+#define EGL_EXT_platform_device 1
+#define EGL_PLATFORM_DEVICE_EXT 0x313F
+#endif /* EGL_EXT_platform_device */
+
+#ifndef EGL_EXT_platform_wayland
+#define EGL_EXT_platform_wayland 1
+#define EGL_PLATFORM_WAYLAND_EXT 0x31D8
+#endif /* EGL_EXT_platform_wayland */
+
+#ifndef EGL_EXT_platform_x11
+#define EGL_EXT_platform_x11 1
+#define EGL_PLATFORM_X11_EXT 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_EXT 0x31D6
+#endif /* EGL_EXT_platform_x11 */
+
+#ifndef EGL_EXT_platform_xcb
+#define EGL_EXT_platform_xcb 1
+#define EGL_PLATFORM_XCB_EXT 0x31DC
+#define EGL_PLATFORM_XCB_SCREEN_EXT 0x31DE
+#endif /* EGL_EXT_platform_xcb */
+
+#ifndef EGL_EXT_present_opaque
+#define EGL_EXT_present_opaque 1
+#define EGL_PRESENT_OPAQUE_EXT 0x31DF
+#endif /* EGL_EXT_present_opaque */
+
+#ifndef EGL_EXT_protected_content
+#define EGL_EXT_protected_content 1
+#define EGL_PROTECTED_CONTENT_EXT 0x32C0
+#endif /* EGL_EXT_protected_content */
+
+#ifndef EGL_EXT_protected_surface
+#define EGL_EXT_protected_surface 1
+#endif /* EGL_EXT_protected_surface */
+
+#ifndef EGL_EXT_stream_consumer_egloutput
+#define EGL_EXT_stream_consumer_egloutput 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMEROUTPUTEXTPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerOutputEXT (EGLDisplay dpy, EGLStreamKHR stream, EGLOutputLayerEXT layer);
+#endif
+#endif /* EGL_EXT_stream_consumer_egloutput */
+
+#ifndef EGL_EXT_surface_CTA861_3_metadata
+#define EGL_EXT_surface_CTA861_3_metadata 1
+#define EGL_CTA861_3_MAX_CONTENT_LIGHT_LEVEL_EXT 0x3360
+#define EGL_CTA861_3_MAX_FRAME_AVERAGE_LEVEL_EXT 0x3361
+#endif /* EGL_EXT_surface_CTA861_3_metadata */
+
+#ifndef EGL_EXT_surface_SMPTE2086_metadata
+#define EGL_EXT_surface_SMPTE2086_metadata 1
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_RX_EXT 0x3341
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_RY_EXT 0x3342
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_GX_EXT 0x3343
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_GY_EXT 0x3344
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_BX_EXT 0x3345
+#define EGL_SMPTE2086_DISPLAY_PRIMARY_BY_EXT 0x3346
+#define EGL_SMPTE2086_WHITE_POINT_X_EXT 0x3347
+#define EGL_SMPTE2086_WHITE_POINT_Y_EXT 0x3348
+#define EGL_SMPTE2086_MAX_LUMINANCE_EXT 0x3349
+#define EGL_SMPTE2086_MIN_LUMINANCE_EXT 0x334A
+#define EGL_METADATA_SCALING_EXT 50000
+#endif /* EGL_EXT_surface_SMPTE2086_metadata */
+
+#ifndef EGL_EXT_surface_compression
+#define EGL_EXT_surface_compression 1
+#define EGL_SURFACE_COMPRESSION_EXT 0x34B0
+#define EGL_SURFACE_COMPRESSION_PLANE1_EXT 0x328E
+#define EGL_SURFACE_COMPRESSION_PLANE2_EXT 0x328F
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_NONE_EXT 0x34B1
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_DEFAULT_EXT 0x34B2
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_1BPC_EXT 0x34B4
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_2BPC_EXT 0x34B5
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_3BPC_EXT 0x34B6
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_4BPC_EXT 0x34B7
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_5BPC_EXT 0x34B8
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_6BPC_EXT 0x34B9
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_7BPC_EXT 0x34BA
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_8BPC_EXT 0x34BB
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_9BPC_EXT 0x34BC
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_10BPC_EXT 0x34BD
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_11BPC_EXT 0x34BE
+#define EGL_SURFACE_COMPRESSION_FIXED_RATE_12BPC_EXT 0x34BF
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSUPPORTEDCOMPRESSIONRATESEXTPROC) (EGLDisplay dpy, EGLConfig config, const EGLAttrib *attrib_list, EGLint *rates, EGLint rate_size, EGLint *num_rates);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQuerySupportedCompressionRatesEXT (EGLDisplay dpy, EGLConfig config, const EGLAttrib *attrib_list, EGLint *rates, EGLint rate_size, EGLint *num_rates);
+#endif
+#endif /* EGL_EXT_surface_compression */
+
+#ifndef EGL_EXT_swap_buffers_with_damage
+#define EGL_EXT_swap_buffers_with_damage 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHDAMAGEEXTPROC) (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithDamageEXT (EGLDisplay dpy, EGLSurface surface, const EGLint *rects, EGLint n_rects);
+#endif
+#endif /* EGL_EXT_swap_buffers_with_damage */
+
+#ifndef EGL_EXT_sync_reuse
+#define EGL_EXT_sync_reuse 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNSIGNALSYNCEXTPROC) (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglUnsignalSyncEXT (EGLDisplay dpy, EGLSync sync, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_EXT_sync_reuse */
+
+#ifndef EGL_EXT_yuv_surface
+#define EGL_EXT_yuv_surface 1
+#define EGL_YUV_ORDER_EXT 0x3301
+#define EGL_YUV_NUMBER_OF_PLANES_EXT 0x3311
+#define EGL_YUV_SUBSAMPLE_EXT 0x3312
+#define EGL_YUV_DEPTH_RANGE_EXT 0x3317
+#define EGL_YUV_CSC_STANDARD_EXT 0x330A
+#define EGL_YUV_PLANE_BPP_EXT 0x331A
+#define EGL_YUV_BUFFER_EXT 0x3300
+#define EGL_YUV_ORDER_YUV_EXT 0x3302
+#define EGL_YUV_ORDER_YVU_EXT 0x3303
+#define EGL_YUV_ORDER_YUYV_EXT 0x3304
+#define EGL_YUV_ORDER_UYVY_EXT 0x3305
+#define EGL_YUV_ORDER_YVYU_EXT 0x3306
+#define EGL_YUV_ORDER_VYUY_EXT 0x3307
+#define EGL_YUV_ORDER_AYUV_EXT 0x3308
+#define EGL_YUV_SUBSAMPLE_4_2_0_EXT 0x3313
+#define EGL_YUV_SUBSAMPLE_4_2_2_EXT 0x3314
+#define EGL_YUV_SUBSAMPLE_4_4_4_EXT 0x3315
+#define EGL_YUV_DEPTH_RANGE_LIMITED_EXT 0x3318
+#define EGL_YUV_DEPTH_RANGE_FULL_EXT 0x3319
+#define EGL_YUV_CSC_STANDARD_601_EXT 0x330B
+#define EGL_YUV_CSC_STANDARD_709_EXT 0x330C
+#define EGL_YUV_CSC_STANDARD_2020_EXT 0x330D
+#define EGL_YUV_PLANE_BPP_0_EXT 0x331B
+#define EGL_YUV_PLANE_BPP_8_EXT 0x331C
+#define EGL_YUV_PLANE_BPP_10_EXT 0x331D
+#endif /* EGL_EXT_yuv_surface */
+
+#ifndef EGL_HI_clientpixmap
+#define EGL_HI_clientpixmap 1
+struct EGLClientPixmapHI {
+ void *pData;
+ EGLint iWidth;
+ EGLint iHeight;
+ EGLint iStride;
+};
+#define EGL_CLIENT_PIXMAP_POINTER_HI 0x8F74
+typedef EGLSurface (EGLAPIENTRYP PFNEGLCREATEPIXMAPSURFACEHIPROC) (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSurface EGLAPIENTRY eglCreatePixmapSurfaceHI (EGLDisplay dpy, EGLConfig config, struct EGLClientPixmapHI *pixmap);
+#endif
+#endif /* EGL_HI_clientpixmap */
+
+#ifndef EGL_HI_colorformats
+#define EGL_HI_colorformats 1
+#define EGL_COLOR_FORMAT_HI 0x8F70
+#define EGL_COLOR_RGB_HI 0x8F71
+#define EGL_COLOR_RGBA_HI 0x8F72
+#define EGL_COLOR_ARGB_HI 0x8F73
+#endif /* EGL_HI_colorformats */
+
+#ifndef EGL_IMG_context_priority
+#define EGL_IMG_context_priority 1
+#define EGL_CONTEXT_PRIORITY_LEVEL_IMG 0x3100
+#define EGL_CONTEXT_PRIORITY_HIGH_IMG 0x3101
+#define EGL_CONTEXT_PRIORITY_MEDIUM_IMG 0x3102
+#define EGL_CONTEXT_PRIORITY_LOW_IMG 0x3103
+#endif /* EGL_IMG_context_priority */
+
+#ifndef EGL_IMG_image_plane_attribs
+#define EGL_IMG_image_plane_attribs 1
+#define EGL_NATIVE_BUFFER_MULTIPLANE_SEPARATE_IMG 0x3105
+#define EGL_NATIVE_BUFFER_PLANE_OFFSET_IMG 0x3106
+#endif /* EGL_IMG_image_plane_attribs */
+
+#ifndef EGL_MESA_drm_image
+#define EGL_MESA_drm_image 1
+#define EGL_DRM_BUFFER_FORMAT_MESA 0x31D0
+#define EGL_DRM_BUFFER_USE_MESA 0x31D1
+#define EGL_DRM_BUFFER_FORMAT_ARGB32_MESA 0x31D2
+#define EGL_DRM_BUFFER_MESA 0x31D3
+#define EGL_DRM_BUFFER_STRIDE_MESA 0x31D4
+#define EGL_DRM_BUFFER_USE_SCANOUT_MESA 0x00000001
+#define EGL_DRM_BUFFER_USE_SHARE_MESA 0x00000002
+#define EGL_DRM_BUFFER_USE_CURSOR_MESA 0x00000004
+typedef EGLImageKHR (EGLAPIENTRYP PFNEGLCREATEDRMIMAGEMESAPROC) (EGLDisplay dpy, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDRMIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLImageKHR EGLAPIENTRY eglCreateDRMImageMESA (EGLDisplay dpy, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDRMImageMESA (EGLDisplay dpy, EGLImageKHR image, EGLint *name, EGLint *handle, EGLint *stride);
+#endif
+#endif /* EGL_MESA_drm_image */
+
+#ifndef EGL_MESA_image_dma_buf_export
+#define EGL_MESA_image_dma_buf_export 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEQUERYMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTDMABUFIMAGEMESAPROC) (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageQueryMESA (EGLDisplay dpy, EGLImageKHR image, int *fourcc, int *num_planes, EGLuint64KHR *modifiers);
+EGLAPI EGLBoolean EGLAPIENTRY eglExportDMABUFImageMESA (EGLDisplay dpy, EGLImageKHR image, int *fds, EGLint *strides, EGLint *offsets);
+#endif
+#endif /* EGL_MESA_image_dma_buf_export */
+
+#ifndef EGL_MESA_platform_gbm
+#define EGL_MESA_platform_gbm 1
+#define EGL_PLATFORM_GBM_MESA 0x31D7
+#endif /* EGL_MESA_platform_gbm */
+
+#ifndef EGL_MESA_platform_surfaceless
+#define EGL_MESA_platform_surfaceless 1
+#define EGL_PLATFORM_SURFACELESS_MESA 0x31DD
+#endif /* EGL_MESA_platform_surfaceless */
+
+#ifndef EGL_MESA_query_driver
+#define EGL_MESA_query_driver 1
+typedef char *(EGLAPIENTRYP PFNEGLGETDISPLAYDRIVERCONFIGPROC) (EGLDisplay dpy);
+typedef const char *(EGLAPIENTRYP PFNEGLGETDISPLAYDRIVERNAMEPROC) (EGLDisplay dpy);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI char *EGLAPIENTRY eglGetDisplayDriverConfig (EGLDisplay dpy);
+EGLAPI const char *EGLAPIENTRY eglGetDisplayDriverName (EGLDisplay dpy);
+#endif
+#endif /* EGL_MESA_query_driver */
+
+#ifndef EGL_NOK_swap_region
+#define EGL_NOK_swap_region 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGIONNOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegionNOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region */
+
+#ifndef EGL_NOK_swap_region2
+#define EGL_NOK_swap_region2 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSREGION2NOKPROC) (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersRegion2NOK (EGLDisplay dpy, EGLSurface surface, EGLint numRects, const EGLint *rects);
+#endif
+#endif /* EGL_NOK_swap_region2 */
+
+#ifndef EGL_NOK_texture_from_pixmap
+#define EGL_NOK_texture_from_pixmap 1
+#define EGL_Y_INVERTED_NOK 0x307F
+#endif /* EGL_NOK_texture_from_pixmap */
+
+#ifndef EGL_NV_3dvision_surface
+#define EGL_NV_3dvision_surface 1
+#define EGL_AUTO_STEREO_NV 0x3136
+#endif /* EGL_NV_3dvision_surface */
+
+#ifndef EGL_NV_context_priority_realtime
+#define EGL_NV_context_priority_realtime 1
+#define EGL_CONTEXT_PRIORITY_REALTIME_NV 0x3357
+#endif /* EGL_NV_context_priority_realtime */
+
+#ifndef EGL_NV_coverage_sample
+#define EGL_NV_coverage_sample 1
+#define EGL_COVERAGE_BUFFERS_NV 0x30E0
+#define EGL_COVERAGE_SAMPLES_NV 0x30E1
+#endif /* EGL_NV_coverage_sample */
+
+#ifndef EGL_NV_coverage_sample_resolve
+#define EGL_NV_coverage_sample_resolve 1
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NV 0x3131
+#define EGL_COVERAGE_SAMPLE_RESOLVE_DEFAULT_NV 0x3132
+#define EGL_COVERAGE_SAMPLE_RESOLVE_NONE_NV 0x3133
+#endif /* EGL_NV_coverage_sample_resolve */
+
+#ifndef EGL_NV_cuda_event
+#define EGL_NV_cuda_event 1
+#define EGL_CUDA_EVENT_HANDLE_NV 0x323B
+#define EGL_SYNC_CUDA_EVENT_NV 0x323C
+#define EGL_SYNC_CUDA_EVENT_COMPLETE_NV 0x323D
+#endif /* EGL_NV_cuda_event */
+
+#ifndef EGL_NV_depth_nonlinear
+#define EGL_NV_depth_nonlinear 1
+#define EGL_DEPTH_ENCODING_NV 0x30E2
+#define EGL_DEPTH_ENCODING_NONE_NV 0
+#define EGL_DEPTH_ENCODING_NONLINEAR_NV 0x30E3
+#endif /* EGL_NV_depth_nonlinear */
+
+#ifndef EGL_NV_device_cuda
+#define EGL_NV_device_cuda 1
+#define EGL_CUDA_DEVICE_NV 0x323A
+#endif /* EGL_NV_device_cuda */
+
+#ifndef EGL_NV_native_query
+#define EGL_NV_native_query 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEDISPLAYNVPROC) (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEWINDOWNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYNATIVEPIXMAPNVPROC) (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeDisplayNV (EGLDisplay dpy, EGLNativeDisplayType *display_id);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativeWindowNV (EGLDisplay dpy, EGLSurface surf, EGLNativeWindowType *window);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryNativePixmapNV (EGLDisplay dpy, EGLSurface surf, EGLNativePixmapType *pixmap);
+#endif
+#endif /* EGL_NV_native_query */
+
+#ifndef EGL_NV_post_convert_rounding
+#define EGL_NV_post_convert_rounding 1
+#endif /* EGL_NV_post_convert_rounding */
+
+#ifndef EGL_NV_post_sub_buffer
+#define EGL_NV_post_sub_buffer 1
+#define EGL_POST_SUB_BUFFER_SUPPORTED_NV 0x30BE
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPOSTSUBBUFFERNVPROC) (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPostSubBufferNV (EGLDisplay dpy, EGLSurface surface, EGLint x, EGLint y, EGLint width, EGLint height);
+#endif
+#endif /* EGL_NV_post_sub_buffer */
+
+#ifndef EGL_NV_quadruple_buffer
+#define EGL_NV_quadruple_buffer 1
+#define EGL_QUADRUPLE_BUFFER_NV 0x3231
+#endif /* EGL_NV_quadruple_buffer */
+
+#ifndef EGL_NV_robustness_video_memory_purge
+#define EGL_NV_robustness_video_memory_purge 1
+#define EGL_GENERATE_RESET_ON_VIDEO_MEMORY_PURGE_NV 0x334C
+#endif /* EGL_NV_robustness_video_memory_purge */
+
+#ifndef EGL_NV_stream_consumer_eglimage
+#define EGL_NV_stream_consumer_eglimage 1
+#define EGL_STREAM_CONSUMER_IMAGE_NV 0x3373
+#define EGL_STREAM_IMAGE_ADD_NV 0x3374
+#define EGL_STREAM_IMAGE_REMOVE_NV 0x3375
+#define EGL_STREAM_IMAGE_AVAILABLE_NV 0x3376
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMIMAGECONSUMERCONNECTNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLint num_modifiers, const EGLuint64KHR *modifiers, const EGLAttrib *attrib_list);
+typedef EGLint (EGLAPIENTRYP PFNEGLQUERYSTREAMCONSUMEREVENTNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLTime timeout, EGLenum *event, EGLAttrib *aux);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMACQUIREIMAGENVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLImage *pImage, EGLSync sync);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMRELEASEIMAGENVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLImage image, EGLSync sync);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamImageConsumerConnectNV (EGLDisplay dpy, EGLStreamKHR stream, EGLint num_modifiers, const EGLuint64KHR *modifiers, const EGLAttrib *attrib_list);
+EGLAPI EGLint EGLAPIENTRY eglQueryStreamConsumerEventNV (EGLDisplay dpy, EGLStreamKHR stream, EGLTime timeout, EGLenum *event, EGLAttrib *aux);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamAcquireImageNV (EGLDisplay dpy, EGLStreamKHR stream, EGLImage *pImage, EGLSync sync);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamReleaseImageNV (EGLDisplay dpy, EGLStreamKHR stream, EGLImage image, EGLSync sync);
+#endif
+#endif /* EGL_NV_stream_consumer_eglimage */
+
+#ifndef EGL_NV_stream_consumer_gltexture_yuv
+#define EGL_NV_stream_consumer_gltexture_yuv 1
+#define EGL_YUV_PLANE0_TEXTURE_UNIT_NV 0x332C
+#define EGL_YUV_PLANE1_TEXTURE_UNIT_NV 0x332D
+#define EGL_YUV_PLANE2_TEXTURE_UNIT_NV 0x332E
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMCONSUMERGLTEXTUREEXTERNALATTRIBSNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamConsumerGLTextureExternalAttribsNV (EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_NV_stream_consumer_gltexture_yuv */
+
+#ifndef EGL_NV_stream_cross_display
+#define EGL_NV_stream_cross_display 1
+#define EGL_STREAM_CROSS_DISPLAY_NV 0x334E
+#endif /* EGL_NV_stream_cross_display */
+
+#ifndef EGL_NV_stream_cross_object
+#define EGL_NV_stream_cross_object 1
+#define EGL_STREAM_CROSS_OBJECT_NV 0x334D
+#endif /* EGL_NV_stream_cross_object */
+
+#ifndef EGL_NV_stream_cross_partition
+#define EGL_NV_stream_cross_partition 1
+#define EGL_STREAM_CROSS_PARTITION_NV 0x323F
+#endif /* EGL_NV_stream_cross_partition */
+
+#ifndef EGL_NV_stream_cross_process
+#define EGL_NV_stream_cross_process 1
+#define EGL_STREAM_CROSS_PROCESS_NV 0x3245
+#endif /* EGL_NV_stream_cross_process */
+
+#ifndef EGL_NV_stream_cross_system
+#define EGL_NV_stream_cross_system 1
+#define EGL_STREAM_CROSS_SYSTEM_NV 0x334F
+#endif /* EGL_NV_stream_cross_system */
+
+#ifndef EGL_NV_stream_dma
+#define EGL_NV_stream_dma 1
+#define EGL_STREAM_DMA_NV 0x3371
+#define EGL_STREAM_DMA_SERVER_NV 0x3372
+#endif /* EGL_NV_stream_dma */
+
+#ifndef EGL_NV_stream_fifo_next
+#define EGL_NV_stream_fifo_next 1
+#define EGL_PENDING_FRAME_NV 0x3329
+#define EGL_STREAM_TIME_PENDING_NV 0x332A
+#endif /* EGL_NV_stream_fifo_next */
+
+#ifndef EGL_NV_stream_fifo_synchronous
+#define EGL_NV_stream_fifo_synchronous 1
+#define EGL_STREAM_FIFO_SYNCHRONOUS_NV 0x3336
+#endif /* EGL_NV_stream_fifo_synchronous */
+
+#ifndef EGL_NV_stream_flush
+#define EGL_NV_stream_flush 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSTREAMFLUSHNVPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamFlushNV (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_NV_stream_flush */
+
+#ifndef EGL_NV_stream_frame_limits
+#define EGL_NV_stream_frame_limits 1
+#define EGL_PRODUCER_MAX_FRAME_HINT_NV 0x3337
+#define EGL_CONSUMER_MAX_FRAME_HINT_NV 0x3338
+#endif /* EGL_NV_stream_frame_limits */
+
+#ifndef EGL_NV_stream_metadata
+#define EGL_NV_stream_metadata 1
+#define EGL_MAX_STREAM_METADATA_BLOCKS_NV 0x3250
+#define EGL_MAX_STREAM_METADATA_BLOCK_SIZE_NV 0x3251
+#define EGL_MAX_STREAM_METADATA_TOTAL_SIZE_NV 0x3252
+#define EGL_PRODUCER_METADATA_NV 0x3253
+#define EGL_CONSUMER_METADATA_NV 0x3254
+#define EGL_PENDING_METADATA_NV 0x3328
+#define EGL_METADATA0_SIZE_NV 0x3255
+#define EGL_METADATA1_SIZE_NV 0x3256
+#define EGL_METADATA2_SIZE_NV 0x3257
+#define EGL_METADATA3_SIZE_NV 0x3258
+#define EGL_METADATA0_TYPE_NV 0x3259
+#define EGL_METADATA1_TYPE_NV 0x325A
+#define EGL_METADATA2_TYPE_NV 0x325B
+#define EGL_METADATA3_TYPE_NV 0x325C
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBNVPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSETSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYSTREAMMETADATANVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribNV (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+EGLAPI EGLBoolean EGLAPIENTRY eglSetStreamMetadataNV (EGLDisplay dpy, EGLStreamKHR stream, EGLint n, EGLint offset, EGLint size, const void *data);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryStreamMetadataNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum name, EGLint n, EGLint offset, EGLint size, void *data);
+#endif
+#endif /* EGL_NV_stream_metadata */
+
+#ifndef EGL_NV_stream_origin
+#define EGL_NV_stream_origin 1
+#define EGL_STREAM_FRAME_ORIGIN_X_NV 0x3366
+#define EGL_STREAM_FRAME_ORIGIN_Y_NV 0x3367
+#define EGL_STREAM_FRAME_MAJOR_AXIS_NV 0x3368
+#define EGL_CONSUMER_AUTO_ORIENTATION_NV 0x3369
+#define EGL_PRODUCER_AUTO_ORIENTATION_NV 0x336A
+#define EGL_LEFT_NV 0x336B
+#define EGL_RIGHT_NV 0x336C
+#define EGL_TOP_NV 0x336D
+#define EGL_BOTTOM_NV 0x336E
+#define EGL_X_AXIS_NV 0x336F
+#define EGL_Y_AXIS_NV 0x3370
+#endif /* EGL_NV_stream_origin */
+
+#ifndef EGL_NV_stream_remote
+#define EGL_NV_stream_remote 1
+#define EGL_STREAM_STATE_INITIALIZING_NV 0x3240
+#define EGL_STREAM_TYPE_NV 0x3241
+#define EGL_STREAM_PROTOCOL_NV 0x3242
+#define EGL_STREAM_ENDPOINT_NV 0x3243
+#define EGL_STREAM_LOCAL_NV 0x3244
+#define EGL_STREAM_PRODUCER_NV 0x3247
+#define EGL_STREAM_CONSUMER_NV 0x3248
+#define EGL_STREAM_PROTOCOL_FD_NV 0x3246
+#endif /* EGL_NV_stream_remote */
+
+#ifndef EGL_NV_stream_reset
+#define EGL_NV_stream_reset 1
+#define EGL_SUPPORT_RESET_NV 0x3334
+#define EGL_SUPPORT_REUSE_NV 0x3335
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLRESETSTREAMNVPROC) (EGLDisplay dpy, EGLStreamKHR stream);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglResetStreamNV (EGLDisplay dpy, EGLStreamKHR stream);
+#endif
+#endif /* EGL_NV_stream_reset */
+
+#ifndef EGL_NV_stream_socket
+#define EGL_NV_stream_socket 1
+#define EGL_STREAM_PROTOCOL_SOCKET_NV 0x324B
+#define EGL_SOCKET_HANDLE_NV 0x324C
+#define EGL_SOCKET_TYPE_NV 0x324D
+#endif /* EGL_NV_stream_socket */
+
+#ifndef EGL_NV_stream_socket_inet
+#define EGL_NV_stream_socket_inet 1
+#define EGL_SOCKET_TYPE_INET_NV 0x324F
+#endif /* EGL_NV_stream_socket_inet */
+
+#ifndef EGL_NV_stream_socket_unix
+#define EGL_NV_stream_socket_unix 1
+#define EGL_SOCKET_TYPE_UNIX_NV 0x324E
+#endif /* EGL_NV_stream_socket_unix */
+
+#ifndef EGL_NV_stream_sync
+#define EGL_NV_stream_sync 1
+#define EGL_SYNC_NEW_FRAME_NV 0x321F
+typedef EGLSyncKHR (EGLAPIENTRYP PFNEGLCREATESTREAMSYNCNVPROC) (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncKHR EGLAPIENTRY eglCreateStreamSyncNV (EGLDisplay dpy, EGLStreamKHR stream, EGLenum type, const EGLint *attrib_list);
+#endif
+#endif /* EGL_NV_stream_sync */
+
+#ifndef EGL_NV_sync
+#define EGL_NV_sync 1
+typedef void *EGLSyncNV;
+typedef khronos_utime_nanoseconds_t EGLTimeNV;
+#ifdef KHRONOS_SUPPORT_INT64
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE_NV 0x30E6
+#define EGL_SYNC_STATUS_NV 0x30E7
+#define EGL_SIGNALED_NV 0x30E8
+#define EGL_UNSIGNALED_NV 0x30E9
+#define EGL_SYNC_FLUSH_COMMANDS_BIT_NV 0x0001
+#define EGL_FOREVER_NV 0xFFFFFFFFFFFFFFFFull
+#define EGL_ALREADY_SIGNALED_NV 0x30EA
+#define EGL_TIMEOUT_EXPIRED_NV 0x30EB
+#define EGL_CONDITION_SATISFIED_NV 0x30EC
+#define EGL_SYNC_TYPE_NV 0x30ED
+#define EGL_SYNC_CONDITION_NV 0x30EE
+#define EGL_SYNC_FENCE_NV 0x30EF
+#define EGL_NO_SYNC_NV EGL_CAST(EGLSyncNV,0)
+typedef EGLSyncNV (EGLAPIENTRYP PFNEGLCREATEFENCESYNCNVPROC) (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLDESTROYSYNCNVPROC) (EGLSyncNV sync);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLFENCENVPROC) (EGLSyncNV sync);
+typedef EGLint (EGLAPIENTRYP PFNEGLCLIENTWAITSYNCNVPROC) (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSIGNALSYNCNVPROC) (EGLSyncNV sync, EGLenum mode);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCATTRIBNVPROC) (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLSyncNV EGLAPIENTRY eglCreateFenceSyncNV (EGLDisplay dpy, EGLenum condition, const EGLint *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglDestroySyncNV (EGLSyncNV sync);
+EGLAPI EGLBoolean EGLAPIENTRY eglFenceNV (EGLSyncNV sync);
+EGLAPI EGLint EGLAPIENTRY eglClientWaitSyncNV (EGLSyncNV sync, EGLint flags, EGLTimeNV timeout);
+EGLAPI EGLBoolean EGLAPIENTRY eglSignalSyncNV (EGLSyncNV sync, EGLenum mode);
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncAttribNV (EGLSyncNV sync, EGLint attribute, EGLint *value);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_sync */
+
+#ifndef EGL_NV_system_time
+#define EGL_NV_system_time 1
+typedef khronos_utime_nanoseconds_t EGLuint64NV;
+#ifdef KHRONOS_SUPPORT_INT64
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMEFREQUENCYNVPROC) (void);
+typedef EGLuint64NV (EGLAPIENTRYP PFNEGLGETSYSTEMTIMENVPROC) (void);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeFrequencyNV (void);
+EGLAPI EGLuint64NV EGLAPIENTRY eglGetSystemTimeNV (void);
+#endif
+#endif /* KHRONOS_SUPPORT_INT64 */
+#endif /* EGL_NV_system_time */
+
+#ifndef EGL_NV_triple_buffer
+#define EGL_NV_triple_buffer 1
+#define EGL_TRIPLE_BUFFER_NV 0x3230
+#endif /* EGL_NV_triple_buffer */
+
+#ifndef EGL_TIZEN_image_native_buffer
+#define EGL_TIZEN_image_native_buffer 1
+#define EGL_NATIVE_BUFFER_TIZEN 0x32A0
+#endif /* EGL_TIZEN_image_native_buffer */
+
+#ifndef EGL_TIZEN_image_native_surface
+#define EGL_TIZEN_image_native_surface 1
+#define EGL_NATIVE_SURFACE_TIZEN 0x32A1
+#endif /* EGL_TIZEN_image_native_surface */
+
+#ifndef EGL_WL_bind_wayland_display
+#define EGL_WL_bind_wayland_display 1
+#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC
+#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC
+#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC
+struct wl_display;
+struct wl_resource;
+#define EGL_WAYLAND_BUFFER_WL 0x31D5
+#define EGL_WAYLAND_PLANE_WL 0x31D6
+#define EGL_TEXTURE_Y_U_V_WL 0x31D7
+#define EGL_TEXTURE_Y_UV_WL 0x31D8
+#define EGL_TEXTURE_Y_XUXV_WL 0x31D9
+#define EGL_TEXTURE_EXTERNAL_WL 0x31DA
+#define EGL_WAYLAND_Y_INVERTED_WL 0x31DB
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLBINDWAYLANDDISPLAYWLPROC) (EGLDisplay dpy, struct wl_display *display);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLUNBINDWAYLANDDISPLAYWLPROC) (EGLDisplay dpy, struct wl_display *display);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYWAYLANDBUFFERWLPROC) (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglBindWaylandDisplayWL (EGLDisplay dpy, struct wl_display *display);
+EGLAPI EGLBoolean EGLAPIENTRY eglUnbindWaylandDisplayWL (EGLDisplay dpy, struct wl_display *display);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryWaylandBufferWL (EGLDisplay dpy, struct wl_resource *buffer, EGLint attribute, EGLint *value);
+#endif
+#endif /* EGL_WL_bind_wayland_display */
+
+#ifndef EGL_WL_create_wayland_buffer_from_image
+#define EGL_WL_create_wayland_buffer_from_image 1
+#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
+struct wl_buffer;
+typedef struct wl_buffer *(EGLAPIENTRYP PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC) (EGLDisplay dpy, EGLImageKHR image);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI struct wl_buffer *EGLAPIENTRY eglCreateWaylandBufferFromImageWL (EGLDisplay dpy, EGLImageKHR image);
+#endif
+#endif /* EGL_WL_create_wayland_buffer_from_image */
+
+/* ANGLE EGL extensions */
+#include "eglext_angle.h"
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif
diff --git a/thirdparty/angle/include/EGL/eglext_angle.h b/thirdparty/angle/include/EGL/eglext_angle.h
new file mode 100644
index 0000000000..4f3f3264ba
--- /dev/null
+++ b/thirdparty/angle/include/EGL/eglext_angle.h
@@ -0,0 +1,428 @@
+//
+// Copyright 2017 The ANGLE Project Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+//
+// eglext_angle.h: ANGLE modifications to the eglext.h header file.
+// Currently we don't include this file directly, we patch eglext.h
+// to include it implicitly so it is visible throughout our code.
+
+#ifndef INCLUDE_EGL_EGLEXT_ANGLE_
+#define INCLUDE_EGL_EGLEXT_ANGLE_
+
+// clang-format off
+
+#ifndef EGL_ANGLE_robust_resource_initialization
+#define EGL_ANGLE_robust_resource_initialization 1
+#define EGL_ROBUST_RESOURCE_INITIALIZATION_ANGLE 0x3453
+#endif /* EGL_ANGLE_robust_resource_initialization */
+
+#ifndef EGL_ANGLE_keyed_mutex
+#define EGL_ANGLE_keyed_mutex 1
+#define EGL_DXGI_KEYED_MUTEX_ANGLE 0x33A2
+#endif /* EGL_ANGLE_keyed_mutex */
+
+#ifndef EGL_ANGLE_d3d_texture_client_buffer
+#define EGL_ANGLE_d3d_texture_client_buffer 1
+#define EGL_D3D_TEXTURE_ANGLE 0x33A3
+#define EGL_TEXTURE_OFFSET_X_ANGLE 0x3490
+#define EGL_TEXTURE_OFFSET_Y_ANGLE 0x3491
+#define EGL_D3D11_TEXTURE_PLANE_ANGLE 0x3492
+#define EGL_D3D11_TEXTURE_ARRAY_SLICE_ANGLE 0x3493
+#endif /* EGL_ANGLE_d3d_texture_client_buffer */
+
+#ifndef EGL_ANGLE_software_display
+#define EGL_ANGLE_software_display 1
+#define EGL_SOFTWARE_DISPLAY_ANGLE ((EGLNativeDisplayType)-1)
+#endif /* EGL_ANGLE_software_display */
+
+#ifndef EGL_ANGLE_direct3d_display
+#define EGL_ANGLE_direct3d_display 1
+#define EGL_D3D11_ELSE_D3D9_DISPLAY_ANGLE ((EGLNativeDisplayType)-2)
+#define EGL_D3D11_ONLY_DISPLAY_ANGLE ((EGLNativeDisplayType)-3)
+#endif /* EGL_ANGLE_direct3d_display */
+
+#ifndef EGL_ANGLE_direct_composition
+#define EGL_ANGLE_direct_composition 1
+#define EGL_DIRECT_COMPOSITION_ANGLE 0x33A5
+#endif /* EGL_ANGLE_direct_composition */
+
+#ifndef EGL_ANGLE_platform_angle
+#define EGL_ANGLE_platform_angle 1
+#define EGL_PLATFORM_ANGLE_ANGLE 0x3202
+#define EGL_PLATFORM_ANGLE_TYPE_ANGLE 0x3203
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MAJOR_ANGLE 0x3204
+#define EGL_PLATFORM_ANGLE_MAX_VERSION_MINOR_ANGLE 0x3205
+#define EGL_PLATFORM_ANGLE_TYPE_DEFAULT_ANGLE 0x3206
+#define EGL_PLATFORM_ANGLE_DEBUG_LAYERS_ENABLED_ANGLE 0x3451
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_ANGLE 0x3209
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_HARDWARE_ANGLE 0x320A
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_NULL_ANGLE 0x345E
+#define EGL_PLATFORM_ANGLE_NATIVE_PLATFORM_TYPE_ANGLE 0x348F
+#endif /* EGL_ANGLE_platform_angle */
+
+#ifndef EGL_ANGLE_platform_angle_d3d
+#define EGL_ANGLE_platform_angle_d3d 1
+#define EGL_PLATFORM_ANGLE_TYPE_D3D9_ANGLE 0x3207
+#define EGL_PLATFORM_ANGLE_TYPE_D3D11_ANGLE 0x3208
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_WARP_ANGLE 0x320B
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_D3D_REFERENCE_ANGLE 0x320C
+#define EGL_PLATFORM_ANGLE_ENABLE_AUTOMATIC_TRIM_ANGLE 0x320F
+#endif /* EGL_ANGLE_platform_angle_d3d */
+
+#ifndef EGL_ANGLE_platform_angle_d3d_luid
+#define EGL_ANGLE_platform_angle_d3d_luid 1
+#define EGL_PLATFORM_ANGLE_D3D_LUID_HIGH_ANGLE 0x34A0
+#define EGL_PLATFORM_ANGLE_D3D_LUID_LOW_ANGLE 0x34A1
+#endif /* EGL_ANGLE_platform_angle_d3d_luid */
+
+#ifndef EGL_ANGLE_platform_angle_d3d11on12
+#define EGL_ANGLE_platform_angle_d3d11on12 1
+#define EGL_PLATFORM_ANGLE_D3D11ON12_ANGLE 0x3488
+#endif /* EGL_ANGLE_platform_angle_d3d11on12 */
+
+#ifndef EGL_ANGLE_platform_angle_opengl
+#define EGL_ANGLE_platform_angle_opengl 1
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGL_ANGLE 0x320D
+#define EGL_PLATFORM_ANGLE_TYPE_OPENGLES_ANGLE 0x320E
+#define EGL_PLATFORM_ANGLE_EGL_HANDLE_ANGLE 0x3480
+#endif /* EGL_ANGLE_platform_angle_opengl */
+
+#ifndef EGL_ANGLE_platform_angle_null
+#define EGL_ANGLE_platform_angle_null 1
+#define EGL_PLATFORM_ANGLE_TYPE_NULL_ANGLE 0x33AE
+#endif /* EGL_ANGLE_platform_angle_null */
+
+#ifndef EGL_ANGLE_platform_angle_vulkan
+#define EGL_ANGLE_platform_angle_vulkan 1
+#define EGL_PLATFORM_ANGLE_TYPE_VULKAN_ANGLE 0x3450
+#define EGL_PLATFORM_VULKAN_DISPLAY_MODE_SIMPLE_ANGLE 0x34A4
+#define EGL_PLATFORM_VULKAN_DISPLAY_MODE_HEADLESS_ANGLE 0x34A5
+#endif /* EGL_ANGLE_platform_angle_vulkan */
+
+#ifndef EGL_ANGLE_platform_angle_metal
+#define EGL_ANGLE_platform_angle_metal 1
+#define EGL_PLATFORM_ANGLE_TYPE_METAL_ANGLE 0x3489
+#endif /* EGL_ANGLE_platform_angle_metal */
+
+#ifndef EGL_ANGLE_platform_angle_device_type_swiftshader
+#define EGL_ANGLE_platform_angle_device_type_swiftshader
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_SWIFTSHADER_ANGLE 0x3487
+#endif /* EGL_ANGLE_platform_angle_device_type_swiftshader */
+
+#ifndef EGL_ANGLE_platform_angle_device_type_egl_angle
+#define EGL_ANGLE_platform_angle_device_type_egl_angle
+#define EGL_PLATFORM_ANGLE_DEVICE_TYPE_EGL_ANGLE 0x348E
+#endif /* EGL_ANGLE_platform_angle_device_type_egl_angle */
+
+#ifndef EGL_ANGLE_context_virtualization
+#define EGL_ANGLE_context_virtualization 1
+#define EGL_CONTEXT_VIRTUALIZATION_GROUP_ANGLE 0x3481
+#endif /* EGL_ANGLE_context_virtualization */
+
+#ifndef EGL_ANGLE_platform_angle_device_context_volatile_eagl
+#define EGL_ANGLE_platform_angle_device_context_volatile_eagl 1
+#define EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_EAGL_ANGLE 0x34A2
+#endif /* EGL_ANGLE_platform_angle_device_context_volatile_eagl */
+
+#ifndef EGL_ANGLE_platform_angle_device_context_volatile_cgl
+#define EGL_ANGLE_platform_angle_device_context_volatile_cgl 1
+#define EGL_PLATFORM_ANGLE_DEVICE_CONTEXT_VOLATILE_CGL_ANGLE 0x34A3
+#endif /* EGL_ANGLE_platform_angle_device_context_volatile_cgl */
+
+#ifndef EGL_ANGLE_platform_angle_device_id
+#define EGL_ANGLE_platform_angle_device_id
+#define EGL_PLATFORM_ANGLE_DEVICE_ID_HIGH_ANGLE 0x34D6
+#define EGL_PLATFORM_ANGLE_DEVICE_ID_LOW_ANGLE 0x34D7
+#define EGL_PLATFORM_ANGLE_DISPLAY_KEY_ANGLE 0x34DC
+#endif /* EGL_ANGLE_platform_angle_device_id */
+
+#ifndef EGL_ANGLE_x11_visual
+#define EGL_ANGLE_x11_visual
+#define EGL_X11_VISUAL_ID_ANGLE 0x33A3
+#endif /* EGL_ANGLE_x11_visual */
+
+#ifndef EGL_ANGLE_surface_orientation
+#define EGL_ANGLE_surface_orientation
+#define EGL_OPTIMAL_SURFACE_ORIENTATION_ANGLE 0x33A7
+#define EGL_SURFACE_ORIENTATION_ANGLE 0x33A8
+#define EGL_SURFACE_ORIENTATION_INVERT_X_ANGLE 0x0001
+#define EGL_SURFACE_ORIENTATION_INVERT_Y_ANGLE 0x0002
+#endif /* EGL_ANGLE_surface_orientation */
+
+#ifndef EGL_ANGLE_experimental_present_path
+#define EGL_ANGLE_experimental_present_path
+#define EGL_EXPERIMENTAL_PRESENT_PATH_ANGLE 0x33A4
+#define EGL_EXPERIMENTAL_PRESENT_PATH_FAST_ANGLE 0x33A9
+#define EGL_EXPERIMENTAL_PRESENT_PATH_COPY_ANGLE 0x33AA
+#endif /* EGL_ANGLE_experimental_present_path */
+
+#ifndef EGL_ANGLE_stream_producer_d3d_texture
+#define EGL_ANGLE_stream_producer_d3d_texture
+#define EGL_D3D_TEXTURE_SUBRESOURCE_ID_ANGLE 0x33AB
+typedef EGLBoolean(EGLAPIENTRYP PFNEGLCREATESTREAMPRODUCERD3DTEXTUREANGLEPROC)(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+typedef EGLBoolean(EGLAPIENTRYP PFNEGLSTREAMPOSTD3DTEXTUREANGLEPROC)(EGLDisplay dpy, EGLStreamKHR stream, void *texture, const EGLAttrib *attrib_list);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglCreateStreamProducerD3DTextureANGLE(EGLDisplay dpy, EGLStreamKHR stream, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglStreamPostD3DTextureANGLE(EGLDisplay dpy, EGLStreamKHR stream, void *texture, const EGLAttrib *attrib_list);
+#endif
+#endif /* EGL_ANGLE_stream_producer_d3d_texture */
+
+#ifndef EGL_ANGLE_create_context_webgl_compatibility
+#define EGL_ANGLE_create_context_webgl_compatibility 1
+#define EGL_CONTEXT_WEBGL_COMPATIBILITY_ANGLE 0x33AC
+#endif /* EGL_ANGLE_create_context_webgl_compatibility */
+
+#ifndef EGL_ANGLE_display_texture_share_group
+#define EGL_ANGLE_display_texture_share_group 1
+#define EGL_DISPLAY_TEXTURE_SHARE_GROUP_ANGLE 0x33AF
+#endif /* EGL_ANGLE_display_texture_share_group */
+
+#ifndef EGL_CHROMIUM_create_context_bind_generates_resource
+#define EGL_CHROMIUM_create_context_bind_generates_resource 1
+#define EGL_CONTEXT_BIND_GENERATES_RESOURCE_CHROMIUM 0x33AD
+#endif /* EGL_CHROMIUM_create_context_bind_generates_resource */
+
+#ifndef EGL_ANGLE_metal_create_context_ownership_identity
+#define EGL_ANGLE_metal_create_context_ownership_identity 1
+#define EGL_CONTEXT_METAL_OWNERSHIP_IDENTITY_ANGLE 0x34D2
+#endif /* EGL_ANGLE_metal_create_context_ownership_identity */
+
+#ifndef EGL_ANGLE_create_context_client_arrays
+#define EGL_ANGLE_create_context_client_arrays 1
+#define EGL_CONTEXT_CLIENT_ARRAYS_ENABLED_ANGLE 0x3452
+#endif /* EGL_ANGLE_create_context_client_arrays */
+
+#ifndef EGL_ANGLE_device_creation
+#define EGL_ANGLE_device_creation 1
+typedef EGLDeviceEXT(EGLAPIENTRYP PFNEGLCREATEDEVICEANGLEPROC) (EGLint device_type, void *native_device, const EGLAttrib *attrib_list);
+typedef EGLBoolean(EGLAPIENTRYP PFNEGLRELEASEDEVICEANGLEPROC) (EGLDeviceEXT device);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLDeviceEXT EGLAPIENTRY eglCreateDeviceANGLE(EGLint device_type, void *native_device, const EGLAttrib *attrib_list);
+EGLAPI EGLBoolean EGLAPIENTRY eglReleaseDeviceANGLE(EGLDeviceEXT device);
+#endif
+#endif /* EGL_ANGLE_device_creation */
+
+#ifndef EGL_ANGLE_program_cache_control
+#define EGL_ANGLE_program_cache_control 1
+#define EGL_PROGRAM_CACHE_SIZE_ANGLE 0x3455
+#define EGL_PROGRAM_CACHE_KEY_LENGTH_ANGLE 0x3456
+#define EGL_PROGRAM_CACHE_RESIZE_ANGLE 0x3457
+#define EGL_PROGRAM_CACHE_TRIM_ANGLE 0x3458
+#define EGL_CONTEXT_PROGRAM_BINARY_CACHE_ENABLED_ANGLE 0x3459
+typedef EGLint (EGLAPIENTRYP PFNEGLPROGRAMCACHEGETATTRIBANGLEPROC) (EGLDisplay dpy, EGLenum attrib);
+typedef void (EGLAPIENTRYP PFNEGLPROGRAMCACHEQUERYANGLEPROC) (EGLDisplay dpy, EGLint index, void *key, EGLint *keysize, void *binary, EGLint *binarysize);
+typedef void (EGLAPIENTRYP PFNEGLPROGRAMCACHEPOPULATEANGLEPROC) (EGLDisplay dpy, const void *key, EGLint keysize, const void *binary, EGLint binarysize);
+typedef EGLint (EGLAPIENTRYP PFNEGLPROGRAMCACHERESIZEANGLEPROC) (EGLDisplay dpy, EGLint limit, EGLint mode);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLint EGLAPIENTRY eglProgramCacheGetAttribANGLE(EGLDisplay dpy, EGLenum attrib);
+EGLAPI void EGLAPIENTRY eglProgramCacheQueryANGLE(EGLDisplay dpy, EGLint index, void *key, EGLint *keysize, void *binary, EGLint *binarysize);
+EGLAPI void EGLAPIENTRY eglProgramCachePopulateANGLE(EGLDisplay dpy, const void *key, EGLint keysize, const void *binary, EGLint binarysize);
+EGLAPI EGLint EGLAPIENTRY eglProgramCacheResizeANGLE(EGLDisplay dpy, EGLint limit, EGLint mode);
+#endif
+#endif /* EGL_ANGLE_program_cache_control */
+
+#ifndef EGL_ANGLE_iosurface_client_buffer
+#define EGL_ANGLE_iosurface_client_buffer 1
+#define EGL_IOSURFACE_ANGLE 0x3454
+#define EGL_IOSURFACE_PLANE_ANGLE 0x345A
+#define EGL_TEXTURE_RECTANGLE_ANGLE 0x345B
+#define EGL_TEXTURE_TYPE_ANGLE 0x345C
+#define EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D
+#define EGL_IOSURFACE_USAGE_HINT_ANGLE 0x348A
+#define EGL_IOSURFACE_READ_HINT_ANGLE 0x0001
+#define EGL_IOSURFACE_WRITE_HINT_ANGLE 0x0002
+#define EGL_BIND_TO_TEXTURE_TARGET_ANGLE 0x348D
+#endif /* EGL_ANGLE_iosurface_client_buffer */
+
+#ifndef ANGLE_metal_texture_client_buffer
+#define ANGLE_metal_texture_client_buffer 1
+#define EGL_METAL_TEXTURE_ANGLE 0x34A7
+#endif /* ANGLE_metal_texture_client_buffer */
+
+#ifndef EGL_ANGLE_create_context_extensions_enabled
+#define EGL_ANGLE_create_context_extensions_enabled 1
+#define EGL_EXTENSIONS_ENABLED_ANGLE 0x345F
+#endif /* EGL_ANGLE_create_context_extensions_enabled */
+
+#ifndef EGL_CHROMIUM_sync_control
+#define EGL_CHROMIUM_sync_control 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETSYNCVALUESCHROMIUMPROC) (EGLDisplay dpy,
+ EGLSurface surface,
+ EGLuint64KHR *ust,
+ EGLuint64KHR *msc,
+ EGLuint64KHR *sbc);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetSyncValuesCHROMIUM(EGLDisplay dpy,
+ EGLSurface surface,
+ EGLuint64KHR *ust,
+ EGLuint64KHR *msc,
+ EGLuint64KHR *sbc);
+#endif
+#endif /* EGL_CHROMIUM_sync_control */
+
+#ifndef EGL_ANGLE_sync_control_rate
+#define EGL_ANGLE_sync_control_rate 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLGETMSCRATEANGLEPROC) (EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint *numerator,
+ EGLint *denominator);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglGetMscRateANGLE(EGLDisplay dpy,
+ EGLSurface surface,
+ EGLint *numerator,
+ EGLint *denominator);
+#endif
+#endif /* EGL_ANGLE_sync_control_rate */
+
+#ifndef EGL_ANGLE_power_preference
+#define EGL_ANGLE_power_preference 1
+#define EGL_POWER_PREFERENCE_ANGLE 0x3482
+#define EGL_LOW_POWER_ANGLE 0x0001
+#define EGL_HIGH_POWER_ANGLE 0x0002
+typedef void(EGLAPIENTRYP PFNEGLRELEASEHIGHPOWERGPUANGLEPROC) (EGLDisplay dpy, EGLContext ctx);
+typedef void(EGLAPIENTRYP PFNEGLREACQUIREHIGHPOWERGPUANGLEPROC) (EGLDisplay dpy, EGLContext ctx);
+typedef void(EGLAPIENTRYP PFNEGLHANDLEGPUSWITCHANGLEPROC) (EGLDisplay dpy);
+typedef void(EGLAPIENTRYP PFNEGLFORCEGPUSWITCHANGLEPROC) (EGLDisplay dpy, EGLint gpuIDHigh, EGLint gpuIDLow);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglReleaseHighPowerGPUANGLE(EGLDisplay dpy, EGLContext ctx);
+EGLAPI void EGLAPIENTRY eglReacquireHighPowerGPUANGLE(EGLDisplay dpy, EGLContext ctx);
+EGLAPI void EGLAPIENTRY eglHandleGPUSwitchANGLE(EGLDisplay dpy);
+EGLAPI void EGLAPIENTRY eglForceGPUSwitchANGLE(EGLDisplay dpy, EGLint gpuIDHigh, EGLint gpuIDLow);
+#endif
+#endif /* EGL_ANGLE_power_preference */
+
+#ifndef EGL_ANGLE_wait_until_work_scheduled
+#define EGL_ANGLE_wait_until_work_scheduled 1
+typedef void(EGLAPIENTRYP PFNEGLWAITUNTILWORKSCHEDULEDANGLEPROC) (EGLDisplay dpy);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void EGLAPIENTRY eglWaitUntilWorkScheduledANGLE(EGLDisplay dpy);
+#endif
+#endif /* EGL_ANGLE_wait_until_work_scheduled */
+
+#ifndef EGL_ANGLE_feature_control
+#define EGL_ANGLE_feature_control 1
+#define EGL_FEATURE_NAME_ANGLE 0x3460
+#define EGL_FEATURE_CATEGORY_ANGLE 0x3461
+#define EGL_FEATURE_DESCRIPTION_ANGLE 0x3462
+#define EGL_FEATURE_BUG_ANGLE 0x3463
+#define EGL_FEATURE_STATUS_ANGLE 0x3464
+#define EGL_FEATURE_COUNT_ANGLE 0x3465
+#define EGL_FEATURE_OVERRIDES_ENABLED_ANGLE 0x3466
+#define EGL_FEATURE_OVERRIDES_DISABLED_ANGLE 0x3467
+#define EGL_FEATURE_CONDITION_ANGLE 0x3468
+#define EGL_FEATURE_ALL_DISABLED_ANGLE 0x3469
+typedef const char *(EGLAPIENTRYP PFNEGLQUERYSTRINGIANGLEPROC) (EGLDisplay dpy, EGLint name, EGLint index);
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLQUERYDISPLAYATTRIBANGLEPROC) (EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI const char *EGLAPIENTRY eglQueryStringiANGLE(EGLDisplay dpy, EGLint name, EGLint index);
+EGLAPI EGLBoolean EGLAPIENTRY eglQueryDisplayAttribANGLE(EGLDisplay dpy, EGLint attribute, EGLAttrib *value);
+#endif
+#endif /* EGL_ANGLE_feature_control */
+
+#ifndef EGL_ANGLE_image_d3d11_texture
+#define EGL_D3D11_TEXTURE_ANGLE 0x3484
+#define EGL_TEXTURE_INTERNAL_FORMAT_ANGLE 0x345D
+#endif /* EGL_ANGLE_image_d3d11_texture */
+
+#ifndef EGL_ANGLE_create_context_backwards_compatible
+#define EGL_ANGLE_create_context_backwards_compatible 1
+#define EGL_CONTEXT_OPENGL_BACKWARDS_COMPATIBLE_ANGLE 0x3483
+#endif /* EGL_ANGLE_create_context_backwards_compatible */
+
+#ifndef EGL_ANGLE_device_cgl
+#define EGL_ANGLE_device_cgl 1
+#define EGL_CGL_CONTEXT_ANGLE 0x3485
+#define EGL_CGL_PIXEL_FORMAT_ANGLE 0x3486
+#endif
+
+#ifndef EGL_ANGLE_ggp_stream_descriptor
+#define EGL_ANGLE_ggp_stream_descriptor 1
+#define EGL_GGP_STREAM_DESCRIPTOR_ANGLE 0x348B
+#endif /* EGL_ANGLE_ggp_stream_descriptor */
+
+#ifndef EGL_ANGLE_swap_with_frame_token
+#define EGL_ANGLE_swap_with_frame_token 1
+typedef khronos_uint64_t EGLFrameTokenANGLE;
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLSWAPBUFFERSWITHFRAMETOKENANGLEPROC)(EGLDisplay dpy, EGLSurface surface, EGLFrameTokenANGLE frametoken);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglSwapBuffersWithFrameTokenANGLE(EGLDisplay dpy, EGLSurface surface, EGLFrameTokenANGLE frametoken);
+#endif
+#endif /* EGL_ANGLE_swap_with_frame_token */
+
+#ifndef EGL_ANGLE_prepare_swap_buffers
+#define EGL_ANGLE_prepare_swap_buffers 1
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLPREPARESWAPBUFFERSANGLEPROC)(EGLDisplay dpy, EGLSurface surface);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglPrepareSwapBuffersANGLE(EGLDisplay dpy, EGLSurface surface);
+#endif
+#endif /* EGL_ANGLE_prepare_swap_buffers */
+
+#ifndef EGL_ANGLE_device_eagl
+#define EGL_ANGLE_device_eagl 1
+#define EGL_EAGL_CONTEXT_ANGLE 0x348C
+#endif
+
+#ifndef EGL_ANGLE_device_metal
+#define EGL_ANGLE_device_metal 1
+#define EGL_METAL_DEVICE_ANGLE 0x34A6
+#endif /* EGL_ANGLE_device_metal */
+
+#ifndef EGL_ANGLE_display_semaphore_share_group
+#define EGL_ANGLE_display_semaphore_share_group 1
+#define EGL_DISPLAY_SEMAPHORE_SHARE_GROUP_ANGLE 0x348D
+#endif /* EGL_ANGLE_display_semaphore_share_group */
+
+#ifndef EGL_ANGLE_external_context_and_surface
+#define EGL_ANGLE_external_context_and_surface 1
+#define EGL_EXTERNAL_CONTEXT_ANGLE 0x348E
+#define EGL_EXTERNAL_SURFACE_ANGLE 0x348F
+#define EGL_EXTERNAL_CONTEXT_SAVE_STATE_ANGLE 0x3490
+#endif /* EGL_ANGLE_external_context_and_surface */
+
+#ifndef EGL_ANGLE_create_surface_swap_interval
+#define EGL_ANGLE_create_surface_swap_interval 1
+#define EGL_SWAP_INTERVAL_ANGLE 0x322F
+#endif /* EGL_ANGLE_create_surface_swap_interval */
+
+#ifndef EGL_ANGLE_device_vulkan
+#define EGL_ANGLE_device_vulkan 1
+#define EGL_VULKAN_VERSION_ANGLE 0x34A8
+#define EGL_VULKAN_INSTANCE_ANGLE 0x34A9
+#define EGL_VULKAN_INSTANCE_EXTENSIONS_ANGLE 0x34AA
+#define EGL_VULKAN_PHYSICAL_DEVICE_ANGLE 0x34AB
+#define EGL_VULKAN_DEVICE_ANGLE 0x34AC
+#define EGL_VULKAN_DEVICE_EXTENSIONS_ANGLE 0x34AD
+#define EGL_VULKAN_FEATURES_ANGLE 0x34AE
+#define EGL_VULKAN_QUEUE_ANGLE 0x34AF
+#define EGL_VULKAN_QUEUE_FAMILIY_INDEX_ANGLE 0x34D0
+#define EGL_VULKAN_GET_INSTANCE_PROC_ADDR 0x34D1
+#endif /* EGL_ANGLE_device_vulkan */
+
+#ifndef EGL_ANGLE_vulkan_image
+#define EGL_ANGLE_vulkan_image
+#define EGL_VULKAN_IMAGE_ANGLE 0x34D3
+#define EGL_VULKAN_IMAGE_CREATE_INFO_HI_ANGLE 0x34D4
+#define EGL_VULKAN_IMAGE_CREATE_INFO_LO_ANGLE 0x34D5
+typedef EGLBoolean (EGLAPIENTRYP PFNEGLEXPORTVKIMAGEANGLEPROC)(EGLDisplay dpy, EGLImage image, void* vk_image, void* vk_image_create_info);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI EGLBoolean EGLAPIENTRY eglExportVkImageANGLE(EGLDisplay dpy, EGLImage image, void* vk_image, void* vk_image_create_info);
+#endif
+#endif /* EGL_ANGLE_vulkan_image */
+
+#ifndef EGL_ANGLE_metal_shared_event_sync
+#define EGL_ANGLE_metal_hared_event_sync 1
+#define EGL_SYNC_METAL_SHARED_EVENT_ANGLE 0x34D8
+#define EGL_SYNC_METAL_SHARED_EVENT_OBJECT_ANGLE 0x34D9
+#define EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_LO_ANGLE 0x34DA
+#define EGL_SYNC_METAL_SHARED_EVENT_SIGNAL_VALUE_HI_ANGLE 0x34DB
+#define EGL_SYNC_METAL_SHARED_EVENT_SIGNALED_ANGLE 0x34DC
+typedef void* (EGLAPIENTRYP PFNEGLCOPYMETALSHAREDEVENTANGLEPROC)(EGLDisplay dpy, EGLSync sync);
+#ifdef EGL_EGLEXT_PROTOTYPES
+EGLAPI void *EGLAPIENTRY eglCopyMetalSharedEventANGLE(EGLDisplay dpy, EGLSync sync);
+#endif
+#endif /* EGL_ANGLE_metal_shared_event_sync */
+
+// clang-format on
+
+#endif // INCLUDE_EGL_EGLEXT_ANGLE_
diff --git a/thirdparty/angle/include/EGL/eglplatform.h b/thirdparty/angle/include/EGL/eglplatform.h
new file mode 100644
index 0000000000..777e985588
--- /dev/null
+++ b/thirdparty/angle/include/EGL/eglplatform.h
@@ -0,0 +1,175 @@
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright 2007-2020 The Khronos Group Inc.
+** SPDX-License-Identifier: Apache-2.0
+*/
+
+/* Platform-specific types and definitions for egl.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by filing an issue or pull request on the public Khronos EGL Registry, at
+ * https://www.github.com/KhronosGroup/EGL-Registry/
+ */
+
+#include <KHR/khrplatform.h>
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#ifndef EGLAPIENTRY
+#define EGLAPIENTRY KHRONOS_APIENTRY
+#endif
+#define EGLAPIENTRYP EGLAPIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ *
+ * Khronos STRONGLY RECOMMENDS that you use the default definitions
+ * provided below, since these changes affect both binary and source
+ * portability of applications using EGL running on different EGL
+ * implementations.
+ */
+
+#if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES)
+
+typedef void *EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+typedef HDC EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+
+#if !defined(WINAPI_FAMILY) || (WINAPI_FAMILY == WINAPI_FAMILY_DESKTOP_APP) /* Windows Desktop */
+typedef HWND EGLNativeWindowType;
+#else /* Windows Store */
+#include <inspectable.h>
+typedef IInspectable* EGLNativeWindowType;
+#endif
+
+#elif defined(__EMSCRIPTEN__)
+
+typedef int EGLNativeDisplayType;
+typedef int EGLNativePixmapType;
+typedef int EGLNativeWindowType;
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(WL_EGL_PLATFORM)
+
+typedef struct wl_display *EGLNativeDisplayType;
+typedef struct wl_egl_pixmap *EGLNativePixmapType;
+typedef struct wl_egl_window *EGLNativeWindowType;
+
+#elif defined(__GBM__)
+
+typedef struct gbm_device *EGLNativeDisplayType;
+typedef struct gbm_bo *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(__ANDROID__) || defined(ANDROID)
+
+struct ANativeWindow;
+struct egl_native_pixmap_t;
+
+typedef void* EGLNativeDisplayType;
+typedef struct egl_native_pixmap_t* EGLNativePixmapType;
+typedef struct ANativeWindow* EGLNativeWindowType;
+
+#elif defined(USE_OZONE)
+
+typedef intptr_t EGLNativeDisplayType;
+typedef intptr_t EGLNativePixmapType;
+typedef intptr_t EGLNativeWindowType;
+
+#elif defined(USE_X11)
+
+/* X11 (tentative) */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap EGLNativePixmapType;
+typedef Window EGLNativeWindowType;
+
+#elif defined(__unix__)
+
+typedef void *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
+#elif defined(__APPLE__)
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(__HAIKU__)
+
+#include <kernel/image.h>
+
+typedef void *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
+#elif defined(__Fuchsia__)
+
+typedef void *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType NativePixmapType;
+typedef EGLNativeWindowType NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other. While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+
+/* C++ / C typecast macros for special EGL handle values */
+#if defined(__cplusplus)
+#define EGL_CAST(type, value) (static_cast<type>(value))
+#else
+#define EGL_CAST(type, value) ((type) (value))
+#endif
+
+#endif /* __eglplatform_h */
diff --git a/thirdparty/angle/include/KHR/khrplatform.h b/thirdparty/angle/include/KHR/khrplatform.h
new file mode 100644
index 0000000000..dd22d92701
--- /dev/null
+++ b/thirdparty/angle/include/KHR/khrplatform.h
@@ -0,0 +1,290 @@
+#ifndef __khrplatform_h_
+#define __khrplatform_h_
+
+/*
+** Copyright (c) 2008-2018 The Khronos Group Inc.
+**
+** Permission is hereby granted, free of charge, to any person obtaining a
+** copy of this software and/or associated documentation files (the
+** "Materials"), to deal in the Materials without restriction, including
+** without limitation the rights to use, copy, modify, merge, publish,
+** distribute, sublicense, and/or sell copies of the Materials, and to
+** permit persons to whom the Materials are 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 Materials.
+**
+** THE MATERIALS ARE 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
+** MATERIALS OR THE USE OR OTHER DEALINGS IN THE MATERIALS.
+*/
+
+/* Khronos platform-specific types and definitions.
+ *
+ * The master copy of khrplatform.h is maintained in the Khronos EGL
+ * Registry repository at https://github.com/KhronosGroup/EGL-Registry
+ * The last semantic modification to khrplatform.h was at commit ID:
+ * 67a3e0864c2d75ea5287b9f3d2eb74a745936692
+ *
+ * Adopters may modify this file to suit their platform. Adopters are
+ * encouraged to submit platform specific modifications to the Khronos
+ * group so that they can be included in future versions of this file.
+ * Please submit changes by filing pull requests or issues on
+ * the EGL Registry repository linked above.
+ *
+ *
+ * See the Implementer's Guidelines for information about where this file
+ * should be located on your system and for more details of its use:
+ * http://www.khronos.org/registry/implementers_guide.pdf
+ *
+ * This file should be included as
+ * #include <KHR/khrplatform.h>
+ * by Khronos client API header files that use its types and defines.
+ *
+ * The types in khrplatform.h should only be used to define API-specific types.
+ *
+ * Types defined in khrplatform.h:
+ * khronos_int8_t signed 8 bit
+ * khronos_uint8_t unsigned 8 bit
+ * khronos_int16_t signed 16 bit
+ * khronos_uint16_t unsigned 16 bit
+ * khronos_int32_t signed 32 bit
+ * khronos_uint32_t unsigned 32 bit
+ * khronos_int64_t signed 64 bit
+ * khronos_uint64_t unsigned 64 bit
+ * khronos_intptr_t signed same number of bits as a pointer
+ * khronos_uintptr_t unsigned same number of bits as a pointer
+ * khronos_ssize_t signed size
+ * khronos_usize_t unsigned size
+ * khronos_float_t signed 32 bit floating point
+ * khronos_time_ns_t unsigned 64 bit time in nanoseconds
+ * khronos_utime_nanoseconds_t unsigned time interval or absolute time in
+ * nanoseconds
+ * khronos_stime_nanoseconds_t signed time interval in nanoseconds
+ * khronos_boolean_enum_t enumerated boolean type. This should
+ * only be used as a base type when a client API's boolean type is
+ * an enum. Client APIs which use an integer or other type for
+ * booleans cannot use this as the base type for their boolean.
+ *
+ * Tokens defined in khrplatform.h:
+ *
+ * KHRONOS_FALSE, KHRONOS_TRUE Enumerated boolean false/true values.
+ *
+ * KHRONOS_SUPPORT_INT64 is 1 if 64 bit integers are supported; otherwise 0.
+ * KHRONOS_SUPPORT_FLOAT is 1 if floats are supported; otherwise 0.
+ *
+ * Calling convention macros defined in this file:
+ * KHRONOS_APICALL
+ * KHRONOS_APIENTRY
+ * KHRONOS_APIATTRIBUTES
+ *
+ * These may be used in function prototypes as:
+ *
+ * KHRONOS_APICALL void KHRONOS_APIENTRY funcname(
+ * int arg1,
+ * int arg2) KHRONOS_APIATTRIBUTES;
+ */
+
+#if defined(__SCITECH_SNAP__) && !defined(KHRONOS_STATIC)
+# define KHRONOS_STATIC 1
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APICALL
+ *-------------------------------------------------------------------------
+ * This precedes the return type of the function in the function prototype.
+ */
+#if defined(KHRONOS_STATIC)
+ /* If the preprocessor constant KHRONOS_STATIC is defined, make the
+ * header compatible with static linking. */
+# define KHRONOS_APICALL
+#elif defined(_WIN32)
+# define KHRONOS_APICALL __declspec(dllimport)
+#elif defined (__SYMBIAN32__)
+# define KHRONOS_APICALL IMPORT_C
+#elif defined(__ANDROID__)
+# define KHRONOS_APICALL __attribute__((visibility("default")))
+#else
+# define KHRONOS_APICALL
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIENTRY
+ *-------------------------------------------------------------------------
+ * This follows the return type of the function and precedes the function
+ * name in the function prototype.
+ */
+#if defined(_WIN32) && !defined(_WIN32_WCE) && !defined(__SCITECH_SNAP__)
+ /* Win32 but not WinCE */
+# define KHRONOS_APIENTRY __stdcall
+#else
+# define KHRONOS_APIENTRY
+#endif
+
+/*-------------------------------------------------------------------------
+ * Definition of KHRONOS_APIATTRIBUTES
+ *-------------------------------------------------------------------------
+ * This follows the closing parenthesis of the function prototype arguments.
+ */
+#if defined (__ARMCC_2__)
+#define KHRONOS_APIATTRIBUTES __softfp
+#else
+#define KHRONOS_APIATTRIBUTES
+#endif
+
+/*-------------------------------------------------------------------------
+ * basic type definitions
+ *-----------------------------------------------------------------------*/
+#if (defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L) || defined(__GNUC__) || defined(__SCO__) || defined(__USLC__)
+
+
+/*
+ * Using <stdint.h>
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__VMS ) || defined(__sgi)
+
+/*
+ * Using <inttypes.h>
+ */
+#include <inttypes.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(_WIN32) && !defined(__SCITECH_SNAP__)
+
+/*
+ * Win32
+ */
+typedef __int32 khronos_int32_t;
+typedef unsigned __int32 khronos_uint32_t;
+typedef __int64 khronos_int64_t;
+typedef unsigned __int64 khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif defined(__sun__) || defined(__digital__)
+
+/*
+ * Sun or Digital
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#if defined(__arch64__) || defined(_LP64)
+typedef long int khronos_int64_t;
+typedef unsigned long int khronos_uint64_t;
+#else
+typedef long long int khronos_int64_t;
+typedef unsigned long long int khronos_uint64_t;
+#endif /* __arch64__ */
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#elif 0
+
+/*
+ * Hypothetical platform with no float or int64 support
+ */
+typedef int khronos_int32_t;
+typedef unsigned int khronos_uint32_t;
+#define KHRONOS_SUPPORT_INT64 0
+#define KHRONOS_SUPPORT_FLOAT 0
+
+#else
+
+/*
+ * Generic fallback
+ */
+#include <stdint.h>
+typedef int32_t khronos_int32_t;
+typedef uint32_t khronos_uint32_t;
+typedef int64_t khronos_int64_t;
+typedef uint64_t khronos_uint64_t;
+#define KHRONOS_SUPPORT_INT64 1
+#define KHRONOS_SUPPORT_FLOAT 1
+
+#endif
+
+
+/*
+ * Types that are (so far) the same on all platforms
+ */
+typedef signed char khronos_int8_t;
+typedef unsigned char khronos_uint8_t;
+typedef signed short int khronos_int16_t;
+typedef unsigned short int khronos_uint16_t;
+
+/*
+ * Types that differ between LLP64 and LP64 architectures - in LLP64,
+ * pointers are 64 bits, but 'long' is still 32 bits. Win64 appears
+ * to be the only LLP64 architecture in current use.
+ */
+#ifdef _WIN64
+typedef signed long long int khronos_intptr_t;
+typedef unsigned long long int khronos_uintptr_t;
+typedef signed long long int khronos_ssize_t;
+typedef unsigned long long int khronos_usize_t;
+#else
+typedef signed long int khronos_intptr_t;
+typedef unsigned long int khronos_uintptr_t;
+typedef signed long int khronos_ssize_t;
+typedef unsigned long int khronos_usize_t;
+#endif
+
+#if KHRONOS_SUPPORT_FLOAT
+/*
+ * Float type
+ */
+typedef float khronos_float_t;
+#endif
+
+#if KHRONOS_SUPPORT_INT64
+/* Time types
+ *
+ * These types can be used to represent a time interval in nanoseconds or
+ * an absolute Unadjusted System Time. Unadjusted System Time is the number
+ * of nanoseconds since some arbitrary system event (e.g. since the last
+ * time the system booted). The Unadjusted System Time is an unsigned
+ * 64 bit value that wraps back to 0 every 584 years. Time intervals
+ * may be either signed or unsigned.
+ */
+typedef khronos_uint64_t khronos_utime_nanoseconds_t;
+typedef khronos_int64_t khronos_stime_nanoseconds_t;
+#endif
+
+/*
+ * Dummy value used to pad enum types to 32 bits.
+ */
+#ifndef KHRONOS_MAX_ENUM
+#define KHRONOS_MAX_ENUM 0x7FFFFFFF
+#endif
+
+/*
+ * Enumerated boolean type
+ *
+ * Values other than zero should be considered to be true. Therefore
+ * comparisons should not be made against KHRONOS_TRUE.
+ */
+typedef enum {
+ KHRONOS_FALSE = 0,
+ KHRONOS_TRUE = 1,
+ KHRONOS_BOOLEAN_ENUM_FORCE_SIZE = KHRONOS_MAX_ENUM
+} khronos_boolean_enum_t;
+
+#endif /* __khrplatform_h_ */
diff --git a/thirdparty/glad/EGL/eglplatform.h b/thirdparty/glad/EGL/eglplatform.h
new file mode 100644
index 0000000000..99362a23de
--- /dev/null
+++ b/thirdparty/glad/EGL/eglplatform.h
@@ -0,0 +1,169 @@
+#ifndef __eglplatform_h_
+#define __eglplatform_h_
+
+/*
+** Copyright 2007-2020 The Khronos Group Inc.
+** SPDX-License-Identifier: Apache-2.0
+*/
+
+/* Platform-specific types and definitions for egl.h
+ *
+ * Adopters may modify khrplatform.h and this file to suit their platform.
+ * You are encouraged to submit all modifications to the Khronos group so that
+ * they can be included in future versions of this file. Please submit changes
+ * by filing an issue or pull request on the public Khronos EGL Registry, at
+ * https://www.github.com/KhronosGroup/EGL-Registry/
+ */
+
+#include <KHR/khrplatform.h>
+
+/* Macros used in EGL function prototype declarations.
+ *
+ * EGL functions should be prototyped as:
+ *
+ * EGLAPI return-type EGLAPIENTRY eglFunction(arguments);
+ * typedef return-type (EXPAPIENTRYP PFNEGLFUNCTIONPROC) (arguments);
+ *
+ * KHRONOS_APICALL and KHRONOS_APIENTRY are defined in KHR/khrplatform.h
+ */
+
+#ifndef EGLAPI
+#define EGLAPI KHRONOS_APICALL
+#endif
+
+#ifndef EGLAPIENTRY
+#define EGLAPIENTRY KHRONOS_APIENTRY
+#endif
+#define EGLAPIENTRYP EGLAPIENTRY*
+
+/* The types NativeDisplayType, NativeWindowType, and NativePixmapType
+ * are aliases of window-system-dependent types, such as X Display * or
+ * Windows Device Context. They must be defined in platform-specific
+ * code below. The EGL-prefixed versions of Native*Type are the same
+ * types, renamed in EGL 1.3 so all types in the API start with "EGL".
+ *
+ * Khronos STRONGLY RECOMMENDS that you use the default definitions
+ * provided below, since these changes affect both binary and source
+ * portability of applications using EGL running on different EGL
+ * implementations.
+ */
+
+#if defined(EGL_NO_PLATFORM_SPECIFIC_TYPES)
+
+typedef void *EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(_WIN32) || defined(__VC32__) && !defined(__CYGWIN__) && !defined(__SCITECH_SNAP__) /* Win32 and WinCE */
+#ifndef WIN32_LEAN_AND_MEAN
+#define WIN32_LEAN_AND_MEAN 1
+#endif
+#include <windows.h>
+
+typedef HDC EGLNativeDisplayType;
+typedef HBITMAP EGLNativePixmapType;
+typedef HWND EGLNativeWindowType;
+
+#elif defined(__EMSCRIPTEN__)
+
+typedef int EGLNativeDisplayType;
+typedef int EGLNativePixmapType;
+typedef int EGLNativeWindowType;
+
+#elif defined(__WINSCW__) || defined(__SYMBIAN32__) /* Symbian */
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(WL_EGL_PLATFORM)
+
+typedef struct wl_display *EGLNativeDisplayType;
+typedef struct wl_egl_pixmap *EGLNativePixmapType;
+typedef struct wl_egl_window *EGLNativeWindowType;
+
+#elif defined(__GBM__)
+
+typedef struct gbm_device *EGLNativeDisplayType;
+typedef struct gbm_bo *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(__ANDROID__) || defined(ANDROID)
+
+struct ANativeWindow;
+struct egl_native_pixmap_t;
+
+typedef void* EGLNativeDisplayType;
+typedef struct egl_native_pixmap_t* EGLNativePixmapType;
+typedef struct ANativeWindow* EGLNativeWindowType;
+
+#elif defined(USE_OZONE)
+
+typedef intptr_t EGLNativeDisplayType;
+typedef intptr_t EGLNativePixmapType;
+typedef intptr_t EGLNativeWindowType;
+
+#elif defined(USE_X11)
+
+/* X11 (tentative) */
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+
+typedef Display *EGLNativeDisplayType;
+typedef Pixmap EGLNativePixmapType;
+typedef Window EGLNativeWindowType;
+
+#elif defined(__unix__)
+
+typedef void *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
+#elif defined(__APPLE__)
+
+typedef int EGLNativeDisplayType;
+typedef void *EGLNativePixmapType;
+typedef void *EGLNativeWindowType;
+
+#elif defined(__HAIKU__)
+
+#include <kernel/image.h>
+
+typedef void *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
+#elif defined(__Fuchsia__)
+
+typedef void *EGLNativeDisplayType;
+typedef khronos_uintptr_t EGLNativePixmapType;
+typedef khronos_uintptr_t EGLNativeWindowType;
+
+#else
+#error "Platform not recognized"
+#endif
+
+/* EGL 1.2 types, renamed for consistency in EGL 1.3 */
+typedef EGLNativeDisplayType NativeDisplayType;
+typedef EGLNativePixmapType NativePixmapType;
+typedef EGLNativeWindowType NativeWindowType;
+
+
+/* Define EGLint. This must be a signed integral type large enough to contain
+ * all legal attribute names and values passed into and out of EGL, whether
+ * their type is boolean, bitmask, enumerant (symbolic constant), integer,
+ * handle, or other. While in general a 32-bit integer will suffice, if
+ * handles are 64 bit types, then EGLint should be defined as a signed 64-bit
+ * integer type.
+ */
+typedef khronos_int32_t EGLint;
+
+
+/* C++ / C typecast macros for special EGL handle values */
+#if defined(__cplusplus)
+#define EGL_CAST(type, value) (static_cast<type>(value))
+#else
+#define EGL_CAST(type, value) ((type) (value))
+#endif
+
+#endif /* __eglplatform_h */
diff --git a/thirdparty/glad/egl.c b/thirdparty/glad/egl.c
new file mode 100644
index 0000000000..e120ea6b2c
--- /dev/null
+++ b/thirdparty/glad/egl.c
@@ -0,0 +1,408 @@
+/**
+ * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <glad/egl.h>
+
+#ifndef GLAD_IMPL_UTIL_C_
+#define GLAD_IMPL_UTIL_C_
+
+#ifdef _MSC_VER
+#define GLAD_IMPL_UTIL_SSCANF sscanf_s
+#else
+#define GLAD_IMPL_UTIL_SSCANF sscanf
+#endif
+
+#endif /* GLAD_IMPL_UTIL_C_ */
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+
+
+int GLAD_EGL_VERSION_1_0 = 0;
+int GLAD_EGL_VERSION_1_1 = 0;
+int GLAD_EGL_VERSION_1_2 = 0;
+int GLAD_EGL_VERSION_1_3 = 0;
+int GLAD_EGL_VERSION_1_4 = 0;
+int GLAD_EGL_VERSION_1_5 = 0;
+int GLAD_EGL_ANDROID_blob_cache = 0;
+int GLAD_EGL_KHR_platform_wayland = 0;
+int GLAD_EGL_KHR_platform_x11 = 0;
+
+
+
+PFNEGLBINDAPIPROC glad_eglBindAPI = NULL;
+PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage = NULL;
+PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig = NULL;
+PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync = NULL;
+PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers = NULL;
+PFNEGLCREATECONTEXTPROC glad_eglCreateContext = NULL;
+PFNEGLCREATEIMAGEPROC glad_eglCreateImage = NULL;
+PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer = NULL;
+PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface = NULL;
+PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface = NULL;
+PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface = NULL;
+PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface = NULL;
+PFNEGLCREATESYNCPROC glad_eglCreateSync = NULL;
+PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface = NULL;
+PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext = NULL;
+PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage = NULL;
+PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface = NULL;
+PFNEGLDESTROYSYNCPROC glad_eglDestroySync = NULL;
+PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib = NULL;
+PFNEGLGETCONFIGSPROC glad_eglGetConfigs = NULL;
+PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext = NULL;
+PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay = NULL;
+PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface = NULL;
+PFNEGLGETDISPLAYPROC glad_eglGetDisplay = NULL;
+PFNEGLGETERRORPROC glad_eglGetError = NULL;
+PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay = NULL;
+PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress = NULL;
+PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib = NULL;
+PFNEGLINITIALIZEPROC glad_eglInitialize = NULL;
+PFNEGLMAKECURRENTPROC glad_eglMakeCurrent = NULL;
+PFNEGLQUERYAPIPROC glad_eglQueryAPI = NULL;
+PFNEGLQUERYCONTEXTPROC glad_eglQueryContext = NULL;
+PFNEGLQUERYSTRINGPROC glad_eglQueryString = NULL;
+PFNEGLQUERYSURFACEPROC glad_eglQuerySurface = NULL;
+PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage = NULL;
+PFNEGLRELEASETHREADPROC glad_eglReleaseThread = NULL;
+PFNEGLSETBLOBCACHEFUNCSANDROIDPROC glad_eglSetBlobCacheFuncsANDROID = NULL;
+PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib = NULL;
+PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers = NULL;
+PFNEGLSWAPINTERVALPROC glad_eglSwapInterval = NULL;
+PFNEGLTERMINATEPROC glad_eglTerminate = NULL;
+PFNEGLWAITCLIENTPROC glad_eglWaitClient = NULL;
+PFNEGLWAITGLPROC glad_eglWaitGL = NULL;
+PFNEGLWAITNATIVEPROC glad_eglWaitNative = NULL;
+PFNEGLWAITSYNCPROC glad_eglWaitSync = NULL;
+
+
+static void glad_egl_load_EGL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_EGL_VERSION_1_0) return;
+ glad_eglChooseConfig = (PFNEGLCHOOSECONFIGPROC) load(userptr, "eglChooseConfig");
+ glad_eglCopyBuffers = (PFNEGLCOPYBUFFERSPROC) load(userptr, "eglCopyBuffers");
+ glad_eglCreateContext = (PFNEGLCREATECONTEXTPROC) load(userptr, "eglCreateContext");
+ glad_eglCreatePbufferSurface = (PFNEGLCREATEPBUFFERSURFACEPROC) load(userptr, "eglCreatePbufferSurface");
+ glad_eglCreatePixmapSurface = (PFNEGLCREATEPIXMAPSURFACEPROC) load(userptr, "eglCreatePixmapSurface");
+ glad_eglCreateWindowSurface = (PFNEGLCREATEWINDOWSURFACEPROC) load(userptr, "eglCreateWindowSurface");
+ glad_eglDestroyContext = (PFNEGLDESTROYCONTEXTPROC) load(userptr, "eglDestroyContext");
+ glad_eglDestroySurface = (PFNEGLDESTROYSURFACEPROC) load(userptr, "eglDestroySurface");
+ glad_eglGetConfigAttrib = (PFNEGLGETCONFIGATTRIBPROC) load(userptr, "eglGetConfigAttrib");
+ glad_eglGetConfigs = (PFNEGLGETCONFIGSPROC) load(userptr, "eglGetConfigs");
+ glad_eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, "eglGetCurrentDisplay");
+ glad_eglGetCurrentSurface = (PFNEGLGETCURRENTSURFACEPROC) load(userptr, "eglGetCurrentSurface");
+ glad_eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, "eglGetDisplay");
+ glad_eglGetError = (PFNEGLGETERRORPROC) load(userptr, "eglGetError");
+ glad_eglGetProcAddress = (PFNEGLGETPROCADDRESSPROC) load(userptr, "eglGetProcAddress");
+ glad_eglInitialize = (PFNEGLINITIALIZEPROC) load(userptr, "eglInitialize");
+ glad_eglMakeCurrent = (PFNEGLMAKECURRENTPROC) load(userptr, "eglMakeCurrent");
+ glad_eglQueryContext = (PFNEGLQUERYCONTEXTPROC) load(userptr, "eglQueryContext");
+ glad_eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, "eglQueryString");
+ glad_eglQuerySurface = (PFNEGLQUERYSURFACEPROC) load(userptr, "eglQuerySurface");
+ glad_eglSwapBuffers = (PFNEGLSWAPBUFFERSPROC) load(userptr, "eglSwapBuffers");
+ glad_eglTerminate = (PFNEGLTERMINATEPROC) load(userptr, "eglTerminate");
+ glad_eglWaitGL = (PFNEGLWAITGLPROC) load(userptr, "eglWaitGL");
+ glad_eglWaitNative = (PFNEGLWAITNATIVEPROC) load(userptr, "eglWaitNative");
+}
+static void glad_egl_load_EGL_VERSION_1_1( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_EGL_VERSION_1_1) return;
+ glad_eglBindTexImage = (PFNEGLBINDTEXIMAGEPROC) load(userptr, "eglBindTexImage");
+ glad_eglReleaseTexImage = (PFNEGLRELEASETEXIMAGEPROC) load(userptr, "eglReleaseTexImage");
+ glad_eglSurfaceAttrib = (PFNEGLSURFACEATTRIBPROC) load(userptr, "eglSurfaceAttrib");
+ glad_eglSwapInterval = (PFNEGLSWAPINTERVALPROC) load(userptr, "eglSwapInterval");
+}
+static void glad_egl_load_EGL_VERSION_1_2( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_EGL_VERSION_1_2) return;
+ glad_eglBindAPI = (PFNEGLBINDAPIPROC) load(userptr, "eglBindAPI");
+ glad_eglCreatePbufferFromClientBuffer = (PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC) load(userptr, "eglCreatePbufferFromClientBuffer");
+ glad_eglQueryAPI = (PFNEGLQUERYAPIPROC) load(userptr, "eglQueryAPI");
+ glad_eglReleaseThread = (PFNEGLRELEASETHREADPROC) load(userptr, "eglReleaseThread");
+ glad_eglWaitClient = (PFNEGLWAITCLIENTPROC) load(userptr, "eglWaitClient");
+}
+static void glad_egl_load_EGL_VERSION_1_4( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_EGL_VERSION_1_4) return;
+ glad_eglGetCurrentContext = (PFNEGLGETCURRENTCONTEXTPROC) load(userptr, "eglGetCurrentContext");
+}
+static void glad_egl_load_EGL_VERSION_1_5( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_EGL_VERSION_1_5) return;
+ glad_eglClientWaitSync = (PFNEGLCLIENTWAITSYNCPROC) load(userptr, "eglClientWaitSync");
+ glad_eglCreateImage = (PFNEGLCREATEIMAGEPROC) load(userptr, "eglCreateImage");
+ glad_eglCreatePlatformPixmapSurface = (PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC) load(userptr, "eglCreatePlatformPixmapSurface");
+ glad_eglCreatePlatformWindowSurface = (PFNEGLCREATEPLATFORMWINDOWSURFACEPROC) load(userptr, "eglCreatePlatformWindowSurface");
+ glad_eglCreateSync = (PFNEGLCREATESYNCPROC) load(userptr, "eglCreateSync");
+ glad_eglDestroyImage = (PFNEGLDESTROYIMAGEPROC) load(userptr, "eglDestroyImage");
+ glad_eglDestroySync = (PFNEGLDESTROYSYNCPROC) load(userptr, "eglDestroySync");
+ glad_eglGetPlatformDisplay = (PFNEGLGETPLATFORMDISPLAYPROC) load(userptr, "eglGetPlatformDisplay");
+ glad_eglGetSyncAttrib = (PFNEGLGETSYNCATTRIBPROC) load(userptr, "eglGetSyncAttrib");
+ glad_eglWaitSync = (PFNEGLWAITSYNCPROC) load(userptr, "eglWaitSync");
+}
+static void glad_egl_load_EGL_ANDROID_blob_cache( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_EGL_ANDROID_blob_cache) return;
+ glad_eglSetBlobCacheFuncsANDROID = (PFNEGLSETBLOBCACHEFUNCSANDROIDPROC) load(userptr, "eglSetBlobCacheFuncsANDROID");
+}
+
+
+
+static int glad_egl_get_extensions(EGLDisplay display, const char **extensions) {
+ *extensions = eglQueryString(display, EGL_EXTENSIONS);
+
+ return extensions != NULL;
+}
+
+static int glad_egl_has_extension(const char *extensions, const char *ext) {
+ const char *loc;
+ const char *terminator;
+ if(extensions == NULL) {
+ return 0;
+ }
+ while(1) {
+ loc = strstr(extensions, ext);
+ if(loc == NULL) {
+ return 0;
+ }
+ terminator = loc + strlen(ext);
+ if((loc == extensions || *(loc - 1) == ' ') &&
+ (*terminator == ' ' || *terminator == '\0')) {
+ return 1;
+ }
+ extensions = terminator;
+ }
+}
+
+static GLADapiproc glad_egl_get_proc_from_userptr(void *userptr, const char *name) {
+ return (GLAD_GNUC_EXTENSION (GLADapiproc (*)(const char *name)) userptr)(name);
+}
+
+static int glad_egl_find_extensions_egl(EGLDisplay display) {
+ const char *extensions;
+ if (!glad_egl_get_extensions(display, &extensions)) return 0;
+
+ GLAD_EGL_ANDROID_blob_cache = glad_egl_has_extension(extensions, "EGL_ANDROID_blob_cache");
+ GLAD_EGL_KHR_platform_wayland = glad_egl_has_extension(extensions, "EGL_KHR_platform_wayland");
+ GLAD_EGL_KHR_platform_x11 = glad_egl_has_extension(extensions, "EGL_KHR_platform_x11");
+
+ return 1;
+}
+
+static int glad_egl_find_core_egl(EGLDisplay display) {
+ int major, minor;
+ const char *version;
+
+ if (display == NULL) {
+ display = EGL_NO_DISPLAY; /* this is usually NULL, better safe than sorry */
+ }
+ if (display == EGL_NO_DISPLAY) {
+ display = eglGetCurrentDisplay();
+ }
+#ifdef EGL_VERSION_1_4
+ if (display == EGL_NO_DISPLAY) {
+ display = eglGetDisplay(EGL_DEFAULT_DISPLAY);
+ }
+#endif
+#ifndef EGL_VERSION_1_5
+ if (display == EGL_NO_DISPLAY) {
+ return 0;
+ }
+#endif
+
+ version = eglQueryString(display, EGL_VERSION);
+ (void) eglGetError();
+
+ if (version == NULL) {
+ major = 1;
+ minor = 0;
+ } else {
+ GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor);
+ }
+
+ GLAD_EGL_VERSION_1_0 = (major == 1 && minor >= 0) || major > 1;
+ GLAD_EGL_VERSION_1_1 = (major == 1 && minor >= 1) || major > 1;
+ GLAD_EGL_VERSION_1_2 = (major == 1 && minor >= 2) || major > 1;
+ GLAD_EGL_VERSION_1_3 = (major == 1 && minor >= 3) || major > 1;
+ GLAD_EGL_VERSION_1_4 = (major == 1 && minor >= 4) || major > 1;
+ GLAD_EGL_VERSION_1_5 = (major == 1 && minor >= 5) || major > 1;
+
+ return GLAD_MAKE_VERSION(major, minor);
+}
+
+int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void* userptr) {
+ int version;
+ eglGetDisplay = (PFNEGLGETDISPLAYPROC) load(userptr, "eglGetDisplay");
+ eglGetCurrentDisplay = (PFNEGLGETCURRENTDISPLAYPROC) load(userptr, "eglGetCurrentDisplay");
+ eglQueryString = (PFNEGLQUERYSTRINGPROC) load(userptr, "eglQueryString");
+ eglGetError = (PFNEGLGETERRORPROC) load(userptr, "eglGetError");
+ if (eglGetDisplay == NULL || eglGetCurrentDisplay == NULL || eglQueryString == NULL || eglGetError == NULL) return 0;
+
+ version = glad_egl_find_core_egl(display);
+ if (!version) return 0;
+ glad_egl_load_EGL_VERSION_1_0(load, userptr);
+ glad_egl_load_EGL_VERSION_1_1(load, userptr);
+ glad_egl_load_EGL_VERSION_1_2(load, userptr);
+ glad_egl_load_EGL_VERSION_1_4(load, userptr);
+ glad_egl_load_EGL_VERSION_1_5(load, userptr);
+
+ if (!glad_egl_find_extensions_egl(display)) return 0;
+ glad_egl_load_EGL_ANDROID_blob_cache(load, userptr);
+
+
+ return version;
+}
+
+int gladLoadEGL(EGLDisplay display, GLADloadfunc load) {
+ return gladLoadEGLUserPtr(display, glad_egl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
+}
+
+
+
+#ifdef GLAD_EGL
+
+#ifndef GLAD_LOADER_LIBRARY_C_
+#define GLAD_LOADER_LIBRARY_C_
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#if GLAD_PLATFORM_WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+
+static void* glad_get_dlopen_handle(const char *lib_names[], int length) {
+ void *handle = NULL;
+ int i;
+
+ for (i = 0; i < length; ++i) {
+#if GLAD_PLATFORM_WIN32
+ #if GLAD_PLATFORM_UWP
+ size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR);
+ LPWSTR buffer = (LPWSTR) malloc(buffer_size);
+ if (buffer != NULL) {
+ int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size);
+ if (ret != 0) {
+ handle = (void*) LoadPackagedLibrary(buffer, 0);
+ }
+ free((void*) buffer);
+ }
+ #else
+ handle = (void*) LoadLibraryA(lib_names[i]);
+ #endif
+#else
+ handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL);
+#endif
+ if (handle != NULL) {
+ return handle;
+ }
+ }
+
+ return NULL;
+}
+
+static void glad_close_dlopen_handle(void* handle) {
+ if (handle != NULL) {
+#if GLAD_PLATFORM_WIN32
+ FreeLibrary((HMODULE) handle);
+#else
+ dlclose(handle);
+#endif
+ }
+}
+
+static GLADapiproc glad_dlsym_handle(void* handle, const char *name) {
+ if (handle == NULL) {
+ return NULL;
+ }
+
+#if GLAD_PLATFORM_WIN32
+ return (GLADapiproc) GetProcAddress((HMODULE) handle, name);
+#else
+ return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name);
+#endif
+}
+
+#endif /* GLAD_LOADER_LIBRARY_C_ */
+
+struct _glad_egl_userptr {
+ void *handle;
+ PFNEGLGETPROCADDRESSPROC get_proc_address_ptr;
+};
+
+static GLADapiproc glad_egl_get_proc(void *vuserptr, const char* name) {
+ struct _glad_egl_userptr userptr = *(struct _glad_egl_userptr*) vuserptr;
+ GLADapiproc result = NULL;
+
+ result = glad_dlsym_handle(userptr.handle, name);
+ if (result == NULL) {
+ result = GLAD_GNUC_EXTENSION (GLADapiproc) userptr.get_proc_address_ptr(name);
+ }
+
+ return result;
+}
+
+static void* _egl_handle = NULL;
+
+static void* glad_egl_dlopen_handle(void) {
+#if GLAD_PLATFORM_APPLE
+ static const char *NAMES[] = {"libEGL.dylib"};
+#elif GLAD_PLATFORM_WIN32
+ static const char *NAMES[] = {"libEGL.dll", "EGL.dll"};
+#else
+ static const char *NAMES[] = {"libEGL.so.1", "libEGL.so"};
+#endif
+
+ if (_egl_handle == NULL) {
+ _egl_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
+ }
+
+ return _egl_handle;
+}
+
+static struct _glad_egl_userptr glad_egl_build_userptr(void *handle) {
+ struct _glad_egl_userptr userptr;
+ userptr.handle = handle;
+ userptr.get_proc_address_ptr = (PFNEGLGETPROCADDRESSPROC) glad_dlsym_handle(handle, "eglGetProcAddress");
+ return userptr;
+}
+
+int gladLoaderLoadEGL(EGLDisplay display) {
+ int version = 0;
+ void *handle = NULL;
+ int did_load = 0;
+ struct _glad_egl_userptr userptr;
+
+ did_load = _egl_handle == NULL;
+ handle = glad_egl_dlopen_handle();
+ if (handle != NULL) {
+ userptr = glad_egl_build_userptr(handle);
+
+ if (userptr.get_proc_address_ptr != NULL) {
+ version = gladLoadEGLUserPtr(display, glad_egl_get_proc, &userptr);
+ }
+
+ if (!version && did_load) {
+ gladLoaderUnloadEGL();
+ }
+ }
+
+ return version;
+}
+
+
+void gladLoaderUnloadEGL() {
+ if (_egl_handle != NULL) {
+ glad_close_dlopen_handle(_egl_handle);
+ _egl_handle = NULL;
+ }
+}
+
+#endif /* GLAD_EGL */
+
+#ifdef __cplusplus
+}
+#endif
diff --git a/thirdparty/glad/gl.c b/thirdparty/glad/gl.c
index 8d12541ed4..ee0cc188fc 100644
--- a/thirdparty/glad/gl.c
+++ b/thirdparty/glad/gl.c
@@ -35,6 +35,10 @@ int GLAD_GL_VERSION_3_0 = 0;
int GLAD_GL_VERSION_3_1 = 0;
int GLAD_GL_VERSION_3_2 = 0;
int GLAD_GL_VERSION_3_3 = 0;
+int GLAD_GL_ES_VERSION_2_0 = 0;
+int GLAD_GL_ES_VERSION_3_0 = 0;
+int GLAD_GL_ES_VERSION_3_1 = 0;
+int GLAD_GL_ES_VERSION_3_2 = 0;
int GLAD_GL_ARB_debug_output = 0;
int GLAD_GL_ARB_framebuffer_object = 0;
int GLAD_GL_ARB_get_program_binary = 0;
@@ -797,6 +801,111 @@ PFNGLWINDOWPOS3IPROC glad_glWindowPos3i = NULL;
PFNGLWINDOWPOS3IVPROC glad_glWindowPos3iv = NULL;
PFNGLWINDOWPOS3SPROC glad_glWindowPos3s = NULL;
PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv = NULL;
+PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram = NULL;
+PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture = NULL;
+PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline = NULL;
+PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback = NULL;
+PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer = NULL;
+PFNGLBLENDBARRIERPROC glad_glBlendBarrier = NULL;
+PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei = NULL;
+PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi = NULL;
+PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei = NULL;
+PFNGLBLENDFUNCIPROC glad_glBlendFunci = NULL;
+PFNGLCLEARDEPTHFPROC glad_glClearDepthf = NULL;
+PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData = NULL;
+PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv = NULL;
+PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback = NULL;
+PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl = NULL;
+PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert = NULL;
+PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines = NULL;
+PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks = NULL;
+PFNGLDEPTHRANGEFPROC glad_glDepthRangef = NULL;
+PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute = NULL;
+PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect = NULL;
+PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect = NULL;
+PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect = NULL;
+PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri = NULL;
+PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines = NULL;
+PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks = NULL;
+PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog = NULL;
+PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv = NULL;
+PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus = NULL;
+PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ = NULL;
+PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel = NULL;
+PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel = NULL;
+PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv = NULL;
+PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog = NULL;
+PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv = NULL;
+PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex = NULL;
+PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation = NULL;
+PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName = NULL;
+PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv = NULL;
+PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat = NULL;
+PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv = NULL;
+PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv = NULL;
+PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv = NULL;
+PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer = NULL;
+PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer = NULL;
+PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline = NULL;
+PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback = NULL;
+PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier = NULL;
+PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion = NULL;
+PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading = NULL;
+PFNGLOBJECTLABELPROC glad_glObjectLabel = NULL;
+PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel = NULL;
+PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri = NULL;
+PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback = NULL;
+PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup = NULL;
+PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox = NULL;
+PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f = NULL;
+PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv = NULL;
+PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i = NULL;
+PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv = NULL;
+PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui = NULL;
+PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv = NULL;
+PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f = NULL;
+PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv = NULL;
+PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i = NULL;
+PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv = NULL;
+PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui = NULL;
+PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv = NULL;
+PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f = NULL;
+PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv = NULL;
+PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i = NULL;
+PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv = NULL;
+PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui = NULL;
+PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv = NULL;
+PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f = NULL;
+PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv = NULL;
+PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i = NULL;
+PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv = NULL;
+PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui = NULL;
+PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv = NULL;
+PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv = NULL;
+PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup = NULL;
+PFNGLREADNPIXELSPROC glad_glReadnPixels = NULL;
+PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler = NULL;
+PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback = NULL;
+PFNGLSHADERBINARYPROC glad_glShaderBinary = NULL;
+PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange = NULL;
+PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D = NULL;
+PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample = NULL;
+PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D = NULL;
+PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample = NULL;
+PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages = NULL;
+PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline = NULL;
+PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding = NULL;
+PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat = NULL;
+PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat = NULL;
+PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor = NULL;
static void glad_gl_load_GL_VERSION_1_0( GLADuserptrloadfunc load, void* userptr) {
@@ -1562,6 +1671,376 @@ static void glad_gl_load_GL_VERSION_3_3( GLADuserptrloadfunc load, void* userptr
glad_glVertexP4ui = (PFNGLVERTEXP4UIPROC) load(userptr, "glVertexP4ui");
glad_glVertexP4uiv = (PFNGLVERTEXP4UIVPROC) load(userptr, "glVertexP4uiv");
}
+static void glad_gl_load_GL_ES_VERSION_2_0( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_GL_ES_VERSION_2_0) return;
+ glad_glActiveTexture = (PFNGLACTIVETEXTUREPROC) load(userptr, "glActiveTexture");
+ glad_glAttachShader = (PFNGLATTACHSHADERPROC) load(userptr, "glAttachShader");
+ glad_glBindAttribLocation = (PFNGLBINDATTRIBLOCATIONPROC) load(userptr, "glBindAttribLocation");
+ glad_glBindBuffer = (PFNGLBINDBUFFERPROC) load(userptr, "glBindBuffer");
+ glad_glBindFramebuffer = (PFNGLBINDFRAMEBUFFERPROC) load(userptr, "glBindFramebuffer");
+ glad_glBindRenderbuffer = (PFNGLBINDRENDERBUFFERPROC) load(userptr, "glBindRenderbuffer");
+ glad_glBindTexture = (PFNGLBINDTEXTUREPROC) load(userptr, "glBindTexture");
+ glad_glBlendColor = (PFNGLBLENDCOLORPROC) load(userptr, "glBlendColor");
+ glad_glBlendEquation = (PFNGLBLENDEQUATIONPROC) load(userptr, "glBlendEquation");
+ glad_glBlendEquationSeparate = (PFNGLBLENDEQUATIONSEPARATEPROC) load(userptr, "glBlendEquationSeparate");
+ glad_glBlendFunc = (PFNGLBLENDFUNCPROC) load(userptr, "glBlendFunc");
+ glad_glBlendFuncSeparate = (PFNGLBLENDFUNCSEPARATEPROC) load(userptr, "glBlendFuncSeparate");
+ glad_glBufferData = (PFNGLBUFFERDATAPROC) load(userptr, "glBufferData");
+ glad_glBufferSubData = (PFNGLBUFFERSUBDATAPROC) load(userptr, "glBufferSubData");
+ glad_glCheckFramebufferStatus = (PFNGLCHECKFRAMEBUFFERSTATUSPROC) load(userptr, "glCheckFramebufferStatus");
+ glad_glClear = (PFNGLCLEARPROC) load(userptr, "glClear");
+ glad_glClearColor = (PFNGLCLEARCOLORPROC) load(userptr, "glClearColor");
+ glad_glClearDepthf = (PFNGLCLEARDEPTHFPROC) load(userptr, "glClearDepthf");
+ glad_glClearStencil = (PFNGLCLEARSTENCILPROC) load(userptr, "glClearStencil");
+ glad_glColorMask = (PFNGLCOLORMASKPROC) load(userptr, "glColorMask");
+ glad_glCompileShader = (PFNGLCOMPILESHADERPROC) load(userptr, "glCompileShader");
+ glad_glCompressedTexImage2D = (PFNGLCOMPRESSEDTEXIMAGE2DPROC) load(userptr, "glCompressedTexImage2D");
+ glad_glCompressedTexSubImage2D = (PFNGLCOMPRESSEDTEXSUBIMAGE2DPROC) load(userptr, "glCompressedTexSubImage2D");
+ glad_glCopyTexImage2D = (PFNGLCOPYTEXIMAGE2DPROC) load(userptr, "glCopyTexImage2D");
+ glad_glCopyTexSubImage2D = (PFNGLCOPYTEXSUBIMAGE2DPROC) load(userptr, "glCopyTexSubImage2D");
+ glad_glCreateProgram = (PFNGLCREATEPROGRAMPROC) load(userptr, "glCreateProgram");
+ glad_glCreateShader = (PFNGLCREATESHADERPROC) load(userptr, "glCreateShader");
+ glad_glCullFace = (PFNGLCULLFACEPROC) load(userptr, "glCullFace");
+ glad_glDeleteBuffers = (PFNGLDELETEBUFFERSPROC) load(userptr, "glDeleteBuffers");
+ glad_glDeleteFramebuffers = (PFNGLDELETEFRAMEBUFFERSPROC) load(userptr, "glDeleteFramebuffers");
+ glad_glDeleteProgram = (PFNGLDELETEPROGRAMPROC) load(userptr, "glDeleteProgram");
+ glad_glDeleteRenderbuffers = (PFNGLDELETERENDERBUFFERSPROC) load(userptr, "glDeleteRenderbuffers");
+ glad_glDeleteShader = (PFNGLDELETESHADERPROC) load(userptr, "glDeleteShader");
+ glad_glDeleteTextures = (PFNGLDELETETEXTURESPROC) load(userptr, "glDeleteTextures");
+ glad_glDepthFunc = (PFNGLDEPTHFUNCPROC) load(userptr, "glDepthFunc");
+ glad_glDepthMask = (PFNGLDEPTHMASKPROC) load(userptr, "glDepthMask");
+ glad_glDepthRangef = (PFNGLDEPTHRANGEFPROC) load(userptr, "glDepthRangef");
+ glad_glDetachShader = (PFNGLDETACHSHADERPROC) load(userptr, "glDetachShader");
+ glad_glDisable = (PFNGLDISABLEPROC) load(userptr, "glDisable");
+ glad_glDisableVertexAttribArray = (PFNGLDISABLEVERTEXATTRIBARRAYPROC) load(userptr, "glDisableVertexAttribArray");
+ glad_glDrawArrays = (PFNGLDRAWARRAYSPROC) load(userptr, "glDrawArrays");
+ glad_glDrawElements = (PFNGLDRAWELEMENTSPROC) load(userptr, "glDrawElements");
+ glad_glEnable = (PFNGLENABLEPROC) load(userptr, "glEnable");
+ glad_glEnableVertexAttribArray = (PFNGLENABLEVERTEXATTRIBARRAYPROC) load(userptr, "glEnableVertexAttribArray");
+ glad_glFinish = (PFNGLFINISHPROC) load(userptr, "glFinish");
+ glad_glFlush = (PFNGLFLUSHPROC) load(userptr, "glFlush");
+ glad_glFramebufferRenderbuffer = (PFNGLFRAMEBUFFERRENDERBUFFERPROC) load(userptr, "glFramebufferRenderbuffer");
+ glad_glFramebufferTexture2D = (PFNGLFRAMEBUFFERTEXTURE2DPROC) load(userptr, "glFramebufferTexture2D");
+ glad_glFrontFace = (PFNGLFRONTFACEPROC) load(userptr, "glFrontFace");
+ glad_glGenBuffers = (PFNGLGENBUFFERSPROC) load(userptr, "glGenBuffers");
+ glad_glGenFramebuffers = (PFNGLGENFRAMEBUFFERSPROC) load(userptr, "glGenFramebuffers");
+ glad_glGenRenderbuffers = (PFNGLGENRENDERBUFFERSPROC) load(userptr, "glGenRenderbuffers");
+ glad_glGenTextures = (PFNGLGENTEXTURESPROC) load(userptr, "glGenTextures");
+ glad_glGenerateMipmap = (PFNGLGENERATEMIPMAPPROC) load(userptr, "glGenerateMipmap");
+ glad_glGetActiveAttrib = (PFNGLGETACTIVEATTRIBPROC) load(userptr, "glGetActiveAttrib");
+ glad_glGetActiveUniform = (PFNGLGETACTIVEUNIFORMPROC) load(userptr, "glGetActiveUniform");
+ glad_glGetAttachedShaders = (PFNGLGETATTACHEDSHADERSPROC) load(userptr, "glGetAttachedShaders");
+ glad_glGetAttribLocation = (PFNGLGETATTRIBLOCATIONPROC) load(userptr, "glGetAttribLocation");
+ glad_glGetBooleanv = (PFNGLGETBOOLEANVPROC) load(userptr, "glGetBooleanv");
+ glad_glGetBufferParameteriv = (PFNGLGETBUFFERPARAMETERIVPROC) load(userptr, "glGetBufferParameteriv");
+ glad_glGetError = (PFNGLGETERRORPROC) load(userptr, "glGetError");
+ glad_glGetFloatv = (PFNGLGETFLOATVPROC) load(userptr, "glGetFloatv");
+ glad_glGetFramebufferAttachmentParameteriv = (PFNGLGETFRAMEBUFFERATTACHMENTPARAMETERIVPROC) load(userptr, "glGetFramebufferAttachmentParameteriv");
+ glad_glGetIntegerv = (PFNGLGETINTEGERVPROC) load(userptr, "glGetIntegerv");
+ glad_glGetProgramInfoLog = (PFNGLGETPROGRAMINFOLOGPROC) load(userptr, "glGetProgramInfoLog");
+ glad_glGetProgramiv = (PFNGLGETPROGRAMIVPROC) load(userptr, "glGetProgramiv");
+ glad_glGetRenderbufferParameteriv = (PFNGLGETRENDERBUFFERPARAMETERIVPROC) load(userptr, "glGetRenderbufferParameteriv");
+ glad_glGetShaderInfoLog = (PFNGLGETSHADERINFOLOGPROC) load(userptr, "glGetShaderInfoLog");
+ glad_glGetShaderPrecisionFormat = (PFNGLGETSHADERPRECISIONFORMATPROC) load(userptr, "glGetShaderPrecisionFormat");
+ glad_glGetShaderSource = (PFNGLGETSHADERSOURCEPROC) load(userptr, "glGetShaderSource");
+ glad_glGetShaderiv = (PFNGLGETSHADERIVPROC) load(userptr, "glGetShaderiv");
+ glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
+ glad_glGetTexParameterfv = (PFNGLGETTEXPARAMETERFVPROC) load(userptr, "glGetTexParameterfv");
+ glad_glGetTexParameteriv = (PFNGLGETTEXPARAMETERIVPROC) load(userptr, "glGetTexParameteriv");
+ glad_glGetUniformLocation = (PFNGLGETUNIFORMLOCATIONPROC) load(userptr, "glGetUniformLocation");
+ glad_glGetUniformfv = (PFNGLGETUNIFORMFVPROC) load(userptr, "glGetUniformfv");
+ glad_glGetUniformiv = (PFNGLGETUNIFORMIVPROC) load(userptr, "glGetUniformiv");
+ glad_glGetVertexAttribPointerv = (PFNGLGETVERTEXATTRIBPOINTERVPROC) load(userptr, "glGetVertexAttribPointerv");
+ glad_glGetVertexAttribfv = (PFNGLGETVERTEXATTRIBFVPROC) load(userptr, "glGetVertexAttribfv");
+ glad_glGetVertexAttribiv = (PFNGLGETVERTEXATTRIBIVPROC) load(userptr, "glGetVertexAttribiv");
+ glad_glHint = (PFNGLHINTPROC) load(userptr, "glHint");
+ glad_glIsBuffer = (PFNGLISBUFFERPROC) load(userptr, "glIsBuffer");
+ glad_glIsEnabled = (PFNGLISENABLEDPROC) load(userptr, "glIsEnabled");
+ glad_glIsFramebuffer = (PFNGLISFRAMEBUFFERPROC) load(userptr, "glIsFramebuffer");
+ glad_glIsProgram = (PFNGLISPROGRAMPROC) load(userptr, "glIsProgram");
+ glad_glIsRenderbuffer = (PFNGLISRENDERBUFFERPROC) load(userptr, "glIsRenderbuffer");
+ glad_glIsShader = (PFNGLISSHADERPROC) load(userptr, "glIsShader");
+ glad_glIsTexture = (PFNGLISTEXTUREPROC) load(userptr, "glIsTexture");
+ glad_glLineWidth = (PFNGLLINEWIDTHPROC) load(userptr, "glLineWidth");
+ glad_glLinkProgram = (PFNGLLINKPROGRAMPROC) load(userptr, "glLinkProgram");
+ glad_glPixelStorei = (PFNGLPIXELSTOREIPROC) load(userptr, "glPixelStorei");
+ glad_glPolygonOffset = (PFNGLPOLYGONOFFSETPROC) load(userptr, "glPolygonOffset");
+ glad_glReadPixels = (PFNGLREADPIXELSPROC) load(userptr, "glReadPixels");
+ glad_glReleaseShaderCompiler = (PFNGLRELEASESHADERCOMPILERPROC) load(userptr, "glReleaseShaderCompiler");
+ glad_glRenderbufferStorage = (PFNGLRENDERBUFFERSTORAGEPROC) load(userptr, "glRenderbufferStorage");
+ glad_glSampleCoverage = (PFNGLSAMPLECOVERAGEPROC) load(userptr, "glSampleCoverage");
+ glad_glScissor = (PFNGLSCISSORPROC) load(userptr, "glScissor");
+ glad_glShaderBinary = (PFNGLSHADERBINARYPROC) load(userptr, "glShaderBinary");
+ glad_glShaderSource = (PFNGLSHADERSOURCEPROC) load(userptr, "glShaderSource");
+ glad_glStencilFunc = (PFNGLSTENCILFUNCPROC) load(userptr, "glStencilFunc");
+ glad_glStencilFuncSeparate = (PFNGLSTENCILFUNCSEPARATEPROC) load(userptr, "glStencilFuncSeparate");
+ glad_glStencilMask = (PFNGLSTENCILMASKPROC) load(userptr, "glStencilMask");
+ glad_glStencilMaskSeparate = (PFNGLSTENCILMASKSEPARATEPROC) load(userptr, "glStencilMaskSeparate");
+ glad_glStencilOp = (PFNGLSTENCILOPPROC) load(userptr, "glStencilOp");
+ glad_glStencilOpSeparate = (PFNGLSTENCILOPSEPARATEPROC) load(userptr, "glStencilOpSeparate");
+ glad_glTexImage2D = (PFNGLTEXIMAGE2DPROC) load(userptr, "glTexImage2D");
+ glad_glTexParameterf = (PFNGLTEXPARAMETERFPROC) load(userptr, "glTexParameterf");
+ glad_glTexParameterfv = (PFNGLTEXPARAMETERFVPROC) load(userptr, "glTexParameterfv");
+ glad_glTexParameteri = (PFNGLTEXPARAMETERIPROC) load(userptr, "glTexParameteri");
+ glad_glTexParameteriv = (PFNGLTEXPARAMETERIVPROC) load(userptr, "glTexParameteriv");
+ glad_glTexSubImage2D = (PFNGLTEXSUBIMAGE2DPROC) load(userptr, "glTexSubImage2D");
+ glad_glUniform1f = (PFNGLUNIFORM1FPROC) load(userptr, "glUniform1f");
+ glad_glUniform1fv = (PFNGLUNIFORM1FVPROC) load(userptr, "glUniform1fv");
+ glad_glUniform1i = (PFNGLUNIFORM1IPROC) load(userptr, "glUniform1i");
+ glad_glUniform1iv = (PFNGLUNIFORM1IVPROC) load(userptr, "glUniform1iv");
+ glad_glUniform2f = (PFNGLUNIFORM2FPROC) load(userptr, "glUniform2f");
+ glad_glUniform2fv = (PFNGLUNIFORM2FVPROC) load(userptr, "glUniform2fv");
+ glad_glUniform2i = (PFNGLUNIFORM2IPROC) load(userptr, "glUniform2i");
+ glad_glUniform2iv = (PFNGLUNIFORM2IVPROC) load(userptr, "glUniform2iv");
+ glad_glUniform3f = (PFNGLUNIFORM3FPROC) load(userptr, "glUniform3f");
+ glad_glUniform3fv = (PFNGLUNIFORM3FVPROC) load(userptr, "glUniform3fv");
+ glad_glUniform3i = (PFNGLUNIFORM3IPROC) load(userptr, "glUniform3i");
+ glad_glUniform3iv = (PFNGLUNIFORM3IVPROC) load(userptr, "glUniform3iv");
+ glad_glUniform4f = (PFNGLUNIFORM4FPROC) load(userptr, "glUniform4f");
+ glad_glUniform4fv = (PFNGLUNIFORM4FVPROC) load(userptr, "glUniform4fv");
+ glad_glUniform4i = (PFNGLUNIFORM4IPROC) load(userptr, "glUniform4i");
+ glad_glUniform4iv = (PFNGLUNIFORM4IVPROC) load(userptr, "glUniform4iv");
+ glad_glUniformMatrix2fv = (PFNGLUNIFORMMATRIX2FVPROC) load(userptr, "glUniformMatrix2fv");
+ glad_glUniformMatrix3fv = (PFNGLUNIFORMMATRIX3FVPROC) load(userptr, "glUniformMatrix3fv");
+ glad_glUniformMatrix4fv = (PFNGLUNIFORMMATRIX4FVPROC) load(userptr, "glUniformMatrix4fv");
+ glad_glUseProgram = (PFNGLUSEPROGRAMPROC) load(userptr, "glUseProgram");
+ glad_glValidateProgram = (PFNGLVALIDATEPROGRAMPROC) load(userptr, "glValidateProgram");
+ glad_glVertexAttrib1f = (PFNGLVERTEXATTRIB1FPROC) load(userptr, "glVertexAttrib1f");
+ glad_glVertexAttrib1fv = (PFNGLVERTEXATTRIB1FVPROC) load(userptr, "glVertexAttrib1fv");
+ glad_glVertexAttrib2f = (PFNGLVERTEXATTRIB2FPROC) load(userptr, "glVertexAttrib2f");
+ glad_glVertexAttrib2fv = (PFNGLVERTEXATTRIB2FVPROC) load(userptr, "glVertexAttrib2fv");
+ glad_glVertexAttrib3f = (PFNGLVERTEXATTRIB3FPROC) load(userptr, "glVertexAttrib3f");
+ glad_glVertexAttrib3fv = (PFNGLVERTEXATTRIB3FVPROC) load(userptr, "glVertexAttrib3fv");
+ glad_glVertexAttrib4f = (PFNGLVERTEXATTRIB4FPROC) load(userptr, "glVertexAttrib4f");
+ glad_glVertexAttrib4fv = (PFNGLVERTEXATTRIB4FVPROC) load(userptr, "glVertexAttrib4fv");
+ glad_glVertexAttribPointer = (PFNGLVERTEXATTRIBPOINTERPROC) load(userptr, "glVertexAttribPointer");
+ glad_glViewport = (PFNGLVIEWPORTPROC) load(userptr, "glViewport");
+}
+static void glad_gl_load_GL_ES_VERSION_3_0( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_GL_ES_VERSION_3_0) return;
+ glad_glBeginQuery = (PFNGLBEGINQUERYPROC) load(userptr, "glBeginQuery");
+ glad_glBeginTransformFeedback = (PFNGLBEGINTRANSFORMFEEDBACKPROC) load(userptr, "glBeginTransformFeedback");
+ glad_glBindBufferBase = (PFNGLBINDBUFFERBASEPROC) load(userptr, "glBindBufferBase");
+ glad_glBindBufferRange = (PFNGLBINDBUFFERRANGEPROC) load(userptr, "glBindBufferRange");
+ glad_glBindSampler = (PFNGLBINDSAMPLERPROC) load(userptr, "glBindSampler");
+ glad_glBindTransformFeedback = (PFNGLBINDTRANSFORMFEEDBACKPROC) load(userptr, "glBindTransformFeedback");
+ glad_glBindVertexArray = (PFNGLBINDVERTEXARRAYPROC) load(userptr, "glBindVertexArray");
+ glad_glBlitFramebuffer = (PFNGLBLITFRAMEBUFFERPROC) load(userptr, "glBlitFramebuffer");
+ glad_glClearBufferfi = (PFNGLCLEARBUFFERFIPROC) load(userptr, "glClearBufferfi");
+ glad_glClearBufferfv = (PFNGLCLEARBUFFERFVPROC) load(userptr, "glClearBufferfv");
+ glad_glClearBufferiv = (PFNGLCLEARBUFFERIVPROC) load(userptr, "glClearBufferiv");
+ glad_glClearBufferuiv = (PFNGLCLEARBUFFERUIVPROC) load(userptr, "glClearBufferuiv");
+ glad_glClientWaitSync = (PFNGLCLIENTWAITSYNCPROC) load(userptr, "glClientWaitSync");
+ glad_glCompressedTexImage3D = (PFNGLCOMPRESSEDTEXIMAGE3DPROC) load(userptr, "glCompressedTexImage3D");
+ glad_glCompressedTexSubImage3D = (PFNGLCOMPRESSEDTEXSUBIMAGE3DPROC) load(userptr, "glCompressedTexSubImage3D");
+ glad_glCopyBufferSubData = (PFNGLCOPYBUFFERSUBDATAPROC) load(userptr, "glCopyBufferSubData");
+ glad_glCopyTexSubImage3D = (PFNGLCOPYTEXSUBIMAGE3DPROC) load(userptr, "glCopyTexSubImage3D");
+ glad_glDeleteQueries = (PFNGLDELETEQUERIESPROC) load(userptr, "glDeleteQueries");
+ glad_glDeleteSamplers = (PFNGLDELETESAMPLERSPROC) load(userptr, "glDeleteSamplers");
+ glad_glDeleteSync = (PFNGLDELETESYNCPROC) load(userptr, "glDeleteSync");
+ glad_glDeleteTransformFeedbacks = (PFNGLDELETETRANSFORMFEEDBACKSPROC) load(userptr, "glDeleteTransformFeedbacks");
+ glad_glDeleteVertexArrays = (PFNGLDELETEVERTEXARRAYSPROC) load(userptr, "glDeleteVertexArrays");
+ glad_glDrawArraysInstanced = (PFNGLDRAWARRAYSINSTANCEDPROC) load(userptr, "glDrawArraysInstanced");
+ glad_glDrawBuffers = (PFNGLDRAWBUFFERSPROC) load(userptr, "glDrawBuffers");
+ glad_glDrawElementsInstanced = (PFNGLDRAWELEMENTSINSTANCEDPROC) load(userptr, "glDrawElementsInstanced");
+ glad_glDrawRangeElements = (PFNGLDRAWRANGEELEMENTSPROC) load(userptr, "glDrawRangeElements");
+ glad_glEndQuery = (PFNGLENDQUERYPROC) load(userptr, "glEndQuery");
+ glad_glEndTransformFeedback = (PFNGLENDTRANSFORMFEEDBACKPROC) load(userptr, "glEndTransformFeedback");
+ glad_glFenceSync = (PFNGLFENCESYNCPROC) load(userptr, "glFenceSync");
+ glad_glFlushMappedBufferRange = (PFNGLFLUSHMAPPEDBUFFERRANGEPROC) load(userptr, "glFlushMappedBufferRange");
+ glad_glFramebufferTextureLayer = (PFNGLFRAMEBUFFERTEXTURELAYERPROC) load(userptr, "glFramebufferTextureLayer");
+ glad_glGenQueries = (PFNGLGENQUERIESPROC) load(userptr, "glGenQueries");
+ glad_glGenSamplers = (PFNGLGENSAMPLERSPROC) load(userptr, "glGenSamplers");
+ glad_glGenTransformFeedbacks = (PFNGLGENTRANSFORMFEEDBACKSPROC) load(userptr, "glGenTransformFeedbacks");
+ glad_glGenVertexArrays = (PFNGLGENVERTEXARRAYSPROC) load(userptr, "glGenVertexArrays");
+ glad_glGetActiveUniformBlockName = (PFNGLGETACTIVEUNIFORMBLOCKNAMEPROC) load(userptr, "glGetActiveUniformBlockName");
+ glad_glGetActiveUniformBlockiv = (PFNGLGETACTIVEUNIFORMBLOCKIVPROC) load(userptr, "glGetActiveUniformBlockiv");
+ glad_glGetActiveUniformsiv = (PFNGLGETACTIVEUNIFORMSIVPROC) load(userptr, "glGetActiveUniformsiv");
+ glad_glGetBufferParameteri64v = (PFNGLGETBUFFERPARAMETERI64VPROC) load(userptr, "glGetBufferParameteri64v");
+ glad_glGetBufferPointerv = (PFNGLGETBUFFERPOINTERVPROC) load(userptr, "glGetBufferPointerv");
+ glad_glGetFragDataLocation = (PFNGLGETFRAGDATALOCATIONPROC) load(userptr, "glGetFragDataLocation");
+ glad_glGetInteger64i_v = (PFNGLGETINTEGER64I_VPROC) load(userptr, "glGetInteger64i_v");
+ glad_glGetInteger64v = (PFNGLGETINTEGER64VPROC) load(userptr, "glGetInteger64v");
+ glad_glGetIntegeri_v = (PFNGLGETINTEGERI_VPROC) load(userptr, "glGetIntegeri_v");
+ glad_glGetInternalformativ = (PFNGLGETINTERNALFORMATIVPROC) load(userptr, "glGetInternalformativ");
+ glad_glGetProgramBinary = (PFNGLGETPROGRAMBINARYPROC) load(userptr, "glGetProgramBinary");
+ glad_glGetQueryObjectuiv = (PFNGLGETQUERYOBJECTUIVPROC) load(userptr, "glGetQueryObjectuiv");
+ glad_glGetQueryiv = (PFNGLGETQUERYIVPROC) load(userptr, "glGetQueryiv");
+ glad_glGetSamplerParameterfv = (PFNGLGETSAMPLERPARAMETERFVPROC) load(userptr, "glGetSamplerParameterfv");
+ glad_glGetSamplerParameteriv = (PFNGLGETSAMPLERPARAMETERIVPROC) load(userptr, "glGetSamplerParameteriv");
+ glad_glGetStringi = (PFNGLGETSTRINGIPROC) load(userptr, "glGetStringi");
+ glad_glGetSynciv = (PFNGLGETSYNCIVPROC) load(userptr, "glGetSynciv");
+ glad_glGetTransformFeedbackVarying = (PFNGLGETTRANSFORMFEEDBACKVARYINGPROC) load(userptr, "glGetTransformFeedbackVarying");
+ glad_glGetUniformBlockIndex = (PFNGLGETUNIFORMBLOCKINDEXPROC) load(userptr, "glGetUniformBlockIndex");
+ glad_glGetUniformIndices = (PFNGLGETUNIFORMINDICESPROC) load(userptr, "glGetUniformIndices");
+ glad_glGetUniformuiv = (PFNGLGETUNIFORMUIVPROC) load(userptr, "glGetUniformuiv");
+ glad_glGetVertexAttribIiv = (PFNGLGETVERTEXATTRIBIIVPROC) load(userptr, "glGetVertexAttribIiv");
+ glad_glGetVertexAttribIuiv = (PFNGLGETVERTEXATTRIBIUIVPROC) load(userptr, "glGetVertexAttribIuiv");
+ glad_glInvalidateFramebuffer = (PFNGLINVALIDATEFRAMEBUFFERPROC) load(userptr, "glInvalidateFramebuffer");
+ glad_glInvalidateSubFramebuffer = (PFNGLINVALIDATESUBFRAMEBUFFERPROC) load(userptr, "glInvalidateSubFramebuffer");
+ glad_glIsQuery = (PFNGLISQUERYPROC) load(userptr, "glIsQuery");
+ glad_glIsSampler = (PFNGLISSAMPLERPROC) load(userptr, "glIsSampler");
+ glad_glIsSync = (PFNGLISSYNCPROC) load(userptr, "glIsSync");
+ glad_glIsTransformFeedback = (PFNGLISTRANSFORMFEEDBACKPROC) load(userptr, "glIsTransformFeedback");
+ glad_glIsVertexArray = (PFNGLISVERTEXARRAYPROC) load(userptr, "glIsVertexArray");
+ glad_glMapBufferRange = (PFNGLMAPBUFFERRANGEPROC) load(userptr, "glMapBufferRange");
+ glad_glPauseTransformFeedback = (PFNGLPAUSETRANSFORMFEEDBACKPROC) load(userptr, "glPauseTransformFeedback");
+ glad_glProgramBinary = (PFNGLPROGRAMBINARYPROC) load(userptr, "glProgramBinary");
+ glad_glProgramParameteri = (PFNGLPROGRAMPARAMETERIPROC) load(userptr, "glProgramParameteri");
+ glad_glReadBuffer = (PFNGLREADBUFFERPROC) load(userptr, "glReadBuffer");
+ glad_glRenderbufferStorageMultisample = (PFNGLRENDERBUFFERSTORAGEMULTISAMPLEPROC) load(userptr, "glRenderbufferStorageMultisample");
+ glad_glResumeTransformFeedback = (PFNGLRESUMETRANSFORMFEEDBACKPROC) load(userptr, "glResumeTransformFeedback");
+ glad_glSamplerParameterf = (PFNGLSAMPLERPARAMETERFPROC) load(userptr, "glSamplerParameterf");
+ glad_glSamplerParameterfv = (PFNGLSAMPLERPARAMETERFVPROC) load(userptr, "glSamplerParameterfv");
+ glad_glSamplerParameteri = (PFNGLSAMPLERPARAMETERIPROC) load(userptr, "glSamplerParameteri");
+ glad_glSamplerParameteriv = (PFNGLSAMPLERPARAMETERIVPROC) load(userptr, "glSamplerParameteriv");
+ glad_glTexImage3D = (PFNGLTEXIMAGE3DPROC) load(userptr, "glTexImage3D");
+ glad_glTexStorage2D = (PFNGLTEXSTORAGE2DPROC) load(userptr, "glTexStorage2D");
+ glad_glTexStorage3D = (PFNGLTEXSTORAGE3DPROC) load(userptr, "glTexStorage3D");
+ glad_glTexSubImage3D = (PFNGLTEXSUBIMAGE3DPROC) load(userptr, "glTexSubImage3D");
+ glad_glTransformFeedbackVaryings = (PFNGLTRANSFORMFEEDBACKVARYINGSPROC) load(userptr, "glTransformFeedbackVaryings");
+ glad_glUniform1ui = (PFNGLUNIFORM1UIPROC) load(userptr, "glUniform1ui");
+ glad_glUniform1uiv = (PFNGLUNIFORM1UIVPROC) load(userptr, "glUniform1uiv");
+ glad_glUniform2ui = (PFNGLUNIFORM2UIPROC) load(userptr, "glUniform2ui");
+ glad_glUniform2uiv = (PFNGLUNIFORM2UIVPROC) load(userptr, "glUniform2uiv");
+ glad_glUniform3ui = (PFNGLUNIFORM3UIPROC) load(userptr, "glUniform3ui");
+ glad_glUniform3uiv = (PFNGLUNIFORM3UIVPROC) load(userptr, "glUniform3uiv");
+ glad_glUniform4ui = (PFNGLUNIFORM4UIPROC) load(userptr, "glUniform4ui");
+ glad_glUniform4uiv = (PFNGLUNIFORM4UIVPROC) load(userptr, "glUniform4uiv");
+ glad_glUniformBlockBinding = (PFNGLUNIFORMBLOCKBINDINGPROC) load(userptr, "glUniformBlockBinding");
+ glad_glUniformMatrix2x3fv = (PFNGLUNIFORMMATRIX2X3FVPROC) load(userptr, "glUniformMatrix2x3fv");
+ glad_glUniformMatrix2x4fv = (PFNGLUNIFORMMATRIX2X4FVPROC) load(userptr, "glUniformMatrix2x4fv");
+ glad_glUniformMatrix3x2fv = (PFNGLUNIFORMMATRIX3X2FVPROC) load(userptr, "glUniformMatrix3x2fv");
+ glad_glUniformMatrix3x4fv = (PFNGLUNIFORMMATRIX3X4FVPROC) load(userptr, "glUniformMatrix3x4fv");
+ glad_glUniformMatrix4x2fv = (PFNGLUNIFORMMATRIX4X2FVPROC) load(userptr, "glUniformMatrix4x2fv");
+ glad_glUniformMatrix4x3fv = (PFNGLUNIFORMMATRIX4X3FVPROC) load(userptr, "glUniformMatrix4x3fv");
+ glad_glUnmapBuffer = (PFNGLUNMAPBUFFERPROC) load(userptr, "glUnmapBuffer");
+ glad_glVertexAttribDivisor = (PFNGLVERTEXATTRIBDIVISORPROC) load(userptr, "glVertexAttribDivisor");
+ glad_glVertexAttribI4i = (PFNGLVERTEXATTRIBI4IPROC) load(userptr, "glVertexAttribI4i");
+ glad_glVertexAttribI4iv = (PFNGLVERTEXATTRIBI4IVPROC) load(userptr, "glVertexAttribI4iv");
+ glad_glVertexAttribI4ui = (PFNGLVERTEXATTRIBI4UIPROC) load(userptr, "glVertexAttribI4ui");
+ glad_glVertexAttribI4uiv = (PFNGLVERTEXATTRIBI4UIVPROC) load(userptr, "glVertexAttribI4uiv");
+ glad_glVertexAttribIPointer = (PFNGLVERTEXATTRIBIPOINTERPROC) load(userptr, "glVertexAttribIPointer");
+ glad_glWaitSync = (PFNGLWAITSYNCPROC) load(userptr, "glWaitSync");
+}
+static void glad_gl_load_GL_ES_VERSION_3_1( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_GL_ES_VERSION_3_1) return;
+ glad_glActiveShaderProgram = (PFNGLACTIVESHADERPROGRAMPROC) load(userptr, "glActiveShaderProgram");
+ glad_glBindImageTexture = (PFNGLBINDIMAGETEXTUREPROC) load(userptr, "glBindImageTexture");
+ glad_glBindProgramPipeline = (PFNGLBINDPROGRAMPIPELINEPROC) load(userptr, "glBindProgramPipeline");
+ glad_glBindVertexBuffer = (PFNGLBINDVERTEXBUFFERPROC) load(userptr, "glBindVertexBuffer");
+ glad_glCreateShaderProgramv = (PFNGLCREATESHADERPROGRAMVPROC) load(userptr, "glCreateShaderProgramv");
+ glad_glDeleteProgramPipelines = (PFNGLDELETEPROGRAMPIPELINESPROC) load(userptr, "glDeleteProgramPipelines");
+ glad_glDispatchCompute = (PFNGLDISPATCHCOMPUTEPROC) load(userptr, "glDispatchCompute");
+ glad_glDispatchComputeIndirect = (PFNGLDISPATCHCOMPUTEINDIRECTPROC) load(userptr, "glDispatchComputeIndirect");
+ glad_glDrawArraysIndirect = (PFNGLDRAWARRAYSINDIRECTPROC) load(userptr, "glDrawArraysIndirect");
+ glad_glDrawElementsIndirect = (PFNGLDRAWELEMENTSINDIRECTPROC) load(userptr, "glDrawElementsIndirect");
+ glad_glFramebufferParameteri = (PFNGLFRAMEBUFFERPARAMETERIPROC) load(userptr, "glFramebufferParameteri");
+ glad_glGenProgramPipelines = (PFNGLGENPROGRAMPIPELINESPROC) load(userptr, "glGenProgramPipelines");
+ glad_glGetBooleani_v = (PFNGLGETBOOLEANI_VPROC) load(userptr, "glGetBooleani_v");
+ glad_glGetFramebufferParameteriv = (PFNGLGETFRAMEBUFFERPARAMETERIVPROC) load(userptr, "glGetFramebufferParameteriv");
+ glad_glGetMultisamplefv = (PFNGLGETMULTISAMPLEFVPROC) load(userptr, "glGetMultisamplefv");
+ glad_glGetProgramInterfaceiv = (PFNGLGETPROGRAMINTERFACEIVPROC) load(userptr, "glGetProgramInterfaceiv");
+ glad_glGetProgramPipelineInfoLog = (PFNGLGETPROGRAMPIPELINEINFOLOGPROC) load(userptr, "glGetProgramPipelineInfoLog");
+ glad_glGetProgramPipelineiv = (PFNGLGETPROGRAMPIPELINEIVPROC) load(userptr, "glGetProgramPipelineiv");
+ glad_glGetProgramResourceIndex = (PFNGLGETPROGRAMRESOURCEINDEXPROC) load(userptr, "glGetProgramResourceIndex");
+ glad_glGetProgramResourceLocation = (PFNGLGETPROGRAMRESOURCELOCATIONPROC) load(userptr, "glGetProgramResourceLocation");
+ glad_glGetProgramResourceName = (PFNGLGETPROGRAMRESOURCENAMEPROC) load(userptr, "glGetProgramResourceName");
+ glad_glGetProgramResourceiv = (PFNGLGETPROGRAMRESOURCEIVPROC) load(userptr, "glGetProgramResourceiv");
+ glad_glGetTexLevelParameterfv = (PFNGLGETTEXLEVELPARAMETERFVPROC) load(userptr, "glGetTexLevelParameterfv");
+ glad_glGetTexLevelParameteriv = (PFNGLGETTEXLEVELPARAMETERIVPROC) load(userptr, "glGetTexLevelParameteriv");
+ glad_glIsProgramPipeline = (PFNGLISPROGRAMPIPELINEPROC) load(userptr, "glIsProgramPipeline");
+ glad_glMemoryBarrier = (PFNGLMEMORYBARRIERPROC) load(userptr, "glMemoryBarrier");
+ glad_glMemoryBarrierByRegion = (PFNGLMEMORYBARRIERBYREGIONPROC) load(userptr, "glMemoryBarrierByRegion");
+ glad_glProgramUniform1f = (PFNGLPROGRAMUNIFORM1FPROC) load(userptr, "glProgramUniform1f");
+ glad_glProgramUniform1fv = (PFNGLPROGRAMUNIFORM1FVPROC) load(userptr, "glProgramUniform1fv");
+ glad_glProgramUniform1i = (PFNGLPROGRAMUNIFORM1IPROC) load(userptr, "glProgramUniform1i");
+ glad_glProgramUniform1iv = (PFNGLPROGRAMUNIFORM1IVPROC) load(userptr, "glProgramUniform1iv");
+ glad_glProgramUniform1ui = (PFNGLPROGRAMUNIFORM1UIPROC) load(userptr, "glProgramUniform1ui");
+ glad_glProgramUniform1uiv = (PFNGLPROGRAMUNIFORM1UIVPROC) load(userptr, "glProgramUniform1uiv");
+ glad_glProgramUniform2f = (PFNGLPROGRAMUNIFORM2FPROC) load(userptr, "glProgramUniform2f");
+ glad_glProgramUniform2fv = (PFNGLPROGRAMUNIFORM2FVPROC) load(userptr, "glProgramUniform2fv");
+ glad_glProgramUniform2i = (PFNGLPROGRAMUNIFORM2IPROC) load(userptr, "glProgramUniform2i");
+ glad_glProgramUniform2iv = (PFNGLPROGRAMUNIFORM2IVPROC) load(userptr, "glProgramUniform2iv");
+ glad_glProgramUniform2ui = (PFNGLPROGRAMUNIFORM2UIPROC) load(userptr, "glProgramUniform2ui");
+ glad_glProgramUniform2uiv = (PFNGLPROGRAMUNIFORM2UIVPROC) load(userptr, "glProgramUniform2uiv");
+ glad_glProgramUniform3f = (PFNGLPROGRAMUNIFORM3FPROC) load(userptr, "glProgramUniform3f");
+ glad_glProgramUniform3fv = (PFNGLPROGRAMUNIFORM3FVPROC) load(userptr, "glProgramUniform3fv");
+ glad_glProgramUniform3i = (PFNGLPROGRAMUNIFORM3IPROC) load(userptr, "glProgramUniform3i");
+ glad_glProgramUniform3iv = (PFNGLPROGRAMUNIFORM3IVPROC) load(userptr, "glProgramUniform3iv");
+ glad_glProgramUniform3ui = (PFNGLPROGRAMUNIFORM3UIPROC) load(userptr, "glProgramUniform3ui");
+ glad_glProgramUniform3uiv = (PFNGLPROGRAMUNIFORM3UIVPROC) load(userptr, "glProgramUniform3uiv");
+ glad_glProgramUniform4f = (PFNGLPROGRAMUNIFORM4FPROC) load(userptr, "glProgramUniform4f");
+ glad_glProgramUniform4fv = (PFNGLPROGRAMUNIFORM4FVPROC) load(userptr, "glProgramUniform4fv");
+ glad_glProgramUniform4i = (PFNGLPROGRAMUNIFORM4IPROC) load(userptr, "glProgramUniform4i");
+ glad_glProgramUniform4iv = (PFNGLPROGRAMUNIFORM4IVPROC) load(userptr, "glProgramUniform4iv");
+ glad_glProgramUniform4ui = (PFNGLPROGRAMUNIFORM4UIPROC) load(userptr, "glProgramUniform4ui");
+ glad_glProgramUniform4uiv = (PFNGLPROGRAMUNIFORM4UIVPROC) load(userptr, "glProgramUniform4uiv");
+ glad_glProgramUniformMatrix2fv = (PFNGLPROGRAMUNIFORMMATRIX2FVPROC) load(userptr, "glProgramUniformMatrix2fv");
+ glad_glProgramUniformMatrix2x3fv = (PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC) load(userptr, "glProgramUniformMatrix2x3fv");
+ glad_glProgramUniformMatrix2x4fv = (PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC) load(userptr, "glProgramUniformMatrix2x4fv");
+ glad_glProgramUniformMatrix3fv = (PFNGLPROGRAMUNIFORMMATRIX3FVPROC) load(userptr, "glProgramUniformMatrix3fv");
+ glad_glProgramUniformMatrix3x2fv = (PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC) load(userptr, "glProgramUniformMatrix3x2fv");
+ glad_glProgramUniformMatrix3x4fv = (PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC) load(userptr, "glProgramUniformMatrix3x4fv");
+ glad_glProgramUniformMatrix4fv = (PFNGLPROGRAMUNIFORMMATRIX4FVPROC) load(userptr, "glProgramUniformMatrix4fv");
+ glad_glProgramUniformMatrix4x2fv = (PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC) load(userptr, "glProgramUniformMatrix4x2fv");
+ glad_glProgramUniformMatrix4x3fv = (PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC) load(userptr, "glProgramUniformMatrix4x3fv");
+ glad_glSampleMaski = (PFNGLSAMPLEMASKIPROC) load(userptr, "glSampleMaski");
+ glad_glTexStorage2DMultisample = (PFNGLTEXSTORAGE2DMULTISAMPLEPROC) load(userptr, "glTexStorage2DMultisample");
+ glad_glUseProgramStages = (PFNGLUSEPROGRAMSTAGESPROC) load(userptr, "glUseProgramStages");
+ glad_glValidateProgramPipeline = (PFNGLVALIDATEPROGRAMPIPELINEPROC) load(userptr, "glValidateProgramPipeline");
+ glad_glVertexAttribBinding = (PFNGLVERTEXATTRIBBINDINGPROC) load(userptr, "glVertexAttribBinding");
+ glad_glVertexAttribFormat = (PFNGLVERTEXATTRIBFORMATPROC) load(userptr, "glVertexAttribFormat");
+ glad_glVertexAttribIFormat = (PFNGLVERTEXATTRIBIFORMATPROC) load(userptr, "glVertexAttribIFormat");
+ glad_glVertexBindingDivisor = (PFNGLVERTEXBINDINGDIVISORPROC) load(userptr, "glVertexBindingDivisor");
+}
+static void glad_gl_load_GL_ES_VERSION_3_2( GLADuserptrloadfunc load, void* userptr) {
+ if(!GLAD_GL_ES_VERSION_3_2) return;
+ glad_glBlendBarrier = (PFNGLBLENDBARRIERPROC) load(userptr, "glBlendBarrier");
+ glad_glBlendEquationSeparatei = (PFNGLBLENDEQUATIONSEPARATEIPROC) load(userptr, "glBlendEquationSeparatei");
+ glad_glBlendEquationi = (PFNGLBLENDEQUATIONIPROC) load(userptr, "glBlendEquationi");
+ glad_glBlendFuncSeparatei = (PFNGLBLENDFUNCSEPARATEIPROC) load(userptr, "glBlendFuncSeparatei");
+ glad_glBlendFunci = (PFNGLBLENDFUNCIPROC) load(userptr, "glBlendFunci");
+ glad_glColorMaski = (PFNGLCOLORMASKIPROC) load(userptr, "glColorMaski");
+ glad_glCopyImageSubData = (PFNGLCOPYIMAGESUBDATAPROC) load(userptr, "glCopyImageSubData");
+ glad_glDebugMessageCallback = (PFNGLDEBUGMESSAGECALLBACKPROC) load(userptr, "glDebugMessageCallback");
+ glad_glDebugMessageControl = (PFNGLDEBUGMESSAGECONTROLPROC) load(userptr, "glDebugMessageControl");
+ glad_glDebugMessageInsert = (PFNGLDEBUGMESSAGEINSERTPROC) load(userptr, "glDebugMessageInsert");
+ glad_glDisablei = (PFNGLDISABLEIPROC) load(userptr, "glDisablei");
+ glad_glDrawElementsBaseVertex = (PFNGLDRAWELEMENTSBASEVERTEXPROC) load(userptr, "glDrawElementsBaseVertex");
+ glad_glDrawElementsInstancedBaseVertex = (PFNGLDRAWELEMENTSINSTANCEDBASEVERTEXPROC) load(userptr, "glDrawElementsInstancedBaseVertex");
+ glad_glDrawRangeElementsBaseVertex = (PFNGLDRAWRANGEELEMENTSBASEVERTEXPROC) load(userptr, "glDrawRangeElementsBaseVertex");
+ glad_glEnablei = (PFNGLENABLEIPROC) load(userptr, "glEnablei");
+ glad_glFramebufferTexture = (PFNGLFRAMEBUFFERTEXTUREPROC) load(userptr, "glFramebufferTexture");
+ glad_glGetDebugMessageLog = (PFNGLGETDEBUGMESSAGELOGPROC) load(userptr, "glGetDebugMessageLog");
+ glad_glGetGraphicsResetStatus = (PFNGLGETGRAPHICSRESETSTATUSPROC) load(userptr, "glGetGraphicsResetStatus");
+ glad_glGetObjectLabel = (PFNGLGETOBJECTLABELPROC) load(userptr, "glGetObjectLabel");
+ glad_glGetObjectPtrLabel = (PFNGLGETOBJECTPTRLABELPROC) load(userptr, "glGetObjectPtrLabel");
+ glad_glGetPointerv = (PFNGLGETPOINTERVPROC) load(userptr, "glGetPointerv");
+ glad_glGetSamplerParameterIiv = (PFNGLGETSAMPLERPARAMETERIIVPROC) load(userptr, "glGetSamplerParameterIiv");
+ glad_glGetSamplerParameterIuiv = (PFNGLGETSAMPLERPARAMETERIUIVPROC) load(userptr, "glGetSamplerParameterIuiv");
+ glad_glGetTexParameterIiv = (PFNGLGETTEXPARAMETERIIVPROC) load(userptr, "glGetTexParameterIiv");
+ glad_glGetTexParameterIuiv = (PFNGLGETTEXPARAMETERIUIVPROC) load(userptr, "glGetTexParameterIuiv");
+ glad_glGetnUniformfv = (PFNGLGETNUNIFORMFVPROC) load(userptr, "glGetnUniformfv");
+ glad_glGetnUniformiv = (PFNGLGETNUNIFORMIVPROC) load(userptr, "glGetnUniformiv");
+ glad_glGetnUniformuiv = (PFNGLGETNUNIFORMUIVPROC) load(userptr, "glGetnUniformuiv");
+ glad_glIsEnabledi = (PFNGLISENABLEDIPROC) load(userptr, "glIsEnabledi");
+ glad_glMinSampleShading = (PFNGLMINSAMPLESHADINGPROC) load(userptr, "glMinSampleShading");
+ glad_glObjectLabel = (PFNGLOBJECTLABELPROC) load(userptr, "glObjectLabel");
+ glad_glObjectPtrLabel = (PFNGLOBJECTPTRLABELPROC) load(userptr, "glObjectPtrLabel");
+ glad_glPatchParameteri = (PFNGLPATCHPARAMETERIPROC) load(userptr, "glPatchParameteri");
+ glad_glPopDebugGroup = (PFNGLPOPDEBUGGROUPPROC) load(userptr, "glPopDebugGroup");
+ glad_glPrimitiveBoundingBox = (PFNGLPRIMITIVEBOUNDINGBOXPROC) load(userptr, "glPrimitiveBoundingBox");
+ glad_glPushDebugGroup = (PFNGLPUSHDEBUGGROUPPROC) load(userptr, "glPushDebugGroup");
+ glad_glReadnPixels = (PFNGLREADNPIXELSPROC) load(userptr, "glReadnPixels");
+ glad_glSamplerParameterIiv = (PFNGLSAMPLERPARAMETERIIVPROC) load(userptr, "glSamplerParameterIiv");
+ glad_glSamplerParameterIuiv = (PFNGLSAMPLERPARAMETERIUIVPROC) load(userptr, "glSamplerParameterIuiv");
+ glad_glTexBuffer = (PFNGLTEXBUFFERPROC) load(userptr, "glTexBuffer");
+ glad_glTexBufferRange = (PFNGLTEXBUFFERRANGEPROC) load(userptr, "glTexBufferRange");
+ glad_glTexParameterIiv = (PFNGLTEXPARAMETERIIVPROC) load(userptr, "glTexParameterIiv");
+ glad_glTexParameterIuiv = (PFNGLTEXPARAMETERIUIVPROC) load(userptr, "glTexParameterIuiv");
+ glad_glTexStorage3DMultisample = (PFNGLTEXSTORAGE3DMULTISAMPLEPROC) load(userptr, "glTexStorage3DMultisample");
+}
static void glad_gl_load_GL_ARB_debug_output( GLADuserptrloadfunc load, void* userptr) {
if(!GLAD_GL_ARB_debug_output) return;
glad_glDebugMessageCallbackARB = (PFNGLDEBUGMESSAGECALLBACKARBPROC) load(userptr, "glDebugMessageCallbackARB");
@@ -1831,6 +2310,78 @@ int gladLoadGL( GLADloadfunc load) {
return gladLoadGLUserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
}
+static int glad_gl_find_extensions_gles2( int version) {
+ const char *exts = NULL;
+ unsigned int num_exts_i = 0;
+ char **exts_i = NULL;
+ if (!glad_gl_get_extensions(version, &exts, &num_exts_i, &exts_i)) return 0;
+
+ GLAD_GL_OVR_multiview = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OVR_multiview");
+ GLAD_GL_OVR_multiview2 = glad_gl_has_extension(version, exts, num_exts_i, exts_i, "GL_OVR_multiview2");
+
+ glad_gl_free_extensions(exts_i, num_exts_i);
+
+ return 1;
+}
+
+static int glad_gl_find_core_gles2(void) {
+ int i;
+ const char* version;
+ const char* prefixes[] = {
+ "OpenGL ES-CM ",
+ "OpenGL ES-CL ",
+ "OpenGL ES ",
+ "OpenGL SC ",
+ NULL
+ };
+ int major = 0;
+ int minor = 0;
+ version = (const char*) glad_glGetString(GL_VERSION);
+ if (!version) return 0;
+ for (i = 0; prefixes[i]; i++) {
+ const size_t length = strlen(prefixes[i]);
+ if (strncmp(version, prefixes[i], length) == 0) {
+ version += length;
+ break;
+ }
+ }
+
+ GLAD_IMPL_UTIL_SSCANF(version, "%d.%d", &major, &minor);
+
+ GLAD_GL_ES_VERSION_2_0 = (major == 2 && minor >= 0) || major > 2;
+ GLAD_GL_ES_VERSION_3_0 = (major == 3 && minor >= 0) || major > 3;
+ GLAD_GL_ES_VERSION_3_1 = (major == 3 && minor >= 1) || major > 3;
+ GLAD_GL_ES_VERSION_3_2 = (major == 3 && minor >= 2) || major > 3;
+
+ return GLAD_MAKE_VERSION(major, minor);
+}
+
+int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr) {
+ int version;
+
+ glad_glGetString = (PFNGLGETSTRINGPROC) load(userptr, "glGetString");
+ if(glad_glGetString == NULL) return 0;
+ if(glad_glGetString(GL_VERSION) == NULL) return 0;
+ version = glad_gl_find_core_gles2();
+
+ glad_gl_load_GL_ES_VERSION_2_0(load, userptr);
+ glad_gl_load_GL_ES_VERSION_3_0(load, userptr);
+ glad_gl_load_GL_ES_VERSION_3_1(load, userptr);
+ glad_gl_load_GL_ES_VERSION_3_2(load, userptr);
+
+ if (!glad_gl_find_extensions_gles2(version)) return 0;
+ glad_gl_load_GL_OVR_multiview(load, userptr);
+
+
+
+ return version;
+}
+
+
+int gladLoadGLES2( GLADloadfunc load) {
+ return gladLoadGLES2UserPtr( glad_gl_get_proc_from_userptr, GLAD_GNUC_EXTENSION (void*) load);
+}
+
@@ -1924,7 +2475,7 @@ static GLADapiproc glad_gl_get_proc(void *vuserptr, const char *name) {
return result;
}
-static void* _glad_GL_loader_handle = NULL;
+static void* _glad_gles_loader_handle = NULL;
static void* glad_gl_dlopen_handle(void) {
#if GLAD_PLATFORM_APPLE
@@ -1946,11 +2497,11 @@ static void* glad_gl_dlopen_handle(void) {
};
#endif
- if (_glad_GL_loader_handle == NULL) {
- _glad_GL_loader_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
+ if (_glad_gles_loader_handle == NULL) {
+ _glad_gles_loader_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
}
- return _glad_GL_loader_handle;
+ return _glad_gles_loader_handle;
}
static struct _glad_gl_userptr glad_gl_build_userptr(void *handle) {
@@ -1976,7 +2527,7 @@ int gladLoaderLoadGL(void) {
int did_load = 0;
struct _glad_gl_userptr userptr;
- did_load = _glad_GL_loader_handle == NULL;
+ did_load = _glad_gles_loader_handle == NULL;
handle = glad_gl_dlopen_handle();
if (handle) {
userptr = glad_gl_build_userptr(handle);
@@ -1994,13 +2545,199 @@ int gladLoaderLoadGL(void) {
void gladLoaderUnloadGL(void) {
+ if (_glad_gles_loader_handle != NULL) {
+ glad_close_dlopen_handle(_glad_gles_loader_handle);
+ _glad_gles_loader_handle = NULL;
+ }
+}
+
+#endif /* GLAD_GL */
+#ifdef GLAD_GLES2
+
+#ifndef GLAD_LOADER_LIBRARY_C_
+#define GLAD_LOADER_LIBRARY_C_
+
+#include <stddef.h>
+#include <stdlib.h>
+
+#if GLAD_PLATFORM_WIN32
+#include <windows.h>
+#else
+#include <dlfcn.h>
+#endif
+
+
+static void* glad_get_dlopen_handle(const char *lib_names[], int length) {
+ void *handle = NULL;
+ int i;
+
+ for (i = 0; i < length; ++i) {
+#if GLAD_PLATFORM_WIN32
+ #if GLAD_PLATFORM_UWP
+ size_t buffer_size = (strlen(lib_names[i]) + 1) * sizeof(WCHAR);
+ LPWSTR buffer = (LPWSTR) malloc(buffer_size);
+ if (buffer != NULL) {
+ int ret = MultiByteToWideChar(CP_ACP, 0, lib_names[i], -1, buffer, buffer_size);
+ if (ret != 0) {
+ handle = (void*) LoadPackagedLibrary(buffer, 0);
+ }
+ free((void*) buffer);
+ }
+ #else
+ handle = (void*) LoadLibraryA(lib_names[i]);
+ #endif
+#else
+ handle = dlopen(lib_names[i], RTLD_LAZY | RTLD_LOCAL);
+#endif
+ if (handle != NULL) {
+ return handle;
+ }
+ }
+
+ return NULL;
+}
+
+static void glad_close_dlopen_handle(void* handle) {
+ if (handle != NULL) {
+#if GLAD_PLATFORM_WIN32
+ FreeLibrary((HMODULE) handle);
+#else
+ dlclose(handle);
+#endif
+ }
+}
+
+static GLADapiproc glad_dlsym_handle(void* handle, const char *name) {
+ if (handle == NULL) {
+ return NULL;
+ }
+
+#if GLAD_PLATFORM_WIN32
+ return (GLADapiproc) GetProcAddress((HMODULE) handle, name);
+#else
+ return GLAD_GNUC_EXTENSION (GLADapiproc) dlsym(handle, name);
+#endif
+}
+
+#endif /* GLAD_LOADER_LIBRARY_C_ */
+
+#if GLAD_PLATFORM_EMSCRIPTEN
+#ifndef GLAD_EGL_H_
+ typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+ typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char *name);
+#endif
+ extern __eglMustCastToProperFunctionPointerType emscripten_GetProcAddress(const char *name);
+#elif EGL_STATIC
+ typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+ typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char *name);
+ extern __eglMustCastToProperFunctionPointerType GLAD_API_PTR eglGetProcAddress(const char *name);
+#else
+ #include <glad/egl.h>
+#endif
+
+
+struct _glad_gles2_userptr {
+ void *handle;
+ PFNEGLGETPROCADDRESSPROC get_proc_address_ptr;
+};
+
+
+static GLADapiproc glad_gles2_get_proc(void *vuserptr, const char* name) {
+ struct _glad_gles2_userptr userptr = *(struct _glad_gles2_userptr*) vuserptr;
+ GLADapiproc result = NULL;
+
+#if GLAD_PLATFORM_EMSCRIPTEN
+ GLAD_UNUSED(glad_dlsym_handle);
+#else
+ result = glad_dlsym_handle(userptr.handle, name);
+#endif
+ if (result == NULL) {
+ result = userptr.get_proc_address_ptr(name);
+ }
+
+ return result;
+}
+
+static void* _glad_GL_loader_handle = NULL;
+
+static void* glad_gles2_dlopen_handle(void) {
+#if GLAD_PLATFORM_EMSCRIPTEN
+#elif GLAD_PLATFORM_APPLE
+ static const char *NAMES[] = {"libGLESv2.dylib"};
+#elif GLAD_PLATFORM_WIN32
+ static const char *NAMES[] = {"GLESv2.dll", "libGLESv2.dll"};
+#else
+ static const char *NAMES[] = {"libGLESv2.so.2", "libGLESv2.so"};
+#endif
+
+#if GLAD_PLATFORM_EMSCRIPTEN
+ GLAD_UNUSED(glad_get_dlopen_handle);
+ return NULL;
+#else
+ if (_glad_GL_loader_handle == NULL) {
+ _glad_GL_loader_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
+ }
+
+ return _glad_GL_loader_handle;
+#endif
+}
+
+static struct _glad_gles2_userptr glad_gles2_build_userptr(void *handle) {
+ struct _glad_gles2_userptr userptr;
+#if GLAD_PLATFORM_EMSCRIPTEN
+ GLAD_UNUSED(handle);
+ userptr.get_proc_address_ptr = emscripten_GetProcAddress;
+#else
+ userptr.handle = handle;
+ userptr.get_proc_address_ptr = eglGetProcAddress;
+#endif
+ return userptr;
+}
+
+int gladLoaderLoadGLES2(void) {
+ int version = 0;
+ void *handle = NULL;
+ int did_load = 0;
+ struct _glad_gles2_userptr userptr;
+
+#if GLAD_PLATFORM_EMSCRIPTEN
+ GLAD_UNUSED(handle);
+ GLAD_UNUSED(did_load);
+ GLAD_UNUSED(glad_gles2_dlopen_handle);
+ GLAD_UNUSED(glad_gles2_build_userptr);
+ userptr.get_proc_address_ptr = emscripten_GetProcAddress;
+ version = gladLoadGLES2UserPtr(glad_gles2_get_proc, &userptr);
+#else
+ if (eglGetProcAddress == NULL) {
+ return 0;
+ }
+
+ did_load = _glad_GL_loader_handle == NULL;
+ handle = glad_gles2_dlopen_handle();
+ if (handle != NULL) {
+ userptr = glad_gles2_build_userptr(handle);
+
+ version = gladLoadGLES2UserPtr(glad_gles2_get_proc, &userptr);
+
+ if (!version && did_load) {
+ gladLoaderUnloadGLES2();
+ }
+ }
+#endif
+
+ return version;
+}
+
+
+
+void gladLoaderUnloadGLES2(void) {
if (_glad_GL_loader_handle != NULL) {
glad_close_dlopen_handle(_glad_GL_loader_handle);
_glad_GL_loader_handle = NULL;
}
}
-#endif /* GLAD_GL */
+#endif /* GLAD_GLES2 */
#ifdef __cplusplus
}
diff --git a/thirdparty/glad/glad/egl.h b/thirdparty/glad/glad/egl.h
new file mode 100644
index 0000000000..1bf35c1404
--- /dev/null
+++ b/thirdparty/glad/glad/egl.h
@@ -0,0 +1,562 @@
+/**
+ * Loader generated by glad 2.0.3 on Fri Feb 3 07:06:48 2023
+ *
+ * SPDX-License-Identifier: (WTFPL OR CC0-1.0) AND Apache-2.0
+ *
+ * Generator: C/C++
+ * Specification: egl
+ * Extensions: 3
+ *
+ * APIs:
+ * - egl=1.5
+ *
+ * Options:
+ * - ALIAS = False
+ * - DEBUG = False
+ * - HEADER_ONLY = False
+ * - LOADER = True
+ * - MX = False
+ * - ON_DEMAND = False
+ *
+ * Commandline:
+ * --api='egl=1.5' --extensions='EGL_ANDROID_blob_cache,EGL_KHR_platform_wayland,EGL_KHR_platform_x11' c --loader
+ *
+ * Online:
+ * http://glad.sh/#api=egl%3D1.5&extensions=EGL_ANDROID_blob_cache%2CEGL_KHR_platform_wayland%2CEGL_KHR_platform_x11&generator=c&options=LOADER
+ *
+ */
+
+#ifndef GLAD_EGL_H_
+#define GLAD_EGL_H_
+
+
+#define GLAD_EGL
+#define GLAD_OPTION_EGL_LOADER
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#ifndef GLAD_PLATFORM_H_
+#define GLAD_PLATFORM_H_
+
+#ifndef GLAD_PLATFORM_WIN32
+ #if defined(_WIN32) || defined(__WIN32__) || defined(WIN32) || defined(__MINGW32__)
+ #define GLAD_PLATFORM_WIN32 1
+ #else
+ #define GLAD_PLATFORM_WIN32 0
+ #endif
+#endif
+
+#ifndef GLAD_PLATFORM_APPLE
+ #ifdef __APPLE__
+ #define GLAD_PLATFORM_APPLE 1
+ #else
+ #define GLAD_PLATFORM_APPLE 0
+ #endif
+#endif
+
+#ifndef GLAD_PLATFORM_EMSCRIPTEN
+ #ifdef __EMSCRIPTEN__
+ #define GLAD_PLATFORM_EMSCRIPTEN 1
+ #else
+ #define GLAD_PLATFORM_EMSCRIPTEN 0
+ #endif
+#endif
+
+#ifndef GLAD_PLATFORM_UWP
+ #if defined(_MSC_VER) && !defined(GLAD_INTERNAL_HAVE_WINAPIFAMILY)
+ #ifdef __has_include
+ #if __has_include(<winapifamily.h>)
+ #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
+ #endif
+ #elif _MSC_VER >= 1700 && !_USING_V110_SDK71_
+ #define GLAD_INTERNAL_HAVE_WINAPIFAMILY 1
+ #endif
+ #endif
+
+ #ifdef GLAD_INTERNAL_HAVE_WINAPIFAMILY
+ #include <winapifamily.h>
+ #if !WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_DESKTOP) && WINAPI_FAMILY_PARTITION(WINAPI_PARTITION_APP)
+ #define GLAD_PLATFORM_UWP 1
+ #endif
+ #endif
+
+ #ifndef GLAD_PLATFORM_UWP
+ #define GLAD_PLATFORM_UWP 0
+ #endif
+#endif
+
+#ifdef __GNUC__
+ #define GLAD_GNUC_EXTENSION __extension__
+#else
+ #define GLAD_GNUC_EXTENSION
+#endif
+
+#define GLAD_UNUSED(x) (void)(x)
+
+#ifndef GLAD_API_CALL
+ #if defined(GLAD_API_CALL_EXPORT)
+ #if GLAD_PLATFORM_WIN32 || defined(__CYGWIN__)
+ #if defined(GLAD_API_CALL_EXPORT_BUILD)
+ #if defined(__GNUC__)
+ #define GLAD_API_CALL __attribute__ ((dllexport)) extern
+ #else
+ #define GLAD_API_CALL __declspec(dllexport) extern
+ #endif
+ #else
+ #if defined(__GNUC__)
+ #define GLAD_API_CALL __attribute__ ((dllimport)) extern
+ #else
+ #define GLAD_API_CALL __declspec(dllimport) extern
+ #endif
+ #endif
+ #elif defined(__GNUC__) && defined(GLAD_API_CALL_EXPORT_BUILD)
+ #define GLAD_API_CALL __attribute__ ((visibility ("default"))) extern
+ #else
+ #define GLAD_API_CALL extern
+ #endif
+ #else
+ #define GLAD_API_CALL extern
+ #endif
+#endif
+
+#ifdef APIENTRY
+ #define GLAD_API_PTR APIENTRY
+#elif GLAD_PLATFORM_WIN32
+ #define GLAD_API_PTR __stdcall
+#else
+ #define GLAD_API_PTR
+#endif
+
+#ifndef GLAPI
+#define GLAPI GLAD_API_CALL
+#endif
+
+#ifndef GLAPIENTRY
+#define GLAPIENTRY GLAD_API_PTR
+#endif
+
+#define GLAD_MAKE_VERSION(major, minor) (major * 10000 + minor)
+#define GLAD_VERSION_MAJOR(version) (version / 10000)
+#define GLAD_VERSION_MINOR(version) (version % 10000)
+
+#define GLAD_GENERATOR_VERSION "2.0.3"
+
+typedef void (*GLADapiproc)(void);
+
+typedef GLADapiproc (*GLADloadfunc)(const char *name);
+typedef GLADapiproc (*GLADuserptrloadfunc)(void *userptr, const char *name);
+
+typedef void (*GLADprecallback)(const char *name, GLADapiproc apiproc, int len_args, ...);
+typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apiproc, int len_args, ...);
+
+#endif /* GLAD_PLATFORM_H_ */
+
+#define EGL_ALPHA_FORMAT 0x3088
+#define EGL_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_ALPHA_FORMAT_PRE 0x308C
+#define EGL_ALPHA_MASK_SIZE 0x303E
+#define EGL_ALPHA_SIZE 0x3021
+#define EGL_BACK_BUFFER 0x3084
+#define EGL_BAD_ACCESS 0x3002
+#define EGL_BAD_ALLOC 0x3003
+#define EGL_BAD_ATTRIBUTE 0x3004
+#define EGL_BAD_CONFIG 0x3005
+#define EGL_BAD_CONTEXT 0x3006
+#define EGL_BAD_CURRENT_SURFACE 0x3007
+#define EGL_BAD_DISPLAY 0x3008
+#define EGL_BAD_MATCH 0x3009
+#define EGL_BAD_NATIVE_PIXMAP 0x300A
+#define EGL_BAD_NATIVE_WINDOW 0x300B
+#define EGL_BAD_PARAMETER 0x300C
+#define EGL_BAD_SURFACE 0x300D
+#define EGL_BIND_TO_TEXTURE_RGB 0x3039
+#define EGL_BIND_TO_TEXTURE_RGBA 0x303A
+#define EGL_BLUE_SIZE 0x3022
+#define EGL_BUFFER_DESTROYED 0x3095
+#define EGL_BUFFER_PRESERVED 0x3094
+#define EGL_BUFFER_SIZE 0x3020
+#define EGL_CLIENT_APIS 0x308D
+#define EGL_CL_EVENT_HANDLE 0x309C
+#define EGL_COLORSPACE 0x3087
+#define EGL_COLORSPACE_LINEAR 0x308A
+#define EGL_COLORSPACE_sRGB 0x3089
+#define EGL_COLOR_BUFFER_TYPE 0x303F
+#define EGL_CONDITION_SATISFIED 0x30F6
+#define EGL_CONFIG_CAVEAT 0x3027
+#define EGL_CONFIG_ID 0x3028
+#define EGL_CONFORMANT 0x3042
+#define EGL_CONTEXT_CLIENT_TYPE 0x3097
+#define EGL_CONTEXT_CLIENT_VERSION 0x3098
+#define EGL_CONTEXT_LOST 0x300E
+#define EGL_CONTEXT_MAJOR_VERSION 0x3098
+#define EGL_CONTEXT_MINOR_VERSION 0x30FB
+#define EGL_CONTEXT_OPENGL_COMPATIBILITY_PROFILE_BIT 0x00000002
+#define EGL_CONTEXT_OPENGL_CORE_PROFILE_BIT 0x00000001
+#define EGL_CONTEXT_OPENGL_DEBUG 0x31B0
+#define EGL_CONTEXT_OPENGL_FORWARD_COMPATIBLE 0x31B1
+#define EGL_CONTEXT_OPENGL_PROFILE_MASK 0x30FD
+#define EGL_CONTEXT_OPENGL_RESET_NOTIFICATION_STRATEGY 0x31BD
+#define EGL_CONTEXT_OPENGL_ROBUST_ACCESS 0x31B2
+#define EGL_CORE_NATIVE_ENGINE 0x305B
+#define EGL_DEFAULT_DISPLAY EGL_CAST(EGLNativeDisplayType,0)
+#define EGL_DEPTH_SIZE 0x3025
+#define EGL_DISPLAY_SCALING 10000
+#define EGL_DONT_CARE EGL_CAST(EGLint,-1)
+#define EGL_DRAW 0x3059
+#define EGL_EXTENSIONS 0x3055
+#define EGL_FALSE 0
+#define EGL_FOREVER 0xFFFFFFFFFFFFFFFF
+#define EGL_GL_COLORSPACE 0x309D
+#define EGL_GL_COLORSPACE_LINEAR 0x308A
+#define EGL_GL_COLORSPACE_SRGB 0x3089
+#define EGL_GL_RENDERBUFFER 0x30B9
+#define EGL_GL_TEXTURE_2D 0x30B1
+#define EGL_GL_TEXTURE_3D 0x30B2
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_X 0x30B4
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Y 0x30B6
+#define EGL_GL_TEXTURE_CUBE_MAP_NEGATIVE_Z 0x30B8
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_X 0x30B3
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Y 0x30B5
+#define EGL_GL_TEXTURE_CUBE_MAP_POSITIVE_Z 0x30B7
+#define EGL_GL_TEXTURE_LEVEL 0x30BC
+#define EGL_GL_TEXTURE_ZOFFSET 0x30BD
+#define EGL_GREEN_SIZE 0x3023
+#define EGL_HEIGHT 0x3056
+#define EGL_HORIZONTAL_RESOLUTION 0x3090
+#define EGL_IMAGE_PRESERVED 0x30D2
+#define EGL_LARGEST_PBUFFER 0x3058
+#define EGL_LEVEL 0x3029
+#define EGL_LOSE_CONTEXT_ON_RESET 0x31BF
+#define EGL_LUMINANCE_BUFFER 0x308F
+#define EGL_LUMINANCE_SIZE 0x303D
+#define EGL_MATCH_NATIVE_PIXMAP 0x3041
+#define EGL_MAX_PBUFFER_HEIGHT 0x302A
+#define EGL_MAX_PBUFFER_PIXELS 0x302B
+#define EGL_MAX_PBUFFER_WIDTH 0x302C
+#define EGL_MAX_SWAP_INTERVAL 0x303C
+#define EGL_MIN_SWAP_INTERVAL 0x303B
+#define EGL_MIPMAP_LEVEL 0x3083
+#define EGL_MIPMAP_TEXTURE 0x3082
+#define EGL_MULTISAMPLE_RESOLVE 0x3099
+#define EGL_MULTISAMPLE_RESOLVE_BOX 0x309B
+#define EGL_MULTISAMPLE_RESOLVE_BOX_BIT 0x0200
+#define EGL_MULTISAMPLE_RESOLVE_DEFAULT 0x309A
+#define EGL_NATIVE_RENDERABLE 0x302D
+#define EGL_NATIVE_VISUAL_ID 0x302E
+#define EGL_NATIVE_VISUAL_TYPE 0x302F
+#define EGL_NONE 0x3038
+#define EGL_NON_CONFORMANT_CONFIG 0x3051
+#define EGL_NOT_INITIALIZED 0x3001
+#define EGL_NO_CONTEXT EGL_CAST(EGLContext,0)
+#define EGL_NO_DISPLAY EGL_CAST(EGLDisplay,0)
+#define EGL_NO_IMAGE EGL_CAST(EGLImage,0)
+#define EGL_NO_RESET_NOTIFICATION 0x31BE
+#define EGL_NO_SURFACE EGL_CAST(EGLSurface,0)
+#define EGL_NO_SYNC EGL_CAST(EGLSync,0)
+#define EGL_NO_TEXTURE 0x305C
+#define EGL_OPENGL_API 0x30A2
+#define EGL_OPENGL_BIT 0x0008
+#define EGL_OPENGL_ES2_BIT 0x0004
+#define EGL_OPENGL_ES3_BIT 0x00000040
+#define EGL_OPENGL_ES_API 0x30A0
+#define EGL_OPENGL_ES_BIT 0x0001
+#define EGL_OPENVG_API 0x30A1
+#define EGL_OPENVG_BIT 0x0002
+#define EGL_OPENVG_IMAGE 0x3096
+#define EGL_PBUFFER_BIT 0x0001
+#define EGL_PIXEL_ASPECT_RATIO 0x3092
+#define EGL_PIXMAP_BIT 0x0002
+#define EGL_PLATFORM_WAYLAND_KHR 0x31D8
+#define EGL_PLATFORM_X11_KHR 0x31D5
+#define EGL_PLATFORM_X11_SCREEN_KHR 0x31D6
+#define EGL_READ 0x305A
+#define EGL_RED_SIZE 0x3024
+#define EGL_RENDERABLE_TYPE 0x3040
+#define EGL_RENDER_BUFFER 0x3086
+#define EGL_RGB_BUFFER 0x308E
+#define EGL_SAMPLES 0x3031
+#define EGL_SAMPLE_BUFFERS 0x3032
+#define EGL_SIGNALED 0x30F2
+#define EGL_SINGLE_BUFFER 0x3085
+#define EGL_SLOW_CONFIG 0x3050
+#define EGL_STENCIL_SIZE 0x3026
+#define EGL_SUCCESS 0x3000
+#define EGL_SURFACE_TYPE 0x3033
+#define EGL_SWAP_BEHAVIOR 0x3093
+#define EGL_SWAP_BEHAVIOR_PRESERVED_BIT 0x0400
+#define EGL_SYNC_CL_EVENT 0x30FE
+#define EGL_SYNC_CL_EVENT_COMPLETE 0x30FF
+#define EGL_SYNC_CONDITION 0x30F8
+#define EGL_SYNC_FENCE 0x30F9
+#define EGL_SYNC_FLUSH_COMMANDS_BIT 0x0001
+#define EGL_SYNC_PRIOR_COMMANDS_COMPLETE 0x30F0
+#define EGL_SYNC_STATUS 0x30F1
+#define EGL_SYNC_TYPE 0x30F7
+#define EGL_TEXTURE_2D 0x305F
+#define EGL_TEXTURE_FORMAT 0x3080
+#define EGL_TEXTURE_RGB 0x305D
+#define EGL_TEXTURE_RGBA 0x305E
+#define EGL_TEXTURE_TARGET 0x3081
+#define EGL_TIMEOUT_EXPIRED 0x30F5
+#define EGL_TRANSPARENT_BLUE_VALUE 0x3035
+#define EGL_TRANSPARENT_GREEN_VALUE 0x3036
+#define EGL_TRANSPARENT_RED_VALUE 0x3037
+#define EGL_TRANSPARENT_RGB 0x3052
+#define EGL_TRANSPARENT_TYPE 0x3034
+#define EGL_TRUE 1
+#define EGL_UNKNOWN EGL_CAST(EGLint,-1)
+#define EGL_UNSIGNALED 0x30F3
+#define EGL_VENDOR 0x3053
+#define EGL_VERSION 0x3054
+#define EGL_VERTICAL_RESOLUTION 0x3091
+#define EGL_VG_ALPHA_FORMAT 0x3088
+#define EGL_VG_ALPHA_FORMAT_NONPRE 0x308B
+#define EGL_VG_ALPHA_FORMAT_PRE 0x308C
+#define EGL_VG_ALPHA_FORMAT_PRE_BIT 0x0040
+#define EGL_VG_COLORSPACE 0x3087
+#define EGL_VG_COLORSPACE_LINEAR 0x308A
+#define EGL_VG_COLORSPACE_LINEAR_BIT 0x0020
+#define EGL_VG_COLORSPACE_sRGB 0x3089
+#define EGL_WIDTH 0x3057
+#define EGL_WINDOW_BIT 0x0004
+
+
+#include <KHR/khrplatform.h>
+#include <EGL/eglplatform.h>
+
+
+
+
+
+
+
+
+
+
+
+struct AHardwareBuffer;
+struct wl_buffer;
+struct wl_display;
+struct wl_resource;
+
+typedef unsigned int EGLBoolean;
+typedef unsigned int EGLenum;
+typedef intptr_t EGLAttribKHR;
+typedef intptr_t EGLAttrib;
+typedef void *EGLClientBuffer;
+typedef void *EGLConfig;
+typedef void *EGLContext;
+typedef void *EGLDeviceEXT;
+typedef void *EGLDisplay;
+typedef void *EGLImage;
+typedef void *EGLImageKHR;
+typedef void *EGLLabelKHR;
+typedef void *EGLObjectKHR;
+typedef void *EGLOutputLayerEXT;
+typedef void *EGLOutputPortEXT;
+typedef void *EGLStreamKHR;
+typedef void *EGLSurface;
+typedef void *EGLSync;
+typedef void *EGLSyncKHR;
+typedef void *EGLSyncNV;
+typedef void (*__eglMustCastToProperFunctionPointerType)(void);
+typedef khronos_utime_nanoseconds_t EGLTimeKHR;
+typedef khronos_utime_nanoseconds_t EGLTime;
+typedef khronos_utime_nanoseconds_t EGLTimeNV;
+typedef khronos_utime_nanoseconds_t EGLuint64NV;
+typedef khronos_uint64_t EGLuint64KHR;
+typedef khronos_stime_nanoseconds_t EGLnsecsANDROID;
+typedef int EGLNativeFileDescriptorKHR;
+typedef khronos_ssize_t EGLsizeiANDROID;
+typedef void (*EGLSetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, const void *value, EGLsizeiANDROID valueSize);
+typedef EGLsizeiANDROID (*EGLGetBlobFuncANDROID) (const void *key, EGLsizeiANDROID keySize, void *value, EGLsizeiANDROID valueSize);
+struct EGLClientPixmapHI {
+ void *pData;
+ EGLint iWidth;
+ EGLint iHeight;
+ EGLint iStride;
+};
+typedef void (GLAD_API_PTR *EGLDEBUGPROCKHR)(EGLenum error,const char *command,EGLint messageType,EGLLabelKHR threadLabel,EGLLabelKHR objectLabel,const char* message);
+#define PFNEGLBINDWAYLANDDISPLAYWL PFNEGLBINDWAYLANDDISPLAYWLPROC
+#define PFNEGLUNBINDWAYLANDDISPLAYWL PFNEGLUNBINDWAYLANDDISPLAYWLPROC
+#define PFNEGLQUERYWAYLANDBUFFERWL PFNEGLQUERYWAYLANDBUFFERWLPROC
+#define PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWL PFNEGLCREATEWAYLANDBUFFERFROMIMAGEWLPROC
+
+
+#define EGL_VERSION_1_0 1
+GLAD_API_CALL int GLAD_EGL_VERSION_1_0;
+#define EGL_VERSION_1_1 1
+GLAD_API_CALL int GLAD_EGL_VERSION_1_1;
+#define EGL_VERSION_1_2 1
+GLAD_API_CALL int GLAD_EGL_VERSION_1_2;
+#define EGL_VERSION_1_3 1
+GLAD_API_CALL int GLAD_EGL_VERSION_1_3;
+#define EGL_VERSION_1_4 1
+GLAD_API_CALL int GLAD_EGL_VERSION_1_4;
+#define EGL_VERSION_1_5 1
+GLAD_API_CALL int GLAD_EGL_VERSION_1_5;
+#define EGL_ANDROID_blob_cache 1
+GLAD_API_CALL int GLAD_EGL_ANDROID_blob_cache;
+#define EGL_KHR_platform_wayland 1
+GLAD_API_CALL int GLAD_EGL_KHR_platform_wayland;
+#define EGL_KHR_platform_x11 1
+GLAD_API_CALL int GLAD_EGL_KHR_platform_x11;
+
+
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDAPIPROC)(EGLenum api);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLBINDTEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLCHOOSECONFIGPROC)(EGLDisplay dpy, const EGLint * attrib_list, EGLConfig * configs, EGLint config_size, EGLint * num_config);
+typedef EGLint (GLAD_API_PTR *PFNEGLCLIENTWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags, EGLTime timeout);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLCOPYBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface, EGLNativePixmapType target);
+typedef EGLContext (GLAD_API_PTR *PFNEGLCREATECONTEXTPROC)(EGLDisplay dpy, EGLConfig config, EGLContext share_context, const EGLint * attrib_list);
+typedef EGLImage (GLAD_API_PTR *PFNEGLCREATEIMAGEPROC)(EGLDisplay dpy, EGLContext ctx, EGLenum target, EGLClientBuffer buffer, const EGLAttrib * attrib_list);
+typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC)(EGLDisplay dpy, EGLenum buftype, EGLClientBuffer buffer, EGLConfig config, const EGLint * attrib_list);
+typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPBUFFERSURFACEPROC)(EGLDisplay dpy, EGLConfig config, const EGLint * attrib_list);
+typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativePixmapType pixmap, const EGLint * attrib_list);
+typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_pixmap, const EGLAttrib * attrib_list);
+typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEPLATFORMWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, void * native_window, const EGLAttrib * attrib_list);
+typedef EGLSync (GLAD_API_PTR *PFNEGLCREATESYNCPROC)(EGLDisplay dpy, EGLenum type, const EGLAttrib * attrib_list);
+typedef EGLSurface (GLAD_API_PTR *PFNEGLCREATEWINDOWSURFACEPROC)(EGLDisplay dpy, EGLConfig config, EGLNativeWindowType win, const EGLint * attrib_list);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYIMAGEPROC)(EGLDisplay dpy, EGLImage image);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLDESTROYSYNCPROC)(EGLDisplay dpy, EGLSync sync);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGATTRIBPROC)(EGLDisplay dpy, EGLConfig config, EGLint attribute, EGLint * value);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETCONFIGSPROC)(EGLDisplay dpy, EGLConfig * configs, EGLint config_size, EGLint * num_config);
+typedef EGLContext (GLAD_API_PTR *PFNEGLGETCURRENTCONTEXTPROC)(void);
+typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETCURRENTDISPLAYPROC)(void);
+typedef EGLSurface (GLAD_API_PTR *PFNEGLGETCURRENTSURFACEPROC)(EGLint readdraw);
+typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETDISPLAYPROC)(EGLNativeDisplayType display_id);
+typedef EGLint (GLAD_API_PTR *PFNEGLGETERRORPROC)(void);
+typedef EGLDisplay (GLAD_API_PTR *PFNEGLGETPLATFORMDISPLAYPROC)(EGLenum platform, void * native_display, const EGLAttrib * attrib_list);
+typedef __eglMustCastToProperFunctionPointerType (GLAD_API_PTR *PFNEGLGETPROCADDRESSPROC)(const char * procname);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLGETSYNCATTRIBPROC)(EGLDisplay dpy, EGLSync sync, EGLint attribute, EGLAttrib * value);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLINITIALIZEPROC)(EGLDisplay dpy, EGLint * major, EGLint * minor);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLMAKECURRENTPROC)(EGLDisplay dpy, EGLSurface draw, EGLSurface read, EGLContext ctx);
+typedef EGLenum (GLAD_API_PTR *PFNEGLQUERYAPIPROC)(void);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYCONTEXTPROC)(EGLDisplay dpy, EGLContext ctx, EGLint attribute, EGLint * value);
+typedef const char * (GLAD_API_PTR *PFNEGLQUERYSTRINGPROC)(EGLDisplay dpy, EGLint name);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLQUERYSURFACEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint * value);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETEXIMAGEPROC)(EGLDisplay dpy, EGLSurface surface, EGLint buffer);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLRELEASETHREADPROC)(void);
+typedef void (GLAD_API_PTR *PFNEGLSETBLOBCACHEFUNCSANDROIDPROC)(EGLDisplay dpy, EGLSetBlobFuncANDROID set, EGLGetBlobFuncANDROID get);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLSURFACEATTRIBPROC)(EGLDisplay dpy, EGLSurface surface, EGLint attribute, EGLint value);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPBUFFERSPROC)(EGLDisplay dpy, EGLSurface surface);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLSWAPINTERVALPROC)(EGLDisplay dpy, EGLint interval);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLTERMINATEPROC)(EGLDisplay dpy);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITCLIENTPROC)(void);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITGLPROC)(void);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITNATIVEPROC)(EGLint engine);
+typedef EGLBoolean (GLAD_API_PTR *PFNEGLWAITSYNCPROC)(EGLDisplay dpy, EGLSync sync, EGLint flags);
+
+GLAD_API_CALL PFNEGLBINDAPIPROC glad_eglBindAPI;
+#define eglBindAPI glad_eglBindAPI
+GLAD_API_CALL PFNEGLBINDTEXIMAGEPROC glad_eglBindTexImage;
+#define eglBindTexImage glad_eglBindTexImage
+GLAD_API_CALL PFNEGLCHOOSECONFIGPROC glad_eglChooseConfig;
+#define eglChooseConfig glad_eglChooseConfig
+GLAD_API_CALL PFNEGLCLIENTWAITSYNCPROC glad_eglClientWaitSync;
+#define eglClientWaitSync glad_eglClientWaitSync
+GLAD_API_CALL PFNEGLCOPYBUFFERSPROC glad_eglCopyBuffers;
+#define eglCopyBuffers glad_eglCopyBuffers
+GLAD_API_CALL PFNEGLCREATECONTEXTPROC glad_eglCreateContext;
+#define eglCreateContext glad_eglCreateContext
+GLAD_API_CALL PFNEGLCREATEIMAGEPROC glad_eglCreateImage;
+#define eglCreateImage glad_eglCreateImage
+GLAD_API_CALL PFNEGLCREATEPBUFFERFROMCLIENTBUFFERPROC glad_eglCreatePbufferFromClientBuffer;
+#define eglCreatePbufferFromClientBuffer glad_eglCreatePbufferFromClientBuffer
+GLAD_API_CALL PFNEGLCREATEPBUFFERSURFACEPROC glad_eglCreatePbufferSurface;
+#define eglCreatePbufferSurface glad_eglCreatePbufferSurface
+GLAD_API_CALL PFNEGLCREATEPIXMAPSURFACEPROC glad_eglCreatePixmapSurface;
+#define eglCreatePixmapSurface glad_eglCreatePixmapSurface
+GLAD_API_CALL PFNEGLCREATEPLATFORMPIXMAPSURFACEPROC glad_eglCreatePlatformPixmapSurface;
+#define eglCreatePlatformPixmapSurface glad_eglCreatePlatformPixmapSurface
+GLAD_API_CALL PFNEGLCREATEPLATFORMWINDOWSURFACEPROC glad_eglCreatePlatformWindowSurface;
+#define eglCreatePlatformWindowSurface glad_eglCreatePlatformWindowSurface
+GLAD_API_CALL PFNEGLCREATESYNCPROC glad_eglCreateSync;
+#define eglCreateSync glad_eglCreateSync
+GLAD_API_CALL PFNEGLCREATEWINDOWSURFACEPROC glad_eglCreateWindowSurface;
+#define eglCreateWindowSurface glad_eglCreateWindowSurface
+GLAD_API_CALL PFNEGLDESTROYCONTEXTPROC glad_eglDestroyContext;
+#define eglDestroyContext glad_eglDestroyContext
+GLAD_API_CALL PFNEGLDESTROYIMAGEPROC glad_eglDestroyImage;
+#define eglDestroyImage glad_eglDestroyImage
+GLAD_API_CALL PFNEGLDESTROYSURFACEPROC glad_eglDestroySurface;
+#define eglDestroySurface glad_eglDestroySurface
+GLAD_API_CALL PFNEGLDESTROYSYNCPROC glad_eglDestroySync;
+#define eglDestroySync glad_eglDestroySync
+GLAD_API_CALL PFNEGLGETCONFIGATTRIBPROC glad_eglGetConfigAttrib;
+#define eglGetConfigAttrib glad_eglGetConfigAttrib
+GLAD_API_CALL PFNEGLGETCONFIGSPROC glad_eglGetConfigs;
+#define eglGetConfigs glad_eglGetConfigs
+GLAD_API_CALL PFNEGLGETCURRENTCONTEXTPROC glad_eglGetCurrentContext;
+#define eglGetCurrentContext glad_eglGetCurrentContext
+GLAD_API_CALL PFNEGLGETCURRENTDISPLAYPROC glad_eglGetCurrentDisplay;
+#define eglGetCurrentDisplay glad_eglGetCurrentDisplay
+GLAD_API_CALL PFNEGLGETCURRENTSURFACEPROC glad_eglGetCurrentSurface;
+#define eglGetCurrentSurface glad_eglGetCurrentSurface
+GLAD_API_CALL PFNEGLGETDISPLAYPROC glad_eglGetDisplay;
+#define eglGetDisplay glad_eglGetDisplay
+GLAD_API_CALL PFNEGLGETERRORPROC glad_eglGetError;
+#define eglGetError glad_eglGetError
+GLAD_API_CALL PFNEGLGETPLATFORMDISPLAYPROC glad_eglGetPlatformDisplay;
+#define eglGetPlatformDisplay glad_eglGetPlatformDisplay
+GLAD_API_CALL PFNEGLGETPROCADDRESSPROC glad_eglGetProcAddress;
+#define eglGetProcAddress glad_eglGetProcAddress
+GLAD_API_CALL PFNEGLGETSYNCATTRIBPROC glad_eglGetSyncAttrib;
+#define eglGetSyncAttrib glad_eglGetSyncAttrib
+GLAD_API_CALL PFNEGLINITIALIZEPROC glad_eglInitialize;
+#define eglInitialize glad_eglInitialize
+GLAD_API_CALL PFNEGLMAKECURRENTPROC glad_eglMakeCurrent;
+#define eglMakeCurrent glad_eglMakeCurrent
+GLAD_API_CALL PFNEGLQUERYAPIPROC glad_eglQueryAPI;
+#define eglQueryAPI glad_eglQueryAPI
+GLAD_API_CALL PFNEGLQUERYCONTEXTPROC glad_eglQueryContext;
+#define eglQueryContext glad_eglQueryContext
+GLAD_API_CALL PFNEGLQUERYSTRINGPROC glad_eglQueryString;
+#define eglQueryString glad_eglQueryString
+GLAD_API_CALL PFNEGLQUERYSURFACEPROC glad_eglQuerySurface;
+#define eglQuerySurface glad_eglQuerySurface
+GLAD_API_CALL PFNEGLRELEASETEXIMAGEPROC glad_eglReleaseTexImage;
+#define eglReleaseTexImage glad_eglReleaseTexImage
+GLAD_API_CALL PFNEGLRELEASETHREADPROC glad_eglReleaseThread;
+#define eglReleaseThread glad_eglReleaseThread
+GLAD_API_CALL PFNEGLSETBLOBCACHEFUNCSANDROIDPROC glad_eglSetBlobCacheFuncsANDROID;
+#define eglSetBlobCacheFuncsANDROID glad_eglSetBlobCacheFuncsANDROID
+GLAD_API_CALL PFNEGLSURFACEATTRIBPROC glad_eglSurfaceAttrib;
+#define eglSurfaceAttrib glad_eglSurfaceAttrib
+GLAD_API_CALL PFNEGLSWAPBUFFERSPROC glad_eglSwapBuffers;
+#define eglSwapBuffers glad_eglSwapBuffers
+GLAD_API_CALL PFNEGLSWAPINTERVALPROC glad_eglSwapInterval;
+#define eglSwapInterval glad_eglSwapInterval
+GLAD_API_CALL PFNEGLTERMINATEPROC glad_eglTerminate;
+#define eglTerminate glad_eglTerminate
+GLAD_API_CALL PFNEGLWAITCLIENTPROC glad_eglWaitClient;
+#define eglWaitClient glad_eglWaitClient
+GLAD_API_CALL PFNEGLWAITGLPROC glad_eglWaitGL;
+#define eglWaitGL glad_eglWaitGL
+GLAD_API_CALL PFNEGLWAITNATIVEPROC glad_eglWaitNative;
+#define eglWaitNative glad_eglWaitNative
+GLAD_API_CALL PFNEGLWAITSYNCPROC glad_eglWaitSync;
+#define eglWaitSync glad_eglWaitSync
+
+
+
+
+
+GLAD_API_CALL int gladLoadEGLUserPtr(EGLDisplay display, GLADuserptrloadfunc load, void *userptr);
+GLAD_API_CALL int gladLoadEGL(EGLDisplay display, GLADloadfunc load);
+
+#ifdef GLAD_EGL
+
+GLAD_API_CALL int gladLoaderLoadEGL(EGLDisplay display);
+
+GLAD_API_CALL void gladLoaderUnloadEGL(void);
+
+#endif
+#ifdef __cplusplus
+}
+#endif
+#endif
diff --git a/thirdparty/glad/glad/gl.h b/thirdparty/glad/glad/gl.h
index b09b5ff280..307ea4dbb8 100644
--- a/thirdparty/glad/glad/gl.h
+++ b/thirdparty/glad/glad/gl.h
@@ -9,6 +9,7 @@
*
* APIs:
* - gl:compatibility=3.3
+ * - gles2=3.2
*
* Options:
* - ALIAS = False
@@ -19,10 +20,10 @@
* - ON_DEMAND = False
*
* Commandline:
- * --api='gl:compatibility=3.3' --extensions='GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_ARB_get_program_binary,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2' c --loader
+ * --merge --api='gl:compatibility=3.3,gles2=3.2' --extensions='GL_ARB_debug_output,GL_ARB_framebuffer_object,GL_ARB_get_program_binary,GL_EXT_framebuffer_blit,GL_EXT_framebuffer_multisample,GL_EXT_framebuffer_object,GL_OVR_multiview,GL_OVR_multiview2' c --loader
*
* Online:
- * http://glad.sh/#api=gl%3Acompatibility%3D3.3&extensions=GL_ARB_debug_output%2CGL_ARB_framebuffer_object%2CGL_ARB_get_program_binary%2CGL_EXT_framebuffer_blit%2CGL_EXT_framebuffer_multisample%2CGL_EXT_framebuffer_object%2CGL_OVR_multiview%2CGL_OVR_multiview2&generator=c&options=LOADER
+ * http://glad.sh/#api=gl%3Acompatibility%3D3.3%2Cgles2%3D3.2&extensions=GL_ARB_debug_output%2CGL_ARB_framebuffer_object%2CGL_ARB_get_program_binary%2CGL_EXT_framebuffer_blit%2CGL_EXT_framebuffer_multisample%2CGL_EXT_framebuffer_object%2CGL_OVR_multiview%2CGL_OVR_multiview2&generator=c&options=MERGE%2CLOADER
*
*/
@@ -49,11 +50,24 @@
#error OpenGL (gl3ext.h) header already included (API: gl), remove previous include!
#endif
#define __gl3ext_h_ 1
+#ifdef __gl2_h_
+ #error OpenGL ES 2 header already included (API: gles2), remove previous include!
+#endif
+#define __gl2_h_ 1
+#ifdef __gles2_gl2_h_
+ #error OpenGL ES 2 header already included (API: gles2), remove previous include!
+#endif
+#define __gles2_gl2_h_ 1
+#ifdef __gles2_gl3_h_
+ #error OpenGL ES 3 header already included (API: gles2), remove previous include!
+#endif
+#define __gles2_gl3_h_ 1
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#define GLAD_GL
+#define GLAD_GLES2
#define GLAD_OPTION_GL_LOADER
#ifdef __cplusplus
@@ -1514,6 +1528,352 @@ typedef void (*GLADpostcallback)(void *ret, const char *name, GLADapiproc apipro
#define GL_ZERO 0
#define GL_ZOOM_X 0x0D16
#define GL_ZOOM_Y 0x0D17
+#define GL_ACTIVE_ATOMIC_COUNTER_BUFFERS 0x92D9
+#define GL_ACTIVE_PROGRAM 0x8259
+#define GL_ACTIVE_RESOURCES 0x92F5
+#define GL_ACTIVE_VARIABLES 0x9305
+#define GL_ALL_BARRIER_BITS 0xFFFFFFFF
+#define GL_ALL_SHADER_BITS 0xFFFFFFFF
+#define GL_ANY_SAMPLES_PASSED_CONSERVATIVE 0x8D6A
+#define GL_ARRAY_SIZE 0x92FB
+#define GL_ARRAY_STRIDE 0x92FE
+#define GL_ATOMIC_COUNTER_BARRIER_BIT 0x00001000
+#define GL_ATOMIC_COUNTER_BUFFER 0x92C0
+#define GL_ATOMIC_COUNTER_BUFFER_BINDING 0x92C1
+#define GL_ATOMIC_COUNTER_BUFFER_INDEX 0x9301
+#define GL_ATOMIC_COUNTER_BUFFER_SIZE 0x92C3
+#define GL_ATOMIC_COUNTER_BUFFER_START 0x92C2
+#define GL_BLOCK_INDEX 0x92FD
+#define GL_BUFFER 0x82E0
+#define GL_BUFFER_BINDING 0x9302
+#define GL_BUFFER_DATA_SIZE 0x9303
+#define GL_BUFFER_UPDATE_BARRIER_BIT 0x00000200
+#define GL_BUFFER_VARIABLE 0x92E5
+#define GL_COLORBURN 0x929A
+#define GL_COLORDODGE 0x9299
+#define GL_COMMAND_BARRIER_BIT 0x00000040
+#define GL_COMPRESSED_R11_EAC 0x9270
+#define GL_COMPRESSED_RG11_EAC 0x9272
+#define GL_COMPRESSED_RGB8_ETC2 0x9274
+#define GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9276
+#define GL_COMPRESSED_RGBA8_ETC2_EAC 0x9278
+#define GL_COMPRESSED_RGBA_ASTC_10x10 0x93BB
+#define GL_COMPRESSED_RGBA_ASTC_10x5 0x93B8
+#define GL_COMPRESSED_RGBA_ASTC_10x6 0x93B9
+#define GL_COMPRESSED_RGBA_ASTC_10x8 0x93BA
+#define GL_COMPRESSED_RGBA_ASTC_12x10 0x93BC
+#define GL_COMPRESSED_RGBA_ASTC_12x12 0x93BD
+#define GL_COMPRESSED_RGBA_ASTC_4x4 0x93B0
+#define GL_COMPRESSED_RGBA_ASTC_5x4 0x93B1
+#define GL_COMPRESSED_RGBA_ASTC_5x5 0x93B2
+#define GL_COMPRESSED_RGBA_ASTC_6x5 0x93B3
+#define GL_COMPRESSED_RGBA_ASTC_6x6 0x93B4
+#define GL_COMPRESSED_RGBA_ASTC_8x5 0x93B5
+#define GL_COMPRESSED_RGBA_ASTC_8x6 0x93B6
+#define GL_COMPRESSED_RGBA_ASTC_8x8 0x93B7
+#define GL_COMPRESSED_SIGNED_R11_EAC 0x9271
+#define GL_COMPRESSED_SIGNED_RG11_EAC 0x9273
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x10 0x93DB
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x5 0x93D8
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x6 0x93D9
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_10x8 0x93DA
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x10 0x93DC
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_12x12 0x93DD
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_4x4 0x93D0
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x4 0x93D1
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_5x5 0x93D2
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x5 0x93D3
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_6x6 0x93D4
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x5 0x93D5
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x6 0x93D6
+#define GL_COMPRESSED_SRGB8_ALPHA8_ASTC_8x8 0x93D7
+#define GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC 0x9279
+#define GL_COMPRESSED_SRGB8_ETC2 0x9275
+#define GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 0x9277
+#define GL_COMPUTE_SHADER 0x91B9
+#define GL_COMPUTE_SHADER_BIT 0x00000020
+#define GL_COMPUTE_WORK_GROUP_SIZE 0x8267
+#define GL_CONTEXT_FLAG_DEBUG_BIT 0x00000002
+#define GL_CONTEXT_FLAG_ROBUST_ACCESS_BIT 0x00000004
+#define GL_CONTEXT_LOST 0x0507
+#define GL_COPY_READ_BUFFER_BINDING 0x8F36
+#define GL_COPY_WRITE_BUFFER_BINDING 0x8F37
+#define GL_DARKEN 0x9297
+#define GL_DEBUG_CALLBACK_FUNCTION 0x8244
+#define GL_DEBUG_CALLBACK_USER_PARAM 0x8245
+#define GL_DEBUG_GROUP_STACK_DEPTH 0x826D
+#define GL_DEBUG_LOGGED_MESSAGES 0x9145
+#define GL_DEBUG_NEXT_LOGGED_MESSAGE_LENGTH 0x8243
+#define GL_DEBUG_OUTPUT 0x92E0
+#define GL_DEBUG_OUTPUT_SYNCHRONOUS 0x8242
+#define GL_DEBUG_SEVERITY_HIGH 0x9146
+#define GL_DEBUG_SEVERITY_LOW 0x9148
+#define GL_DEBUG_SEVERITY_MEDIUM 0x9147
+#define GL_DEBUG_SEVERITY_NOTIFICATION 0x826B
+#define GL_DEBUG_SOURCE_API 0x8246
+#define GL_DEBUG_SOURCE_APPLICATION 0x824A
+#define GL_DEBUG_SOURCE_OTHER 0x824B
+#define GL_DEBUG_SOURCE_SHADER_COMPILER 0x8248
+#define GL_DEBUG_SOURCE_THIRD_PARTY 0x8249
+#define GL_DEBUG_SOURCE_WINDOW_SYSTEM 0x8247
+#define GL_DEBUG_TYPE_DEPRECATED_BEHAVIOR 0x824D
+#define GL_DEBUG_TYPE_ERROR 0x824C
+#define GL_DEBUG_TYPE_MARKER 0x8268
+#define GL_DEBUG_TYPE_OTHER 0x8251
+#define GL_DEBUG_TYPE_PERFORMANCE 0x8250
+#define GL_DEBUG_TYPE_POP_GROUP 0x826A
+#define GL_DEBUG_TYPE_PORTABILITY 0x824F
+#define GL_DEBUG_TYPE_PUSH_GROUP 0x8269
+#define GL_DEBUG_TYPE_UNDEFINED_BEHAVIOR 0x824E
+#define GL_DEPTH_STENCIL_TEXTURE_MODE 0x90EA
+#define GL_DIFFERENCE 0x929E
+#define GL_DISPATCH_INDIRECT_BUFFER 0x90EE
+#define GL_DISPATCH_INDIRECT_BUFFER_BINDING 0x90EF
+#define GL_DRAW_INDIRECT_BUFFER 0x8F3F
+#define GL_DRAW_INDIRECT_BUFFER_BINDING 0x8F43
+#define GL_ELEMENT_ARRAY_BARRIER_BIT 0x00000002
+#define GL_EXCLUSION 0x92A0
+#define GL_FIXED 0x140C
+#define GL_FRACTIONAL_EVEN 0x8E7C
+#define GL_FRACTIONAL_ODD 0x8E7B
+#define GL_FRAGMENT_INTERPOLATION_OFFSET_BITS 0x8E5D
+#define GL_FRAGMENT_SHADER_BIT 0x00000002
+#define GL_FRAMEBUFFER_BARRIER_BIT 0x00000400
+#define GL_FRAMEBUFFER_DEFAULT_FIXED_SAMPLE_LOCATIONS 0x9314
+#define GL_FRAMEBUFFER_DEFAULT_HEIGHT 0x9311
+#define GL_FRAMEBUFFER_DEFAULT_LAYERS 0x9312
+#define GL_FRAMEBUFFER_DEFAULT_SAMPLES 0x9313
+#define GL_FRAMEBUFFER_DEFAULT_WIDTH 0x9310
+#define GL_FRAMEBUFFER_INCOMPLETE_DIMENSIONS 0x8CD9
+#define GL_GEOMETRY_SHADER_BIT 0x00000004
+#define GL_GEOMETRY_SHADER_INVOCATIONS 0x887F
+#define GL_GUILTY_CONTEXT_RESET 0x8253
+#define GL_HARDLIGHT 0x929B
+#define GL_HIGH_FLOAT 0x8DF2
+#define GL_HIGH_INT 0x8DF5
+#define GL_HSL_COLOR 0x92AF
+#define GL_HSL_HUE 0x92AD
+#define GL_HSL_LUMINOSITY 0x92B0
+#define GL_HSL_SATURATION 0x92AE
+#define GL_IMAGE_2D 0x904D
+#define GL_IMAGE_2D_ARRAY 0x9053
+#define GL_IMAGE_3D 0x904E
+#define GL_IMAGE_BINDING_ACCESS 0x8F3E
+#define GL_IMAGE_BINDING_FORMAT 0x906E
+#define GL_IMAGE_BINDING_LAYER 0x8F3D
+#define GL_IMAGE_BINDING_LAYERED 0x8F3C
+#define GL_IMAGE_BINDING_LEVEL 0x8F3B
+#define GL_IMAGE_BINDING_NAME 0x8F3A
+#define GL_IMAGE_BUFFER 0x9051
+#define GL_IMAGE_CUBE 0x9050
+#define GL_IMAGE_CUBE_MAP_ARRAY 0x9054
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_CLASS 0x90C9
+#define GL_IMAGE_FORMAT_COMPATIBILITY_BY_SIZE 0x90C8
+#define GL_IMAGE_FORMAT_COMPATIBILITY_TYPE 0x90C7
+#define GL_IMPLEMENTATION_COLOR_READ_FORMAT 0x8B9B
+#define GL_IMPLEMENTATION_COLOR_READ_TYPE 0x8B9A
+#define GL_INNOCENT_CONTEXT_RESET 0x8254
+#define GL_INT_IMAGE_2D 0x9058
+#define GL_INT_IMAGE_2D_ARRAY 0x905E
+#define GL_INT_IMAGE_3D 0x9059
+#define GL_INT_IMAGE_BUFFER 0x905C
+#define GL_INT_IMAGE_CUBE 0x905B
+#define GL_INT_IMAGE_CUBE_MAP_ARRAY 0x905F
+#define GL_INT_SAMPLER_CUBE_MAP_ARRAY 0x900E
+#define GL_ISOLINES 0x8E7A
+#define GL_IS_PER_PATCH 0x92E7
+#define GL_IS_ROW_MAJOR 0x9300
+#define GL_LAYER_PROVOKING_VERTEX 0x825E
+#define GL_LIGHTEN 0x9298
+#define GL_LOCATION 0x930E
+#define GL_LOSE_CONTEXT_ON_RESET 0x8252
+#define GL_LOW_FLOAT 0x8DF0
+#define GL_LOW_INT 0x8DF3
+#define GL_MATRIX_STRIDE 0x92FF
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_BINDINGS 0x92DC
+#define GL_MAX_ATOMIC_COUNTER_BUFFER_SIZE 0x92D8
+#define GL_MAX_COMBINED_ATOMIC_COUNTERS 0x92D7
+#define GL_MAX_COMBINED_ATOMIC_COUNTER_BUFFERS 0x92D1
+#define GL_MAX_COMBINED_COMPUTE_UNIFORM_COMPONENTS 0x8266
+#define GL_MAX_COMBINED_IMAGE_UNIFORMS 0x90CF
+#define GL_MAX_COMBINED_IMAGE_UNITS_AND_FRAGMENT_OUTPUTS 0x8F39
+#define GL_MAX_COMBINED_SHADER_OUTPUT_RESOURCES 0x8F39
+#define GL_MAX_COMBINED_SHADER_STORAGE_BLOCKS 0x90DC
+#define GL_MAX_COMBINED_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E1E
+#define GL_MAX_COMBINED_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E1F
+#define GL_MAX_COMPUTE_ATOMIC_COUNTERS 0x8265
+#define GL_MAX_COMPUTE_ATOMIC_COUNTER_BUFFERS 0x8264
+#define GL_MAX_COMPUTE_IMAGE_UNIFORMS 0x91BD
+#define GL_MAX_COMPUTE_SHADER_STORAGE_BLOCKS 0x90DB
+#define GL_MAX_COMPUTE_SHARED_MEMORY_SIZE 0x8262
+#define GL_MAX_COMPUTE_TEXTURE_IMAGE_UNITS 0x91BC
+#define GL_MAX_COMPUTE_UNIFORM_BLOCKS 0x91BB
+#define GL_MAX_COMPUTE_UNIFORM_COMPONENTS 0x8263
+#define GL_MAX_COMPUTE_WORK_GROUP_COUNT 0x91BE
+#define GL_MAX_COMPUTE_WORK_GROUP_INVOCATIONS 0x90EB
+#define GL_MAX_COMPUTE_WORK_GROUP_SIZE 0x91BF
+#define GL_MAX_DEBUG_GROUP_STACK_DEPTH 0x826C
+#define GL_MAX_DEBUG_LOGGED_MESSAGES 0x9144
+#define GL_MAX_DEBUG_MESSAGE_LENGTH 0x9143
+#define GL_MAX_ELEMENT_INDEX 0x8D6B
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTERS 0x92D6
+#define GL_MAX_FRAGMENT_ATOMIC_COUNTER_BUFFERS 0x92D0
+#define GL_MAX_FRAGMENT_IMAGE_UNIFORMS 0x90CE
+#define GL_MAX_FRAGMENT_INTERPOLATION_OFFSET 0x8E5C
+#define GL_MAX_FRAGMENT_SHADER_STORAGE_BLOCKS 0x90DA
+#define GL_MAX_FRAGMENT_UNIFORM_VECTORS 0x8DFD
+#define GL_MAX_FRAMEBUFFER_HEIGHT 0x9316
+#define GL_MAX_FRAMEBUFFER_LAYERS 0x9317
+#define GL_MAX_FRAMEBUFFER_SAMPLES 0x9318
+#define GL_MAX_FRAMEBUFFER_WIDTH 0x9315
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTERS 0x92D5
+#define GL_MAX_GEOMETRY_ATOMIC_COUNTER_BUFFERS 0x92CF
+#define GL_MAX_GEOMETRY_IMAGE_UNIFORMS 0x90CD
+#define GL_MAX_GEOMETRY_SHADER_INVOCATIONS 0x8E5A
+#define GL_MAX_GEOMETRY_SHADER_STORAGE_BLOCKS 0x90D7
+#define GL_MAX_IMAGE_UNITS 0x8F38
+#define GL_MAX_LABEL_LENGTH 0x82E8
+#define GL_MAX_NAME_LENGTH 0x92F6
+#define GL_MAX_NUM_ACTIVE_VARIABLES 0x92F7
+#define GL_MAX_PATCH_VERTICES 0x8E7D
+#define GL_MAX_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5F
+#define GL_MAX_SHADER_STORAGE_BLOCK_SIZE 0x90DE
+#define GL_MAX_SHADER_STORAGE_BUFFER_BINDINGS 0x90DD
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTERS 0x92D3
+#define GL_MAX_TESS_CONTROL_ATOMIC_COUNTER_BUFFERS 0x92CD
+#define GL_MAX_TESS_CONTROL_IMAGE_UNIFORMS 0x90CB
+#define GL_MAX_TESS_CONTROL_INPUT_COMPONENTS 0x886C
+#define GL_MAX_TESS_CONTROL_OUTPUT_COMPONENTS 0x8E83
+#define GL_MAX_TESS_CONTROL_SHADER_STORAGE_BLOCKS 0x90D8
+#define GL_MAX_TESS_CONTROL_TEXTURE_IMAGE_UNITS 0x8E81
+#define GL_MAX_TESS_CONTROL_TOTAL_OUTPUT_COMPONENTS 0x8E85
+#define GL_MAX_TESS_CONTROL_UNIFORM_BLOCKS 0x8E89
+#define GL_MAX_TESS_CONTROL_UNIFORM_COMPONENTS 0x8E7F
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTERS 0x92D4
+#define GL_MAX_TESS_EVALUATION_ATOMIC_COUNTER_BUFFERS 0x92CE
+#define GL_MAX_TESS_EVALUATION_IMAGE_UNIFORMS 0x90CC
+#define GL_MAX_TESS_EVALUATION_INPUT_COMPONENTS 0x886D
+#define GL_MAX_TESS_EVALUATION_OUTPUT_COMPONENTS 0x8E86
+#define GL_MAX_TESS_EVALUATION_SHADER_STORAGE_BLOCKS 0x90D9
+#define GL_MAX_TESS_EVALUATION_TEXTURE_IMAGE_UNITS 0x8E82
+#define GL_MAX_TESS_EVALUATION_UNIFORM_BLOCKS 0x8E8A
+#define GL_MAX_TESS_EVALUATION_UNIFORM_COMPONENTS 0x8E80
+#define GL_MAX_TESS_GEN_LEVEL 0x8E7E
+#define GL_MAX_TESS_PATCH_COMPONENTS 0x8E84
+#define GL_MAX_UNIFORM_LOCATIONS 0x826E
+#define GL_MAX_VARYING_VECTORS 0x8DFC
+#define GL_MAX_VERTEX_ATOMIC_COUNTERS 0x92D2
+#define GL_MAX_VERTEX_ATOMIC_COUNTER_BUFFERS 0x92CC
+#define GL_MAX_VERTEX_ATTRIB_BINDINGS 0x82DA
+#define GL_MAX_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D9
+#define GL_MAX_VERTEX_ATTRIB_STRIDE 0x82E5
+#define GL_MAX_VERTEX_IMAGE_UNIFORMS 0x90CA
+#define GL_MAX_VERTEX_SHADER_STORAGE_BLOCKS 0x90D6
+#define GL_MAX_VERTEX_UNIFORM_VECTORS 0x8DFB
+#define GL_MEDIUM_FLOAT 0x8DF1
+#define GL_MEDIUM_INT 0x8DF4
+#define GL_MIN_FRAGMENT_INTERPOLATION_OFFSET 0x8E5B
+#define GL_MIN_PROGRAM_TEXTURE_GATHER_OFFSET 0x8E5E
+#define GL_MIN_SAMPLE_SHADING_VALUE 0x8C37
+#define GL_MULTIPLY 0x9294
+#define GL_MULTISAMPLE_LINE_WIDTH_GRANULARITY 0x9382
+#define GL_MULTISAMPLE_LINE_WIDTH_RANGE 0x9381
+#define GL_NAME_LENGTH 0x92F9
+#define GL_NO_RESET_NOTIFICATION 0x8261
+#define GL_NUM_ACTIVE_VARIABLES 0x9304
+#define GL_NUM_SAMPLE_COUNTS 0x9380
+#define GL_NUM_SHADER_BINARY_FORMATS 0x8DF9
+#define GL_OFFSET 0x92FC
+#define GL_OVERLAY 0x9296
+#define GL_PATCHES 0x000E
+#define GL_PATCH_VERTICES 0x8E72
+#define GL_PIXEL_BUFFER_BARRIER_BIT 0x00000080
+#define GL_PRIMITIVE_BOUNDING_BOX 0x92BE
+#define GL_PRIMITIVE_RESTART_FIXED_INDEX 0x8D69
+#define GL_PRIMITIVE_RESTART_FOR_PATCHES_SUPPORTED 0x8221
+#define GL_PROGRAM 0x82E2
+#define GL_PROGRAM_INPUT 0x92E3
+#define GL_PROGRAM_OUTPUT 0x92E4
+#define GL_PROGRAM_PIPELINE 0x82E4
+#define GL_PROGRAM_PIPELINE_BINDING 0x825A
+#define GL_PROGRAM_SEPARABLE 0x8258
+#define GL_QUERY 0x82E3
+#define GL_REFERENCED_BY_COMPUTE_SHADER 0x930B
+#define GL_REFERENCED_BY_FRAGMENT_SHADER 0x930A
+#define GL_REFERENCED_BY_GEOMETRY_SHADER 0x9309
+#define GL_REFERENCED_BY_TESS_CONTROL_SHADER 0x9307
+#define GL_REFERENCED_BY_TESS_EVALUATION_SHADER 0x9308
+#define GL_REFERENCED_BY_VERTEX_SHADER 0x9306
+#define GL_RESET_NOTIFICATION_STRATEGY 0x8256
+#define GL_RGB565 0x8D62
+#define GL_SAMPLER 0x82E6
+#define GL_SAMPLER_CUBE_MAP_ARRAY 0x900C
+#define GL_SAMPLER_CUBE_MAP_ARRAY_SHADOW 0x900D
+#define GL_SAMPLE_SHADING 0x8C36
+#define GL_SCREEN 0x9295
+#define GL_SHADER 0x82E1
+#define GL_SHADER_BINARY_FORMATS 0x8DF8
+#define GL_SHADER_COMPILER 0x8DFA
+#define GL_SHADER_IMAGE_ACCESS_BARRIER_BIT 0x00000020
+#define GL_SHADER_STORAGE_BARRIER_BIT 0x00002000
+#define GL_SHADER_STORAGE_BLOCK 0x92E6
+#define GL_SHADER_STORAGE_BUFFER 0x90D2
+#define GL_SHADER_STORAGE_BUFFER_BINDING 0x90D3
+#define GL_SHADER_STORAGE_BUFFER_OFFSET_ALIGNMENT 0x90DF
+#define GL_SHADER_STORAGE_BUFFER_SIZE 0x90D5
+#define GL_SHADER_STORAGE_BUFFER_START 0x90D4
+#define GL_SOFTLIGHT 0x929C
+#define GL_TESS_CONTROL_OUTPUT_VERTICES 0x8E75
+#define GL_TESS_CONTROL_SHADER 0x8E88
+#define GL_TESS_CONTROL_SHADER_BIT 0x00000008
+#define GL_TESS_EVALUATION_SHADER 0x8E87
+#define GL_TESS_EVALUATION_SHADER_BIT 0x00000010
+#define GL_TESS_GEN_MODE 0x8E76
+#define GL_TESS_GEN_POINT_MODE 0x8E79
+#define GL_TESS_GEN_SPACING 0x8E77
+#define GL_TESS_GEN_VERTEX_ORDER 0x8E78
+#define GL_TEXTURE_BINDING_CUBE_MAP_ARRAY 0x900A
+#define GL_TEXTURE_BUFFER_BINDING 0x8C2A
+#define GL_TEXTURE_BUFFER_OFFSET 0x919D
+#define GL_TEXTURE_BUFFER_OFFSET_ALIGNMENT 0x919F
+#define GL_TEXTURE_BUFFER_SIZE 0x919E
+#define GL_TEXTURE_CUBE_MAP_ARRAY 0x9009
+#define GL_TEXTURE_FETCH_BARRIER_BIT 0x00000008
+#define GL_TEXTURE_IMMUTABLE_FORMAT 0x912F
+#define GL_TEXTURE_IMMUTABLE_LEVELS 0x82DF
+#define GL_TEXTURE_UPDATE_BARRIER_BIT 0x00000100
+#define GL_TOP_LEVEL_ARRAY_SIZE 0x930C
+#define GL_TOP_LEVEL_ARRAY_STRIDE 0x930D
+#define GL_TRANSFORM_FEEDBACK 0x8E22
+#define GL_TRANSFORM_FEEDBACK_ACTIVE 0x8E24
+#define GL_TRANSFORM_FEEDBACK_BARRIER_BIT 0x00000800
+#define GL_TRANSFORM_FEEDBACK_BINDING 0x8E25
+#define GL_TRANSFORM_FEEDBACK_BUFFER_ACTIVE 0x8E24
+#define GL_TRANSFORM_FEEDBACK_BUFFER_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_PAUSED 0x8E23
+#define GL_TRANSFORM_FEEDBACK_VARYING 0x92F4
+#define GL_TYPE 0x92FA
+#define GL_UNDEFINED_VERTEX 0x8260
+#define GL_UNIFORM 0x92E1
+#define GL_UNIFORM_BARRIER_BIT 0x00000004
+#define GL_UNIFORM_BLOCK 0x92E2
+#define GL_UNKNOWN_CONTEXT_RESET 0x8255
+#define GL_UNSIGNED_INT_ATOMIC_COUNTER 0x92DB
+#define GL_UNSIGNED_INT_IMAGE_2D 0x9063
+#define GL_UNSIGNED_INT_IMAGE_2D_ARRAY 0x9069
+#define GL_UNSIGNED_INT_IMAGE_3D 0x9064
+#define GL_UNSIGNED_INT_IMAGE_BUFFER 0x9067
+#define GL_UNSIGNED_INT_IMAGE_CUBE 0x9066
+#define GL_UNSIGNED_INT_IMAGE_CUBE_MAP_ARRAY 0x906A
+#define GL_UNSIGNED_INT_SAMPLER_CUBE_MAP_ARRAY 0x900F
+#define GL_VERTEX_ATTRIB_ARRAY_BARRIER_BIT 0x00000001
+#define GL_VERTEX_ATTRIB_BINDING 0x82D4
+#define GL_VERTEX_ATTRIB_RELATIVE_OFFSET 0x82D5
+#define GL_VERTEX_BINDING_BUFFER 0x8F4F
+#define GL_VERTEX_BINDING_DIVISOR 0x82D6
+#define GL_VERTEX_BINDING_OFFSET 0x82D7
+#define GL_VERTEX_BINDING_STRIDE 0x82D8
+#define GL_VERTEX_SHADER_BIT 0x00000001
#include <KHR/khrplatform.h>
@@ -1605,6 +1965,14 @@ GLAD_API_CALL int GLAD_GL_VERSION_3_1;
GLAD_API_CALL int GLAD_GL_VERSION_3_2;
#define GL_VERSION_3_3 1
GLAD_API_CALL int GLAD_GL_VERSION_3_3;
+#define GL_ES_VERSION_2_0 1
+GLAD_API_CALL int GLAD_GL_ES_VERSION_2_0;
+#define GL_ES_VERSION_3_0 1
+GLAD_API_CALL int GLAD_GL_ES_VERSION_3_0;
+#define GL_ES_VERSION_3_1 1
+GLAD_API_CALL int GLAD_GL_ES_VERSION_3_1;
+#define GL_ES_VERSION_3_2 1
+GLAD_API_CALL int GLAD_GL_ES_VERSION_3_2;
#define GL_ARB_debug_output 1
GLAD_API_CALL int GLAD_GL_ARB_debug_output;
#define GL_ARB_framebuffer_object 1
@@ -2374,6 +2742,111 @@ typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IPROC)(GLint x, GLint y, GLint z);
typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3IVPROC)(const GLint * v);
typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SPROC)(GLshort x, GLshort y, GLshort z);
typedef void (GLAD_API_PTR *PFNGLWINDOWPOS3SVPROC)(const GLshort * v);
+typedef void (GLAD_API_PTR *PFNGLACTIVESHADERPROGRAMPROC)(GLuint pipeline, GLuint program);
+typedef void (GLAD_API_PTR *PFNGLBINDIMAGETEXTUREPROC)(GLuint unit, GLuint texture, GLint level, GLboolean layered, GLint layer, GLenum access, GLenum format);
+typedef void (GLAD_API_PTR *PFNGLBINDPROGRAMPIPELINEPROC)(GLuint pipeline);
+typedef void (GLAD_API_PTR *PFNGLBINDTRANSFORMFEEDBACKPROC)(GLenum target, GLuint id);
+typedef void (GLAD_API_PTR *PFNGLBINDVERTEXBUFFERPROC)(GLuint bindingindex, GLuint buffer, GLintptr offset, GLsizei stride);
+typedef void (GLAD_API_PTR *PFNGLBLENDBARRIERPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONSEPARATEIPROC)(GLuint buf, GLenum modeRGB, GLenum modeAlpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDEQUATIONIPROC)(GLuint buf, GLenum mode);
+typedef void (GLAD_API_PTR *PFNGLBLENDFUNCSEPARATEIPROC)(GLuint buf, GLenum srcRGB, GLenum dstRGB, GLenum srcAlpha, GLenum dstAlpha);
+typedef void (GLAD_API_PTR *PFNGLBLENDFUNCIPROC)(GLuint buf, GLenum src, GLenum dst);
+typedef void (GLAD_API_PTR *PFNGLCLEARDEPTHFPROC)(GLfloat d);
+typedef void (GLAD_API_PTR *PFNGLCOPYIMAGESUBDATAPROC)(GLuint srcName, GLenum srcTarget, GLint srcLevel, GLint srcX, GLint srcY, GLint srcZ, GLuint dstName, GLenum dstTarget, GLint dstLevel, GLint dstX, GLint dstY, GLint dstZ, GLsizei srcWidth, GLsizei srcHeight, GLsizei srcDepth);
+typedef GLuint (GLAD_API_PTR *PFNGLCREATESHADERPROGRAMVPROC)(GLenum type, GLsizei count, const GLchar *const* strings);
+typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECALLBACKPROC)(GLDEBUGPROC callback, const void * userParam);
+typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGECONTROLPROC)(GLenum source, GLenum type, GLenum severity, GLsizei count, const GLuint * ids, GLboolean enabled);
+typedef void (GLAD_API_PTR *PFNGLDEBUGMESSAGEINSERTPROC)(GLenum source, GLenum type, GLuint id, GLenum severity, GLsizei length, const GLchar * buf);
+typedef void (GLAD_API_PTR *PFNGLDELETEPROGRAMPIPELINESPROC)(GLsizei n, const GLuint * pipelines);
+typedef void (GLAD_API_PTR *PFNGLDELETETRANSFORMFEEDBACKSPROC)(GLsizei n, const GLuint * ids);
+typedef void (GLAD_API_PTR *PFNGLDEPTHRANGEFPROC)(GLfloat n, GLfloat f);
+typedef void (GLAD_API_PTR *PFNGLDISPATCHCOMPUTEPROC)(GLuint num_groups_x, GLuint num_groups_y, GLuint num_groups_z);
+typedef void (GLAD_API_PTR *PFNGLDISPATCHCOMPUTEINDIRECTPROC)(GLintptr indirect);
+typedef void (GLAD_API_PTR *PFNGLDRAWARRAYSINDIRECTPROC)(GLenum mode, const void * indirect);
+typedef void (GLAD_API_PTR *PFNGLDRAWELEMENTSINDIRECTPROC)(GLenum mode, GLenum type, const void * indirect);
+typedef void (GLAD_API_PTR *PFNGLFRAMEBUFFERPARAMETERIPROC)(GLenum target, GLenum pname, GLint param);
+typedef void (GLAD_API_PTR *PFNGLGENPROGRAMPIPELINESPROC)(GLsizei n, GLuint * pipelines);
+typedef void (GLAD_API_PTR *PFNGLGENTRANSFORMFEEDBACKSPROC)(GLsizei n, GLuint * ids);
+typedef GLuint (GLAD_API_PTR *PFNGLGETDEBUGMESSAGELOGPROC)(GLuint count, GLsizei bufSize, GLenum * sources, GLenum * types, GLuint * ids, GLenum * severities, GLsizei * lengths, GLchar * messageLog);
+typedef void (GLAD_API_PTR *PFNGLGETFRAMEBUFFERPARAMETERIVPROC)(GLenum target, GLenum pname, GLint * params);
+typedef GLenum (GLAD_API_PTR *PFNGLGETGRAPHICSRESETSTATUSPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLGETINTERNALFORMATIVPROC)(GLenum target, GLenum internalformat, GLenum pname, GLsizei count, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei bufSize, GLsizei * length, GLchar * label);
+typedef void (GLAD_API_PTR *PFNGLGETOBJECTPTRLABELPROC)(const void * ptr, GLsizei bufSize, GLsizei * length, GLchar * label);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMINTERFACEIVPROC)(GLuint program, GLenum programInterface, GLenum pname, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEINFOLOGPROC)(GLuint pipeline, GLsizei bufSize, GLsizei * length, GLchar * infoLog);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMPIPELINEIVPROC)(GLuint pipeline, GLenum pname, GLint * params);
+typedef GLuint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCEINDEXPROC)(GLuint program, GLenum programInterface, const GLchar * name);
+typedef GLint (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCELOCATIONPROC)(GLuint program, GLenum programInterface, const GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCENAMEPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei bufSize, GLsizei * length, GLchar * name);
+typedef void (GLAD_API_PTR *PFNGLGETPROGRAMRESOURCEIVPROC)(GLuint program, GLenum programInterface, GLuint index, GLsizei propCount, const GLenum * props, GLsizei count, GLsizei * length, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETSHADERPRECISIONFORMATPROC)(GLenum shadertype, GLenum precisiontype, GLint * range, GLint * precision);
+typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMFVPROC)(GLuint program, GLint location, GLsizei bufSize, GLfloat * params);
+typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLint * params);
+typedef void (GLAD_API_PTR *PFNGLGETNUNIFORMUIVPROC)(GLuint program, GLint location, GLsizei bufSize, GLuint * params);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATEFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum * attachments);
+typedef void (GLAD_API_PTR *PFNGLINVALIDATESUBFRAMEBUFFERPROC)(GLenum target, GLsizei numAttachments, const GLenum * attachments, GLint x, GLint y, GLsizei width, GLsizei height);
+typedef GLboolean (GLAD_API_PTR *PFNGLISPROGRAMPIPELINEPROC)(GLuint pipeline);
+typedef GLboolean (GLAD_API_PTR *PFNGLISTRANSFORMFEEDBACKPROC)(GLuint id);
+typedef void (GLAD_API_PTR *PFNGLMEMORYBARRIERPROC)(GLbitfield barriers);
+typedef void (GLAD_API_PTR *PFNGLMEMORYBARRIERBYREGIONPROC)(GLbitfield barriers);
+typedef void (GLAD_API_PTR *PFNGLMINSAMPLESHADINGPROC)(GLfloat value);
+typedef void (GLAD_API_PTR *PFNGLOBJECTLABELPROC)(GLenum identifier, GLuint name, GLsizei length, const GLchar * label);
+typedef void (GLAD_API_PTR *PFNGLOBJECTPTRLABELPROC)(const void * ptr, GLsizei length, const GLchar * label);
+typedef void (GLAD_API_PTR *PFNGLPATCHPARAMETERIPROC)(GLenum pname, GLint value);
+typedef void (GLAD_API_PTR *PFNGLPAUSETRANSFORMFEEDBACKPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLPOPDEBUGGROUPPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLPRIMITIVEBOUNDINGBOXPROC)(GLfloat minX, GLfloat minY, GLfloat minZ, GLfloat minW, GLfloat maxX, GLfloat maxY, GLfloat maxZ, GLfloat maxW);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FPROC)(GLuint program, GLint location, GLfloat v0);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IPROC)(GLuint program, GLint location, GLint v0);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIPROC)(GLuint program, GLint location, GLuint v0);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM1UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IPROC)(GLuint program, GLint location, GLint v0, GLint v1);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM2UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM3UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FPROC)(GLuint program, GLint location, GLfloat v0, GLfloat v1, GLfloat v2, GLfloat v3);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4FVPROC)(GLuint program, GLint location, GLsizei count, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IPROC)(GLuint program, GLint location, GLint v0, GLint v1, GLint v2, GLint v3);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4IVPROC)(GLuint program, GLint location, GLsizei count, const GLint * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIPROC)(GLuint program, GLint location, GLuint v0, GLuint v1, GLuint v2, GLuint v3);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORM4UIVPROC)(GLuint program, GLint location, GLsizei count, const GLuint * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC)(GLuint program, GLint location, GLsizei count, GLboolean transpose, const GLfloat * value);
+typedef void (GLAD_API_PTR *PFNGLPUSHDEBUGGROUPPROC)(GLenum source, GLuint id, GLsizei length, const GLchar * message);
+typedef void (GLAD_API_PTR *PFNGLREADNPIXELSPROC)(GLint x, GLint y, GLsizei width, GLsizei height, GLenum format, GLenum type, GLsizei bufSize, void * data);
+typedef void (GLAD_API_PTR *PFNGLRELEASESHADERCOMPILERPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLRESUMETRANSFORMFEEDBACKPROC)(void);
+typedef void (GLAD_API_PTR *PFNGLSHADERBINARYPROC)(GLsizei count, const GLuint * shaders, GLenum binaryFormat, const void * binary, GLsizei length);
+typedef void (GLAD_API_PTR *PFNGLTEXBUFFERRANGEPROC)(GLenum target, GLenum internalformat, GLuint buffer, GLintptr offset, GLsizeiptr size);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE2DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLboolean fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DPROC)(GLenum target, GLsizei levels, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth);
+typedef void (GLAD_API_PTR *PFNGLTEXSTORAGE3DMULTISAMPLEPROC)(GLenum target, GLsizei samples, GLenum internalformat, GLsizei width, GLsizei height, GLsizei depth, GLboolean fixedsamplelocations);
+typedef void (GLAD_API_PTR *PFNGLUSEPROGRAMSTAGESPROC)(GLuint pipeline, GLbitfield stages, GLuint program);
+typedef void (GLAD_API_PTR *PFNGLVALIDATEPROGRAMPIPELINEPROC)(GLuint pipeline);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBBINDINGPROC)(GLuint attribindex, GLuint bindingindex);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLboolean normalized, GLuint relativeoffset);
+typedef void (GLAD_API_PTR *PFNGLVERTEXATTRIBIFORMATPROC)(GLuint attribindex, GLint size, GLenum type, GLuint relativeoffset);
+typedef void (GLAD_API_PTR *PFNGLVERTEXBINDINGDIVISORPROC)(GLuint bindingindex, GLuint divisor);
GLAD_API_CALL PFNGLACCUMPROC glad_glAccum;
#define glAccum glad_glAccum
@@ -3877,6 +4350,216 @@ GLAD_API_CALL PFNGLWINDOWPOS3SPROC glad_glWindowPos3s;
#define glWindowPos3s glad_glWindowPos3s
GLAD_API_CALL PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv;
#define glWindowPos3sv glad_glWindowPos3sv
+GLAD_API_CALL PFNGLACTIVESHADERPROGRAMPROC glad_glActiveShaderProgram;
+#define glActiveShaderProgram glad_glActiveShaderProgram
+GLAD_API_CALL PFNGLBINDIMAGETEXTUREPROC glad_glBindImageTexture;
+#define glBindImageTexture glad_glBindImageTexture
+GLAD_API_CALL PFNGLBINDPROGRAMPIPELINEPROC glad_glBindProgramPipeline;
+#define glBindProgramPipeline glad_glBindProgramPipeline
+GLAD_API_CALL PFNGLBINDTRANSFORMFEEDBACKPROC glad_glBindTransformFeedback;
+#define glBindTransformFeedback glad_glBindTransformFeedback
+GLAD_API_CALL PFNGLBINDVERTEXBUFFERPROC glad_glBindVertexBuffer;
+#define glBindVertexBuffer glad_glBindVertexBuffer
+GLAD_API_CALL PFNGLBLENDBARRIERPROC glad_glBlendBarrier;
+#define glBlendBarrier glad_glBlendBarrier
+GLAD_API_CALL PFNGLBLENDEQUATIONSEPARATEIPROC glad_glBlendEquationSeparatei;
+#define glBlendEquationSeparatei glad_glBlendEquationSeparatei
+GLAD_API_CALL PFNGLBLENDEQUATIONIPROC glad_glBlendEquationi;
+#define glBlendEquationi glad_glBlendEquationi
+GLAD_API_CALL PFNGLBLENDFUNCSEPARATEIPROC glad_glBlendFuncSeparatei;
+#define glBlendFuncSeparatei glad_glBlendFuncSeparatei
+GLAD_API_CALL PFNGLBLENDFUNCIPROC glad_glBlendFunci;
+#define glBlendFunci glad_glBlendFunci
+GLAD_API_CALL PFNGLCLEARDEPTHFPROC glad_glClearDepthf;
+#define glClearDepthf glad_glClearDepthf
+GLAD_API_CALL PFNGLCOPYIMAGESUBDATAPROC glad_glCopyImageSubData;
+#define glCopyImageSubData glad_glCopyImageSubData
+GLAD_API_CALL PFNGLCREATESHADERPROGRAMVPROC glad_glCreateShaderProgramv;
+#define glCreateShaderProgramv glad_glCreateShaderProgramv
+GLAD_API_CALL PFNGLDEBUGMESSAGECALLBACKPROC glad_glDebugMessageCallback;
+#define glDebugMessageCallback glad_glDebugMessageCallback
+GLAD_API_CALL PFNGLDEBUGMESSAGECONTROLPROC glad_glDebugMessageControl;
+#define glDebugMessageControl glad_glDebugMessageControl
+GLAD_API_CALL PFNGLDEBUGMESSAGEINSERTPROC glad_glDebugMessageInsert;
+#define glDebugMessageInsert glad_glDebugMessageInsert
+GLAD_API_CALL PFNGLDELETEPROGRAMPIPELINESPROC glad_glDeleteProgramPipelines;
+#define glDeleteProgramPipelines glad_glDeleteProgramPipelines
+GLAD_API_CALL PFNGLDELETETRANSFORMFEEDBACKSPROC glad_glDeleteTransformFeedbacks;
+#define glDeleteTransformFeedbacks glad_glDeleteTransformFeedbacks
+GLAD_API_CALL PFNGLDEPTHRANGEFPROC glad_glDepthRangef;
+#define glDepthRangef glad_glDepthRangef
+GLAD_API_CALL PFNGLDISPATCHCOMPUTEPROC glad_glDispatchCompute;
+#define glDispatchCompute glad_glDispatchCompute
+GLAD_API_CALL PFNGLDISPATCHCOMPUTEINDIRECTPROC glad_glDispatchComputeIndirect;
+#define glDispatchComputeIndirect glad_glDispatchComputeIndirect
+GLAD_API_CALL PFNGLDRAWARRAYSINDIRECTPROC glad_glDrawArraysIndirect;
+#define glDrawArraysIndirect glad_glDrawArraysIndirect
+GLAD_API_CALL PFNGLDRAWELEMENTSINDIRECTPROC glad_glDrawElementsIndirect;
+#define glDrawElementsIndirect glad_glDrawElementsIndirect
+GLAD_API_CALL PFNGLFRAMEBUFFERPARAMETERIPROC glad_glFramebufferParameteri;
+#define glFramebufferParameteri glad_glFramebufferParameteri
+GLAD_API_CALL PFNGLGENPROGRAMPIPELINESPROC glad_glGenProgramPipelines;
+#define glGenProgramPipelines glad_glGenProgramPipelines
+GLAD_API_CALL PFNGLGENTRANSFORMFEEDBACKSPROC glad_glGenTransformFeedbacks;
+#define glGenTransformFeedbacks glad_glGenTransformFeedbacks
+GLAD_API_CALL PFNGLGETDEBUGMESSAGELOGPROC glad_glGetDebugMessageLog;
+#define glGetDebugMessageLog glad_glGetDebugMessageLog
+GLAD_API_CALL PFNGLGETFRAMEBUFFERPARAMETERIVPROC glad_glGetFramebufferParameteriv;
+#define glGetFramebufferParameteriv glad_glGetFramebufferParameteriv
+GLAD_API_CALL PFNGLGETGRAPHICSRESETSTATUSPROC glad_glGetGraphicsResetStatus;
+#define glGetGraphicsResetStatus glad_glGetGraphicsResetStatus
+GLAD_API_CALL PFNGLGETINTERNALFORMATIVPROC glad_glGetInternalformativ;
+#define glGetInternalformativ glad_glGetInternalformativ
+GLAD_API_CALL PFNGLGETOBJECTLABELPROC glad_glGetObjectLabel;
+#define glGetObjectLabel glad_glGetObjectLabel
+GLAD_API_CALL PFNGLGETOBJECTPTRLABELPROC glad_glGetObjectPtrLabel;
+#define glGetObjectPtrLabel glad_glGetObjectPtrLabel
+GLAD_API_CALL PFNGLGETPROGRAMINTERFACEIVPROC glad_glGetProgramInterfaceiv;
+#define glGetProgramInterfaceiv glad_glGetProgramInterfaceiv
+GLAD_API_CALL PFNGLGETPROGRAMPIPELINEINFOLOGPROC glad_glGetProgramPipelineInfoLog;
+#define glGetProgramPipelineInfoLog glad_glGetProgramPipelineInfoLog
+GLAD_API_CALL PFNGLGETPROGRAMPIPELINEIVPROC glad_glGetProgramPipelineiv;
+#define glGetProgramPipelineiv glad_glGetProgramPipelineiv
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCEINDEXPROC glad_glGetProgramResourceIndex;
+#define glGetProgramResourceIndex glad_glGetProgramResourceIndex
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCELOCATIONPROC glad_glGetProgramResourceLocation;
+#define glGetProgramResourceLocation glad_glGetProgramResourceLocation
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCENAMEPROC glad_glGetProgramResourceName;
+#define glGetProgramResourceName glad_glGetProgramResourceName
+GLAD_API_CALL PFNGLGETPROGRAMRESOURCEIVPROC glad_glGetProgramResourceiv;
+#define glGetProgramResourceiv glad_glGetProgramResourceiv
+GLAD_API_CALL PFNGLGETSHADERPRECISIONFORMATPROC glad_glGetShaderPrecisionFormat;
+#define glGetShaderPrecisionFormat glad_glGetShaderPrecisionFormat
+GLAD_API_CALL PFNGLGETNUNIFORMFVPROC glad_glGetnUniformfv;
+#define glGetnUniformfv glad_glGetnUniformfv
+GLAD_API_CALL PFNGLGETNUNIFORMIVPROC glad_glGetnUniformiv;
+#define glGetnUniformiv glad_glGetnUniformiv
+GLAD_API_CALL PFNGLGETNUNIFORMUIVPROC glad_glGetnUniformuiv;
+#define glGetnUniformuiv glad_glGetnUniformuiv
+GLAD_API_CALL PFNGLINVALIDATEFRAMEBUFFERPROC glad_glInvalidateFramebuffer;
+#define glInvalidateFramebuffer glad_glInvalidateFramebuffer
+GLAD_API_CALL PFNGLINVALIDATESUBFRAMEBUFFERPROC glad_glInvalidateSubFramebuffer;
+#define glInvalidateSubFramebuffer glad_glInvalidateSubFramebuffer
+GLAD_API_CALL PFNGLISPROGRAMPIPELINEPROC glad_glIsProgramPipeline;
+#define glIsProgramPipeline glad_glIsProgramPipeline
+GLAD_API_CALL PFNGLISTRANSFORMFEEDBACKPROC glad_glIsTransformFeedback;
+#define glIsTransformFeedback glad_glIsTransformFeedback
+GLAD_API_CALL PFNGLMEMORYBARRIERPROC glad_glMemoryBarrier;
+#define glMemoryBarrier glad_glMemoryBarrier
+GLAD_API_CALL PFNGLMEMORYBARRIERBYREGIONPROC glad_glMemoryBarrierByRegion;
+#define glMemoryBarrierByRegion glad_glMemoryBarrierByRegion
+GLAD_API_CALL PFNGLMINSAMPLESHADINGPROC glad_glMinSampleShading;
+#define glMinSampleShading glad_glMinSampleShading
+GLAD_API_CALL PFNGLOBJECTLABELPROC glad_glObjectLabel;
+#define glObjectLabel glad_glObjectLabel
+GLAD_API_CALL PFNGLOBJECTPTRLABELPROC glad_glObjectPtrLabel;
+#define glObjectPtrLabel glad_glObjectPtrLabel
+GLAD_API_CALL PFNGLPATCHPARAMETERIPROC glad_glPatchParameteri;
+#define glPatchParameteri glad_glPatchParameteri
+GLAD_API_CALL PFNGLPAUSETRANSFORMFEEDBACKPROC glad_glPauseTransformFeedback;
+#define glPauseTransformFeedback glad_glPauseTransformFeedback
+GLAD_API_CALL PFNGLPOPDEBUGGROUPPROC glad_glPopDebugGroup;
+#define glPopDebugGroup glad_glPopDebugGroup
+GLAD_API_CALL PFNGLPRIMITIVEBOUNDINGBOXPROC glad_glPrimitiveBoundingBox;
+#define glPrimitiveBoundingBox glad_glPrimitiveBoundingBox
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1FPROC glad_glProgramUniform1f;
+#define glProgramUniform1f glad_glProgramUniform1f
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1FVPROC glad_glProgramUniform1fv;
+#define glProgramUniform1fv glad_glProgramUniform1fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1IPROC glad_glProgramUniform1i;
+#define glProgramUniform1i glad_glProgramUniform1i
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1IVPROC glad_glProgramUniform1iv;
+#define glProgramUniform1iv glad_glProgramUniform1iv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIPROC glad_glProgramUniform1ui;
+#define glProgramUniform1ui glad_glProgramUniform1ui
+GLAD_API_CALL PFNGLPROGRAMUNIFORM1UIVPROC glad_glProgramUniform1uiv;
+#define glProgramUniform1uiv glad_glProgramUniform1uiv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2FPROC glad_glProgramUniform2f;
+#define glProgramUniform2f glad_glProgramUniform2f
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2FVPROC glad_glProgramUniform2fv;
+#define glProgramUniform2fv glad_glProgramUniform2fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2IPROC glad_glProgramUniform2i;
+#define glProgramUniform2i glad_glProgramUniform2i
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2IVPROC glad_glProgramUniform2iv;
+#define glProgramUniform2iv glad_glProgramUniform2iv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIPROC glad_glProgramUniform2ui;
+#define glProgramUniform2ui glad_glProgramUniform2ui
+GLAD_API_CALL PFNGLPROGRAMUNIFORM2UIVPROC glad_glProgramUniform2uiv;
+#define glProgramUniform2uiv glad_glProgramUniform2uiv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3FPROC glad_glProgramUniform3f;
+#define glProgramUniform3f glad_glProgramUniform3f
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3FVPROC glad_glProgramUniform3fv;
+#define glProgramUniform3fv glad_glProgramUniform3fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3IPROC glad_glProgramUniform3i;
+#define glProgramUniform3i glad_glProgramUniform3i
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3IVPROC glad_glProgramUniform3iv;
+#define glProgramUniform3iv glad_glProgramUniform3iv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIPROC glad_glProgramUniform3ui;
+#define glProgramUniform3ui glad_glProgramUniform3ui
+GLAD_API_CALL PFNGLPROGRAMUNIFORM3UIVPROC glad_glProgramUniform3uiv;
+#define glProgramUniform3uiv glad_glProgramUniform3uiv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4FPROC glad_glProgramUniform4f;
+#define glProgramUniform4f glad_glProgramUniform4f
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4FVPROC glad_glProgramUniform4fv;
+#define glProgramUniform4fv glad_glProgramUniform4fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4IPROC glad_glProgramUniform4i;
+#define glProgramUniform4i glad_glProgramUniform4i
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4IVPROC glad_glProgramUniform4iv;
+#define glProgramUniform4iv glad_glProgramUniform4iv
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIPROC glad_glProgramUniform4ui;
+#define glProgramUniform4ui glad_glProgramUniform4ui
+GLAD_API_CALL PFNGLPROGRAMUNIFORM4UIVPROC glad_glProgramUniform4uiv;
+#define glProgramUniform4uiv glad_glProgramUniform4uiv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2FVPROC glad_glProgramUniformMatrix2fv;
+#define glProgramUniformMatrix2fv glad_glProgramUniformMatrix2fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X3FVPROC glad_glProgramUniformMatrix2x3fv;
+#define glProgramUniformMatrix2x3fv glad_glProgramUniformMatrix2x3fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX2X4FVPROC glad_glProgramUniformMatrix2x4fv;
+#define glProgramUniformMatrix2x4fv glad_glProgramUniformMatrix2x4fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3FVPROC glad_glProgramUniformMatrix3fv;
+#define glProgramUniformMatrix3fv glad_glProgramUniformMatrix3fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X2FVPROC glad_glProgramUniformMatrix3x2fv;
+#define glProgramUniformMatrix3x2fv glad_glProgramUniformMatrix3x2fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX3X4FVPROC glad_glProgramUniformMatrix3x4fv;
+#define glProgramUniformMatrix3x4fv glad_glProgramUniformMatrix3x4fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4FVPROC glad_glProgramUniformMatrix4fv;
+#define glProgramUniformMatrix4fv glad_glProgramUniformMatrix4fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X2FVPROC glad_glProgramUniformMatrix4x2fv;
+#define glProgramUniformMatrix4x2fv glad_glProgramUniformMatrix4x2fv
+GLAD_API_CALL PFNGLPROGRAMUNIFORMMATRIX4X3FVPROC glad_glProgramUniformMatrix4x3fv;
+#define glProgramUniformMatrix4x3fv glad_glProgramUniformMatrix4x3fv
+GLAD_API_CALL PFNGLPUSHDEBUGGROUPPROC glad_glPushDebugGroup;
+#define glPushDebugGroup glad_glPushDebugGroup
+GLAD_API_CALL PFNGLREADNPIXELSPROC glad_glReadnPixels;
+#define glReadnPixels glad_glReadnPixels
+GLAD_API_CALL PFNGLRELEASESHADERCOMPILERPROC glad_glReleaseShaderCompiler;
+#define glReleaseShaderCompiler glad_glReleaseShaderCompiler
+GLAD_API_CALL PFNGLRESUMETRANSFORMFEEDBACKPROC glad_glResumeTransformFeedback;
+#define glResumeTransformFeedback glad_glResumeTransformFeedback
+GLAD_API_CALL PFNGLSHADERBINARYPROC glad_glShaderBinary;
+#define glShaderBinary glad_glShaderBinary
+GLAD_API_CALL PFNGLTEXBUFFERRANGEPROC glad_glTexBufferRange;
+#define glTexBufferRange glad_glTexBufferRange
+GLAD_API_CALL PFNGLTEXSTORAGE2DPROC glad_glTexStorage2D;
+#define glTexStorage2D glad_glTexStorage2D
+GLAD_API_CALL PFNGLTEXSTORAGE2DMULTISAMPLEPROC glad_glTexStorage2DMultisample;
+#define glTexStorage2DMultisample glad_glTexStorage2DMultisample
+GLAD_API_CALL PFNGLTEXSTORAGE3DPROC glad_glTexStorage3D;
+#define glTexStorage3D glad_glTexStorage3D
+GLAD_API_CALL PFNGLTEXSTORAGE3DMULTISAMPLEPROC glad_glTexStorage3DMultisample;
+#define glTexStorage3DMultisample glad_glTexStorage3DMultisample
+GLAD_API_CALL PFNGLUSEPROGRAMSTAGESPROC glad_glUseProgramStages;
+#define glUseProgramStages glad_glUseProgramStages
+GLAD_API_CALL PFNGLVALIDATEPROGRAMPIPELINEPROC glad_glValidateProgramPipeline;
+#define glValidateProgramPipeline glad_glValidateProgramPipeline
+GLAD_API_CALL PFNGLVERTEXATTRIBBINDINGPROC glad_glVertexAttribBinding;
+#define glVertexAttribBinding glad_glVertexAttribBinding
+GLAD_API_CALL PFNGLVERTEXATTRIBFORMATPROC glad_glVertexAttribFormat;
+#define glVertexAttribFormat glad_glVertexAttribFormat
+GLAD_API_CALL PFNGLVERTEXATTRIBIFORMATPROC glad_glVertexAttribIFormat;
+#define glVertexAttribIFormat glad_glVertexAttribIFormat
+GLAD_API_CALL PFNGLVERTEXBINDINGDIVISORPROC glad_glVertexBindingDivisor;
+#define glVertexBindingDivisor glad_glVertexBindingDivisor
@@ -3885,6 +4568,9 @@ GLAD_API_CALL PFNGLWINDOWPOS3SVPROC glad_glWindowPos3sv;
GLAD_API_CALL int gladLoadGLUserPtr( GLADuserptrloadfunc load, void *userptr);
GLAD_API_CALL int gladLoadGL( GLADloadfunc load);
+GLAD_API_CALL int gladLoadGLES2UserPtr( GLADuserptrloadfunc load, void *userptr);
+GLAD_API_CALL int gladLoadGLES2( GLADloadfunc load);
+
#ifdef GLAD_GL
@@ -3892,6 +4578,13 @@ GLAD_API_CALL int gladLoaderLoadGL(void);
GLAD_API_CALL void gladLoaderUnloadGL(void);
#endif
+#ifdef GLAD_GLES2
+
+GLAD_API_CALL int gladLoaderLoadGLES2(void);
+GLAD_API_CALL void gladLoaderUnloadGLES2(void);
+
+#endif /* GLAD_GLES2 */
+
#ifdef __cplusplus
}
diff --git a/thirdparty/glad/patches/patch_enable_both_gl_and_gles.diff b/thirdparty/glad/patches/patch_enable_both_gl_and_gles.diff
new file mode 100644
index 0000000000..a98efe51d8
--- /dev/null
+++ b/thirdparty/glad/patches/patch_enable_both_gl_and_gles.diff
@@ -0,0 +1,62 @@
+diff --git a/thirdparty/glad/gl.c b/thirdparty/glad/gl.c
+index a0b59dbbfb..9f10f6544a 100644
+--- a/thirdparty/glad/gl.c
++++ b/thirdparty/glad/gl.c
+@@ -2475,7 +2475,7 @@ static GLADapiproc glad_gl_get_proc(void *vuserptr, const char *name) {
+ return result;
+ }
+
+-static void* _glad_GL_loader_handle = NULL;
++static void* _glad_gles_loader_handle = NULL;
+
+ static void* glad_gl_dlopen_handle(void) {
+ #if GLAD_PLATFORM_APPLE
+@@ -2497,11 +2497,11 @@ static void* glad_gl_dlopen_handle(void) {
+ };
+ #endif
+
+- if (_glad_GL_loader_handle == NULL) {
+- _glad_GL_loader_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
++ if (_glad_gles_loader_handle == NULL) {
++ _glad_gles_loader_handle = glad_get_dlopen_handle(NAMES, sizeof(NAMES) / sizeof(NAMES[0]));
+ }
+
+- return _glad_GL_loader_handle;
++ return _glad_gles_loader_handle;
+ }
+
+ static struct _glad_gl_userptr glad_gl_build_userptr(void *handle) {
+@@ -2527,7 +2527,7 @@ int gladLoaderLoadGL(void) {
+ int did_load = 0;
+ struct _glad_gl_userptr userptr;
+
+- did_load = _glad_GL_loader_handle == NULL;
++ did_load = _glad_gles_loader_handle == NULL;
+ handle = glad_gl_dlopen_handle();
+ if (handle) {
+ userptr = glad_gl_build_userptr(handle);
+@@ -2545,9 +2545,9 @@ int gladLoaderLoadGL(void) {
+
+
+ void gladLoaderUnloadGL(void) {
+- if (_glad_GL_loader_handle != NULL) {
+- glad_close_dlopen_handle(_glad_GL_loader_handle);
+- _glad_GL_loader_handle = NULL;
++ if (_glad_gles_loader_handle != NULL) {
++ glad_close_dlopen_handle(_glad_gles_loader_handle);
++ _glad_gles_loader_handle = NULL;
+ }
+ }
+
+diff --git a/thirdparty/glad/glad/gl.h b/thirdparty/glad/glad/gl.h
+index 905c16aeed..f3cb7d8cb5 100644
+--- a/thirdparty/glad/glad/gl.h
++++ b/thirdparty/glad/glad/gl.h
+@@ -67,6 +67,7 @@
+ #endif
+
+ #define GLAD_GL
++#define GLAD_GLES2
+ #define GLAD_OPTION_GL_LOADER
+
+ #ifdef __cplusplus
diff --git a/thirdparty/libwebp/src/dec/vp8i_dec.h b/thirdparty/libwebp/src/dec/vp8i_dec.h
index 1ae4ff62f2..7929fd7506 100644
--- a/thirdparty/libwebp/src/dec/vp8i_dec.h
+++ b/thirdparty/libwebp/src/dec/vp8i_dec.h
@@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define DEC_MAJ_VERSION 1
#define DEC_MIN_VERSION 3
-#define DEC_REV_VERSION 1
+#define DEC_REV_VERSION 2
// YUV-cache parameters. Cache is 32-bytes wide (= one cacheline).
// Constraints are: We need to store one 16x16 block of luma samples (y),
diff --git a/thirdparty/libwebp/src/dec/vp8l_dec.c b/thirdparty/libwebp/src/dec/vp8l_dec.c
index c0ea0181e5..7995313fa1 100644
--- a/thirdparty/libwebp/src/dec/vp8l_dec.c
+++ b/thirdparty/libwebp/src/dec/vp8l_dec.c
@@ -253,11 +253,11 @@ static int ReadHuffmanCodeLengths(
int symbol;
int max_symbol;
int prev_code_len = DEFAULT_CODE_LENGTH;
- HuffmanCode table[1 << LENGTHS_TABLE_BITS];
+ HuffmanTables tables;
- if (!VP8LBuildHuffmanTable(table, LENGTHS_TABLE_BITS,
- code_length_code_lengths,
- NUM_CODE_LENGTH_CODES)) {
+ if (!VP8LHuffmanTablesAllocate(1 << LENGTHS_TABLE_BITS, &tables) ||
+ !VP8LBuildHuffmanTable(&tables, LENGTHS_TABLE_BITS,
+ code_length_code_lengths, NUM_CODE_LENGTH_CODES)) {
goto End;
}
@@ -277,7 +277,7 @@ static int ReadHuffmanCodeLengths(
int code_len;
if (max_symbol-- == 0) break;
VP8LFillBitWindow(br);
- p = &table[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
+ p = &tables.curr_segment->start[VP8LPrefetchBits(br) & LENGTHS_TABLE_MASK];
VP8LSetBitPos(br, br->bit_pos_ + p->bits);
code_len = p->value;
if (code_len < kCodeLengthLiterals) {
@@ -300,6 +300,7 @@ static int ReadHuffmanCodeLengths(
ok = 1;
End:
+ VP8LHuffmanTablesDeallocate(&tables);
if (!ok) dec->status_ = VP8_STATUS_BITSTREAM_ERROR;
return ok;
}
@@ -307,7 +308,8 @@ static int ReadHuffmanCodeLengths(
// 'code_lengths' is pre-allocated temporary buffer, used for creating Huffman
// tree.
static int ReadHuffmanCode(int alphabet_size, VP8LDecoder* const dec,
- int* const code_lengths, HuffmanCode* const table) {
+ int* const code_lengths,
+ HuffmanTables* const table) {
int ok = 0;
int size = 0;
VP8LBitReader* const br = &dec->br_;
@@ -362,8 +364,7 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
VP8LMetadata* const hdr = &dec->hdr_;
uint32_t* huffman_image = NULL;
HTreeGroup* htree_groups = NULL;
- HuffmanCode* huffman_tables = NULL;
- HuffmanCode* huffman_table = NULL;
+ HuffmanTables* huffman_tables = &hdr->huffman_tables_;
int num_htree_groups = 1;
int num_htree_groups_max = 1;
int max_alphabet_size = 0;
@@ -372,6 +373,10 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int* mapping = NULL;
int ok = 0;
+ // Check the table has been 0 initialized (through InitMetadata).
+ assert(huffman_tables->root.start == NULL);
+ assert(huffman_tables->curr_segment == NULL);
+
if (allow_recursion && VP8LReadBits(br, 1)) {
// use meta Huffman codes.
const int huffman_precision = VP8LReadBits(br, 3) + 2;
@@ -434,16 +439,15 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
code_lengths = (int*)WebPSafeCalloc((uint64_t)max_alphabet_size,
sizeof(*code_lengths));
- huffman_tables = (HuffmanCode*)WebPSafeMalloc(num_htree_groups * table_size,
- sizeof(*huffman_tables));
htree_groups = VP8LHtreeGroupsNew(num_htree_groups);
- if (htree_groups == NULL || code_lengths == NULL || huffman_tables == NULL) {
+ if (htree_groups == NULL || code_lengths == NULL ||
+ !VP8LHuffmanTablesAllocate(num_htree_groups * table_size,
+ huffman_tables)) {
dec->status_ = VP8_STATUS_OUT_OF_MEMORY;
goto Error;
}
- huffman_table = huffman_tables;
for (i = 0; i < num_htree_groups_max; ++i) {
// If the index "i" is unused in the Huffman image, just make sure the
// coefficients are valid but do not store them.
@@ -468,19 +472,20 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
int max_bits = 0;
for (j = 0; j < HUFFMAN_CODES_PER_META_CODE; ++j) {
int alphabet_size = kAlphabetSize[j];
- htrees[j] = huffman_table;
if (j == 0 && color_cache_bits > 0) {
alphabet_size += (1 << color_cache_bits);
}
- size = ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_table);
+ size =
+ ReadHuffmanCode(alphabet_size, dec, code_lengths, huffman_tables);
+ htrees[j] = huffman_tables->curr_segment->curr_table;
if (size == 0) {
goto Error;
}
if (is_trivial_literal && kLiteralMap[j] == 1) {
- is_trivial_literal = (huffman_table->bits == 0);
+ is_trivial_literal = (htrees[j]->bits == 0);
}
- total_size += huffman_table->bits;
- huffman_table += size;
+ total_size += htrees[j]->bits;
+ huffman_tables->curr_segment->curr_table += size;
if (j <= ALPHA) {
int local_max_bits = code_lengths[0];
int k;
@@ -515,14 +520,13 @@ static int ReadHuffmanCodes(VP8LDecoder* const dec, int xsize, int ysize,
hdr->huffman_image_ = huffman_image;
hdr->num_htree_groups_ = num_htree_groups;
hdr->htree_groups_ = htree_groups;
- hdr->huffman_tables_ = huffman_tables;
Error:
WebPSafeFree(code_lengths);
WebPSafeFree(mapping);
if (!ok) {
WebPSafeFree(huffman_image);
- WebPSafeFree(huffman_tables);
+ VP8LHuffmanTablesDeallocate(huffman_tables);
VP8LHtreeGroupsFree(htree_groups);
}
return ok;
@@ -1358,7 +1362,7 @@ static void ClearMetadata(VP8LMetadata* const hdr) {
assert(hdr != NULL);
WebPSafeFree(hdr->huffman_image_);
- WebPSafeFree(hdr->huffman_tables_);
+ VP8LHuffmanTablesDeallocate(&hdr->huffman_tables_);
VP8LHtreeGroupsFree(hdr->htree_groups_);
VP8LColorCacheClear(&hdr->color_cache_);
VP8LColorCacheClear(&hdr->saved_color_cache_);
@@ -1673,7 +1677,7 @@ int VP8LDecodeImage(VP8LDecoder* const dec) {
if (dec == NULL) return 0;
- assert(dec->hdr_.huffman_tables_ != NULL);
+ assert(dec->hdr_.huffman_tables_.root.start != NULL);
assert(dec->hdr_.htree_groups_ != NULL);
assert(dec->hdr_.num_htree_groups_ > 0);
diff --git a/thirdparty/libwebp/src/dec/vp8li_dec.h b/thirdparty/libwebp/src/dec/vp8li_dec.h
index 72b2e86120..32540a4b88 100644
--- a/thirdparty/libwebp/src/dec/vp8li_dec.h
+++ b/thirdparty/libwebp/src/dec/vp8li_dec.h
@@ -51,7 +51,7 @@ typedef struct {
uint32_t* huffman_image_;
int num_htree_groups_;
HTreeGroup* htree_groups_;
- HuffmanCode* huffman_tables_;
+ HuffmanTables huffman_tables_;
} VP8LMetadata;
typedef struct VP8LDecoder VP8LDecoder;
diff --git a/thirdparty/libwebp/src/demux/demux.c b/thirdparty/libwebp/src/demux/demux.c
index fd45a2500e..4b0d3f59e9 100644
--- a/thirdparty/libwebp/src/demux/demux.c
+++ b/thirdparty/libwebp/src/demux/demux.c
@@ -25,7 +25,7 @@
#define DMUX_MAJ_VERSION 1
#define DMUX_MIN_VERSION 3
-#define DMUX_REV_VERSION 1
+#define DMUX_REV_VERSION 2
typedef struct {
size_t start_; // start location of the data
diff --git a/thirdparty/libwebp/src/enc/vp8i_enc.h b/thirdparty/libwebp/src/enc/vp8i_enc.h
index 19d9a6edb7..0864fbf1f5 100644
--- a/thirdparty/libwebp/src/enc/vp8i_enc.h
+++ b/thirdparty/libwebp/src/enc/vp8i_enc.h
@@ -32,7 +32,7 @@ extern "C" {
// version numbers
#define ENC_MAJ_VERSION 1
#define ENC_MIN_VERSION 3
-#define ENC_REV_VERSION 1
+#define ENC_REV_VERSION 2
enum { MAX_LF_LEVELS = 64, // Maximum loop filter level
MAX_VARIABLE_LEVEL = 67, // last (inclusive) level with variable cost
diff --git a/thirdparty/libwebp/src/mux/muxi.h b/thirdparty/libwebp/src/mux/muxi.h
index fc44d6f2fe..afc5954353 100644
--- a/thirdparty/libwebp/src/mux/muxi.h
+++ b/thirdparty/libwebp/src/mux/muxi.h
@@ -29,7 +29,7 @@ extern "C" {
#define MUX_MAJ_VERSION 1
#define MUX_MIN_VERSION 3
-#define MUX_REV_VERSION 1
+#define MUX_REV_VERSION 2
// Chunk object.
typedef struct WebPChunk WebPChunk;
diff --git a/thirdparty/libwebp/src/utils/huffman_utils.c b/thirdparty/libwebp/src/utils/huffman_utils.c
index 90c2fbf7c1..cf73abd437 100644
--- a/thirdparty/libwebp/src/utils/huffman_utils.c
+++ b/thirdparty/libwebp/src/utils/huffman_utils.c
@@ -177,21 +177,24 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
if (num_open < 0) {
return 0;
}
- if (root_table == NULL) continue;
for (; count[len] > 0; --count[len]) {
HuffmanCode code;
if ((key & mask) != low) {
- table += table_size;
+ if (root_table != NULL) table += table_size;
table_bits = NextTableBitSize(count, len, root_bits);
table_size = 1 << table_bits;
total_size += table_size;
low = key & mask;
- root_table[low].bits = (uint8_t)(table_bits + root_bits);
- root_table[low].value = (uint16_t)((table - root_table) - low);
+ if (root_table != NULL) {
+ root_table[low].bits = (uint8_t)(table_bits + root_bits);
+ root_table[low].value = (uint16_t)((table - root_table) - low);
+ }
+ }
+ if (root_table != NULL) {
+ code.bits = (uint8_t)(len - root_bits);
+ code.value = (uint16_t)sorted[symbol++];
+ ReplicateValue(&table[key >> root_bits], step, table_size, code);
}
- code.bits = (uint8_t)(len - root_bits);
- code.value = (uint16_t)sorted[symbol++];
- ReplicateValue(&table[key >> root_bits], step, table_size, code);
key = GetNextKey(key, len);
}
}
@@ -211,25 +214,83 @@ static int BuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
((1 << MAX_CACHE_BITS) + NUM_LITERAL_CODES + NUM_LENGTH_CODES)
// Cut-off value for switching between heap and stack allocation.
#define SORTED_SIZE_CUTOFF 512
-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size) {
- int total_size;
+ const int total_size =
+ BuildHuffmanTable(NULL, root_bits, code_lengths, code_lengths_size, NULL);
assert(code_lengths_size <= MAX_CODE_LENGTHS_SIZE);
- if (root_table == NULL) {
- total_size = BuildHuffmanTable(NULL, root_bits,
- code_lengths, code_lengths_size, NULL);
- } else if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
+ if (total_size == 0 || root_table == NULL) return total_size;
+
+ if (root_table->curr_segment->curr_table + total_size >=
+ root_table->curr_segment->start + root_table->curr_segment->size) {
+ // If 'root_table' does not have enough memory, allocate a new segment.
+ // The available part of root_table->curr_segment is left unused because we
+ // need a contiguous buffer.
+ const int segment_size = root_table->curr_segment->size;
+ struct HuffmanTablesSegment* next =
+ (HuffmanTablesSegment*)WebPSafeMalloc(1, sizeof(*next));
+ if (next == NULL) return 0;
+ // Fill the new segment.
+ // We need at least 'total_size' but if that value is small, it is better to
+ // allocate a big chunk to prevent more allocations later. 'segment_size' is
+ // therefore chosen (any other arbitrary value could be chosen).
+ next->size = total_size > segment_size ? total_size : segment_size;
+ next->start =
+ (HuffmanCode*)WebPSafeMalloc(next->size, sizeof(*next->start));
+ if (next->start == NULL) {
+ WebPSafeFree(next);
+ return 0;
+ }
+ next->curr_table = next->start;
+ next->next = NULL;
+ // Point to the new segment.
+ root_table->curr_segment->next = next;
+ root_table->curr_segment = next;
+ }
+ if (code_lengths_size <= SORTED_SIZE_CUTOFF) {
// use local stack-allocated array.
uint16_t sorted[SORTED_SIZE_CUTOFF];
- total_size = BuildHuffmanTable(root_table, root_bits,
- code_lengths, code_lengths_size, sorted);
- } else { // rare case. Use heap allocation.
+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
+ code_lengths, code_lengths_size, sorted);
+ } else { // rare case. Use heap allocation.
uint16_t* const sorted =
(uint16_t*)WebPSafeMalloc(code_lengths_size, sizeof(*sorted));
if (sorted == NULL) return 0;
- total_size = BuildHuffmanTable(root_table, root_bits,
- code_lengths, code_lengths_size, sorted);
+ BuildHuffmanTable(root_table->curr_segment->curr_table, root_bits,
+ code_lengths, code_lengths_size, sorted);
WebPSafeFree(sorted);
}
return total_size;
}
+
+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables) {
+ // Have 'segment' point to the first segment for now, 'root'.
+ HuffmanTablesSegment* const root = &huffman_tables->root;
+ huffman_tables->curr_segment = root;
+ // Allocate root.
+ root->start = (HuffmanCode*)WebPSafeMalloc(size, sizeof(*root->start));
+ if (root->start == NULL) return 0;
+ root->curr_table = root->start;
+ root->next = NULL;
+ root->size = size;
+ return 1;
+}
+
+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables) {
+ HuffmanTablesSegment *current, *next;
+ if (huffman_tables == NULL) return;
+ // Free the root node.
+ current = &huffman_tables->root;
+ next = current->next;
+ WebPSafeFree(current->start);
+ current->start = NULL;
+ current->next = NULL;
+ current = next;
+ // Free the following nodes.
+ while (current != NULL) {
+ next = current->next;
+ WebPSafeFree(current->start);
+ WebPSafeFree(current);
+ current = next;
+ }
+}
diff --git a/thirdparty/libwebp/src/utils/huffman_utils.h b/thirdparty/libwebp/src/utils/huffman_utils.h
index 13b7ad1ac4..98415c5328 100644
--- a/thirdparty/libwebp/src/utils/huffman_utils.h
+++ b/thirdparty/libwebp/src/utils/huffman_utils.h
@@ -43,6 +43,29 @@ typedef struct {
// or non-literal symbol otherwise
} HuffmanCode32;
+// Contiguous memory segment of HuffmanCodes.
+typedef struct HuffmanTablesSegment {
+ HuffmanCode* start;
+ // Pointer to where we are writing into the segment. Starts at 'start' and
+ // cannot go beyond 'start' + 'size'.
+ HuffmanCode* curr_table;
+ // Pointer to the next segment in the chain.
+ struct HuffmanTablesSegment* next;
+ int size;
+} HuffmanTablesSegment;
+
+// Chained memory segments of HuffmanCodes.
+typedef struct HuffmanTables {
+ HuffmanTablesSegment root;
+ // Currently processed segment. At first, this is 'root'.
+ HuffmanTablesSegment* curr_segment;
+} HuffmanTables;
+
+// Allocates a HuffmanTables with 'size' contiguous HuffmanCodes. Returns 0 on
+// memory allocation error, 1 otherwise.
+int VP8LHuffmanTablesAllocate(int size, HuffmanTables* huffman_tables);
+void VP8LHuffmanTablesDeallocate(HuffmanTables* const huffman_tables);
+
#define HUFFMAN_PACKED_BITS 6
#define HUFFMAN_PACKED_TABLE_SIZE (1u << HUFFMAN_PACKED_BITS)
@@ -78,9 +101,7 @@ void VP8LHtreeGroupsFree(HTreeGroup* const htree_groups);
// the huffman table.
// Returns built table size or 0 in case of error (invalid tree or
// memory error).
-// If root_table is NULL, it returns 0 if a lookup cannot be built, something
-// > 0 otherwise (but not the table size).
-int VP8LBuildHuffmanTable(HuffmanCode* const root_table, int root_bits,
+int VP8LBuildHuffmanTable(HuffmanTables* const root_table, int root_bits,
const int code_lengths[], int code_lengths_size);
#ifdef __cplusplus